테스트의 소중함
테스트가 있어야 믿음직합니다.
테스트가 있어야 빨리 버그를 잡을 수 있습니다.
HTTP 요청에 메시지를 실어서 보내고 응답을 받는 간단한 클래스 작성이 목적입니다. 다음과 같은 인터페이스가 필요합니다.
String request(String url, String message);
}
기존 코드(스크롤 주의)
[#M_ more.. | less.. | public static String request(String url, String message) {
Logger.info(HttpClientActor.class, "- url : |" + url + "|");
Logger.info(HttpClientActor.class, "- message : |" + message + "|");
System.out.println("================== request ===================");
Date startDate = null;
Date endDate = null;
HttpClient client = null;
// PostMethod method = null;
GetMethod method = null;
// int readSize = 0;
// Byte[] bytes = null;
String output = null;
String returnValue = null;
// Create an instance of HttpClient.
client = new HttpClient();
// Create a method instance.
// GetMethod method = new GetMethod(url);
try {
// method = new PostMethod(m_url
// + URLEncoder.encode(makeRequestMsg(message).replace('\n', ' '), "UTF-8"));
// method = new PostMethod(m_url + URLEncoder.encode(message.replace('\n', ' '),
// "UTF-8"));
// method = new PostMethod(m_url + URLEncoder.encode(message, "UTF-8"));
// method = new PostMethod(m_url + URLEncoder.encode(message, "KSC5601"));
// method = new PostMethod(m_url);
message = new String(message.getBytes(), 20, message.length() - 20);
method = new GetMethod(url + message);
} catch (Exception e) {
e.printStackTrace();
Logger.error(HttpClientActor.class, "error message : " + e.getMessage());
}
System.out.println("================== the end of PostMethod ===================");
// Provide custom retry handler is necessary
startDate = new Date();
try {
System.out.println("================== the start of executeMethod ===================");
// Execute the method.
// method.setRequestBody(message);
int statusCode = client.executeMethod(method);
System.out.println("================== the end of executeMethod ===================");
if (statusCode != HttpStatus.SC_OK) {
Logger.error(HttpClientActor.class, "Method failed: " + method.getStatusLine());
}
InputStream in = method.getResponseBodyAsStream();
output = convertInputStreamToString(in);
returnValue = output;
System.out.println("================================================");
System.out.println("===== output message =====");
System.out.println("================================================");
System.out.println(returnValue);
Logger.info(HttpClientActor.class, "- recv msg : |" + returnValue + "|");
} catch (HttpException e) {
System.err.println("Fatal protocol violation: " + e.getMessage());
e.printStackTrace();
} catch (IOException e) {
System.err.println("Fatal transport error: " + e.getMessage());
e.printStackTrace();
} finally {
// Release the connection.
method.releaseConnection();
}
endDate = new Date();
System.out
.println("### running time (msec) : " + (endDate.getTime() - startDate.getTime()));
return returnValue;
}
/**
* convert inputStream to string
*/
private static String convertInputStreamToString(InputStream input) {
System.out.println("================== convertInputStreamToString ===================");
int BYTE_SIZE = 256;
StringBuffer output = new StringBuffer();
byte[] buffer = new byte[BYTE_SIZE];
int byteRead;
try {
while ((byteRead = input.read(buffer, 0, BYTE_SIZE)) != -1) {
output.append(new String(buffer));
}
System.out.println("byteRead : " + byteRead);
input.close();
} catch (IOException e) {
System.out.println("convertClobToString : " + e.getMessage());
} finally {
}
return output.toString();
}_M#]인코딩과 로깅까지 고려한 코드입니다. 하지만 위의 코드는 제대로 동작하지 않습니다. 저렇게 긴 코드를 대체 어디서부터 어떻게 손을 댈지 고민하느니 새로 짜는게 좋을 것 같다는 생각이 들어서 새로 짰습니다.
새로 짠 코드
[#M_ more.. | less.. | public static String request(String url, String msg) {
InputStream inputStream = null;
StringBuilder response = new StringBuilder();
URLConnection connection;
try {
URL request = new URL(url + msg);
connection = request.openConnection();
inputStream = connection.getInputStream();
for (int i = 0; i < msg.length(); i++) {
response.append((char) inputStream.read());
}
}
catch (IOException e) {
e.printStackTrace();
}
finally {
try {
if (inputStream != null)
inputStream.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
return response.toString();
}_M#]로깅와 인코딩은 전혀 신경쓰지 않고 짠 코드입니다. 소스 코드의 절반이 try-catch 코드지만 제대로 동작합니다. 물론 저 코드를 짠 순간은 저녀석이 제대로 동작하는지 알 길이 없습니다. 불안하죠. 그래서 테스트 코드를 작성합니다.
String url = "http://localhost:8080/tapsTest/merchantProcess.do?message=";
String msg = "123456789012345678901234567890";
String response = SimpleHttpClient.request(url, msg);
assertEquals("CnbReqQ 1234567890", response);
}
테스트 코드 네 줄까지 합쳐도 기존 코드보다 짧습니다. 그리고 위 테스트 코드를 통해서 요청과 응답을 제대로 받았음을 확인했습니다.(서버에 다녀와야 하기때문에 단위테스트는 아닙니다.)
덤으로 기존의 애플리케이션이 바로 위의 코드때문에 제대로 동작하지 않는다는 것도 확인할 수 있습니다. 위의 테스트케이스에서 클래스만 살짝 바꿔주면 되니까요.