테스트를 (먼저) 만들면 결과물이 훨씬 간결합니다.

테스트가 있어야 믿음직합니다.

테스트가 있어야 빨리 버그를 잡을 수 있습니다.

HTTP 요청에 메시지를 실어서 보내고 응답을 받는 간단한 클래스 작성이 목적입니다. 다음과 같은 인터페이스가 필요합니다.

public interface HttpClient{
    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 코드지만 제대로 동작합니다. 물론 저 코드를 짠 순간은 저녀석이 제대로 동작하는지 알 길이 없습니다. 불안하죠. 그래서 테스트 코드를 작성합니다.

    public void testRequest() throws Exception {
        String url = “http://localhost:8080/tapsTest/merchantProcess.do?message=&#8221;;
        String msg = “123456789012345678901234567890”;
        String response = SimpleHttpClient.request(url, msg);
        assertEquals(“CnbReqQ             1234567890”, response);
    }

테스트 코드 네 줄까지 합쳐도 기존 코드보다 짧습니다. 그리고 위 테스트 코드를 통해서 요청과 응답을 제대로 받았음을 확인했습니다.(서버에 다녀와야 하기때문에 단위테스트는 아닙니다.)

덤으로 기존의 애플리케이션이 바로 위의 코드때문에 제대로 동작하지 않는다는 것도 확인할 수 있습니다. 위의 테스트케이스에서 클래스만 살짝 바꿔주면 되니까요.