본문 바로가기
교재 실습/자바 웹 프로그래밍 Next Step

2.1 main() 메서드를 활용한 테스트의 문제점

by Jint 2024. 3. 26.

소스코드를 구현한 후 정상적으로 동작하는지 확인하는 일반적인 방법은 main() 메서드를 활용해 의도한 결과 값이 정상적으로 출력되는지 콘솔을 통해 확인하는 것이 일반적이다. 이 과정을 살펴보기 위해 덧셈(add), 뺄셈(subtract), 곱셈(multiply), 나눗셈(divide) 을 구현하는 간단한 사칙연산 계산기 구현 코드를 살펴본다.

 

public class Calculator {

    int add(int i, int j) {
        return i + j;
    }

    int subtract(int i, int j) {
        return i - j;
    }

    int multiply(int i, int j) {
        return i * j;
    }

    int divide(int i, int j) {
        return i / j;
    }
    
    public static void main(String[] args) {
        Calculator cal = new Calculator();
        System.out.println(cal.add(3, 4));
        System.out.println(cal.subtract(5, 4));
        System.out.println(cal.multiply(2, 6));
        System.out.println(cal.divide(8, 4));
    }
    
}


계산기 코드는 실제로 서비스를 담당하는 프로덕션 코드(production code)와 이 프로덕션 코드가 정상적으로 동작하는지 확인하기 위한 main() 메서드로 나뉜다. 일반적으로 main() 은 프로그래밍을 실행하기 위한 목적과 프로덕션 코드가 정상적으로 동작하는지 확인하는 테스트 목적으로 나뉜다. 이 책에서는 main() 의 목적을 테스트로 생각해 테스트 코드로 부르도록 하겠다.
위 계산기 코드의 첫 번째 문제점은 프로덕션 코드와 테스트 코드(main() 메서드)가 같은 클래스에 위치하고 있다는 것이다. 테스트 코드의 경우 테스트 단계에서만 필요하기 때문에 굳이 서비스하는 시점이 같이 배포할 필요가 없다.

이 문제를 해결하기 위한 첫 번째 단계로 프로덕션 코드(Calculator 클래스)와 테스트 코드(CalculatorTest)를 분리할 수 있다.

 

public class Calculator {

    int add(int i, int j) {
        return i + j;
    }

    int subtract(int i, int j) {
        return i - j;
    }

    int multiply(int i, int j) {
        return i * j;
    }

    int divide(int i, int j) {
        return i / j;
    }
    
}

public class CalculatorTest {

    public static void main(String[] args) {
        Calculator cal = new Calculator();
        System.out.println(cal.add(9, 3));
        System.out.println(cal.subtract(9, 3));
        System.out.println(cal.multiply(9, 3));
        System.out.println(cal.divide(9, 3));
    }

}


테스트를 담당하는 별도의 클래스를 추가했지만 main() 메서드 하나에서 프로덕션 코드의 여러 메서드를 동시에 테스트하고 있기 때문에, 프로덕션 코드의 복잡도가 증가할수록 main() 메서드의 복잡도도 증가하고 결과적으로 main() 메서드를 유지하는데 부담된다. 이 같은 문제를 해결하기 위해 다음과 같이 테스트 코드를 각 메서드별로 분리할 수도 있다.

 

public class Calculator {

    int add(int i, int j) {
        return i + j;
    }

    int subtract(int i, int j) {
        return i - j;
    }

    int multiply(int i, int j) {
        return i * j;
    }

    int divide(int i, int j) {
        return i / j;
    }
    
}

public class CalculatorTest {

    public static void main(String[] args) {
        Calculator cal = new Calculator();
        add(cal);
        subtract(cal);
        multiply(cal);
        divide(cal);
    }

    private static void add(Calculator cal) {
        System.out.println(cal.add(9, 3));
    }

    private static void subtract(Calculator cal) {
        System.out.println(cal.subtract(9, 3));
    }

    private static void multiply(Calculator cal) {
        System.out.println(cal.multiply(9, 3));
    }

    private static void divide(Calculator cal) {
        System.out.println(cal.divide(9, 3));
    }

}


하지만 이 또한 최정적인 해결책이 될 수 없다. 그 이유는 개발자가 프로그래밍하는 과정을 살펴보면 된다. 프로그래밍을 할 때 한 번에 메서드 하나의 구현에 집중한다. 클래스가 가진 모든 메서드에 관심이 있는 것이 아닌 현재 구현하고 있는 메서드에만 집중하고 싶다. 하지만 위 테스트 코드는 Calculator 클래스가 가진 모든 메서드를 테스트할 수밖에 없다. 그렇다고 테스트하는 메서드만 남기고 다른 메서드를 주석처리 하는 것 또한 불합리한 작업이다.

main() 메서드를 활용한 위 테스트가 안고 있는 다른 문제점은 테스트 결과를 매번 콘솔에 출력되는 값을 통해 수동으로 확인해야 한다. 위와 같이 로직이 간단한 경우는 결과 값을 쉽게 예측하지만, 로직의 복잡도가 높은 경우, 구현을 완료한 후 한달이 지난 시점이라고 생각할 때, 프로덕션 코드의 복잡한 로직을 머릿속으로 계산해 결과 값이 정상적으로 출력되는지 일일이 확인해야 하는 번거로움이 있다.
main() 메서드를 활용한 테스트의 이 같은 문제점을 핵멸하기 위해 등장한 라이브러리가 JUnit 이다. JUnit 은 관심을 가지는 메서드에 대한 테스트만 가능하다. 또한 로직을 실행한 후 결과값 확인을 프로그래밍을 통해 자동화하는 것이 가능하다. JUnit 을 활용한 문제 해결법을 살펴본다.


참고도서 : https://roadbook.co.kr/169

 

[신간안내] 자바 웹 프로그래밍 Next Step

● 저자: 박재성 ● 페이지: 480 ● 판형: 사륙배변형(172*225) ● 도수: 1도 ● 정가: 30,000원 ● 발행일: 2016년 9월 19일 ● ISBN: 978-89-97924-24-0 93000 [강컴] [교보] [반디] [알라딘] [예스24] [인터파크] [샘

roadbook.co.kr

댓글