ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Production Code & Test Code & JUnit
    Language/Java 2020. 7. 9. 08:28

    우아한테크코스(이하 우테코) 레벨1 복습을 위한 글입니다.

     

     

    우테코에서는 TDD를 강조합니다.
    첫 주 수업에서 배웠던 내용도 테스트였습니다.
    관련 내용을 간단하게 복습해보겠습니다.

     


     

    Production Code란.

    프로그램 구현을 담당하는 부분으로 사용자가 실제로 사용하는 소스 코드를 의미합니다.

    Test Code란.

    프로덕션 코드가 정상적으로 동작하는지 확인하는 코드를 의미합니다.

     


     

    main method를 이용하면 production code와 test code를 한 클래스에서 처리해 줄 수 있습니다.

    // 더하는 기능을 구현할 클래스 
    public class Adder {
        int add(int i, int j) {
            return i + j;
        }
    
    	// 메서드를 사용하여 Test를 진행
        public static void main(String[] args) {
            Adder adder = new Adder();
            System.out.println(adder.add(1, 3)); // 출력값이 의도한 값인지 확인 가능 
        }
    }

    이런 방식은 실제로 사용하지 않을뿐더러 문제점이 있습니다.

    • Production code와 Test Code가 클래스 하나에 존재합니다. 그러므로 클래스 크기가 커지고 복잡도 또한 증가합니다.
    • Test Code가 실 서비스 시 같이 배포됩니다.
    • main method 하나에서 여러 개의 기능을 테스트합니다. 즉 복잡도가 증가합니다.
    • method명으로 어떤 테스트를 하는지 의도를 드러내기 힘듭니다.
    • 테스트 결과를 사람이 수동으로 확인해야 합니다. (출력문이 의도한 결과와 맞는지 비교해야 합니다.)

     

    하하하, 메인에다가 뭐하는거냐


     

    main method를 활용한 테스트의 문제점은 JUnit으로 해결할 수 있습니다.

    우테코에서는 JUnit 5.x 버전을 주로 사용하여 미션을 진행했습니다.
    그렇지만 현업에서는 JUnit 4.x 버전을 많이 사용한다는 이야기를 들었습니다.

     

    JUnit를 이용하면 Annotation을 활용하여 가독성 좋은 테스트 코드를 구현할 수 있습니다.

    // 자동차 클래스에 대한 테스트 클래스 CarTest
    
    private Car car;
    
    @BeforeEach // (1)
    void setUp() {
        car = new Car("toney");
    }
    
    @DisplayName("3이하일 경우 움직이지 않는다.") // (2)
    @Test // (3)
    void goOrNot_랜덤숫자가_3이하일경우_전진하지_않음() {
        int randomNumber = 3;
        Position expectedPosition = new Position();
        car.goOrNot(randomNumber);
        assertThat(car.getPosition()).isEqualTo(expectedPosition); // (4)
    }
    
    @DisplayName("4이상일 경우 움직인다.")
    @Test
    void goOrNot_랜덤숫자가_4이상일경우_전진() {
        int randomNumber = 4;
        Position expectedPosition = new Position(1);
        car.goOrNot(randomNumber);
        assertThat(car.getPosition()).isEqualTo(expectedPosition);
    }

    위의 예시에서 활용한 Annotation에 대해 설명하겠습니다.

    • (1) @BeforeEach: JUnit4의@Before와 동일한 Annotation으로서 각 테스트 메서드가 실행되기 전에 실행되도록 하는 Annotation입니다.
      예를 들자면setUp()은 "goOrNot_랜덤숫자가_3이하일경우_전진하지_않음()"와"goOrNot_랜덤숫자가_4이상일경우_전진()"이 실행되기 전에 각각 실행되어 car를 초기화해줍니다.
    • (2) @DisplayName: JUnit5에 추가된 Annotation으로서 메서드 가독성을 높일 이름을 추가할 수 있습니다. Junit5에서 추가되었습니다.
    • (3) @Test: 해당 메서드에서 테스트를 진행함을 알려주는 Annotation입니다.
      @ParameterizedTest를 활용하면 메서드의 파라미터로 값을 받아 테스트에 이용할 수 있습니다.

     

    Annotation에 대한 더 많은 정보는 공식문서를 참고하시길 바랍니다.

    JUnit 이외에도 테스트할 때 assertj를 이용하는 경우도 많기에 확인하시면 좋을 듯합니다.

    이번 예시에서는 assertj를 활용했습니다.
    위의 예시에서 활용한 assertThat 메서드에 대해 설명하겠습니다.

    • (4) asserThat: 테스트 메서드가 실행되고 코드가 의도한 대로 작동하는지 확인하는 데 사용하는 메서드입니다.
      "goOrNot_랜덤숫자가_3이하일경우_전진하지_않음()"에서는car가 전진하지 않기 때문에 Position이 초기화된 기본 값인 expectedPosition과 동일한 값이어야 하고, 이를 확인하는 역할을 합니다.
      메서드 체이닝을 통해 여러 가지 기능을 실행할 수 있습니다.

    JUnit에서 제공하는 Assertion에 대한 추가적인 정보는 공식문서를 참고하시길 바랍니다.

    JUnit과 assertj에 대해서는 추후에 따로 포스팅하겠습니다.

     


     

    앞서 main method를 활용한 테스트의 문제점은 production code와 test code를 분리하여 해결할 수 있습니다.
    추가적으로 보다 효과적으로 테스트를 작성하기 위해 JUnit 같은 Test Framework를 사용했습니다. 
    이렇게 구현한 test code는 효율적인 단위 테스트나 TDD를 위한 기반이 됩니다.

    처음 JUnit을 배우고 4달의 시간이 흘렀습니다.
    이제는 처음보다 익숙해져서 원활하게 테스트 메서드를 작성합니다.
    또한 Controller와 Service단의 테스트를 위한 방법도 배웠으며 인수테스트에 대해서도 공부했습니다. 
    하지만 유지보수가 원활한 테스트를 작성하거나 가짜 객체를 사용하여 테스트함에 있어 부족한 부분이 많기에 지속적으로 공부할 예정입니다.

    'Language > Java' 카테고리의 다른 글

    Java의 Error와 Exception 그리고 예외처리 전략  (1) 2020.09.17
    String과 StringBuilder  (0) 2020.08.02
    학습 테스트와 단위 테스트  (0) 2020.07.20

    댓글

Toneyparky Blog