[우아한 테크코스-프리코스 4주차] 단위 테스트 코드 리팩토링 @Parameterized @CsvSource @ValueSource

우아한 테크코스 4주차 미션 크리스마스 GitHub Link

과제 진행 요구 사항 - 단위테스트


과제 진행 요구사항

3 주차 미션에 이어서 4 주차 미션에서 역시도 단위테스트 구현이 포함되어있었다. Java 의 클린코드 컨벤션에 따라 중복 코드, 중복 함수는 지양해야하고 이는 단위 테스트 코드에도 적용되어야한다. 핵심 로직 코드가 중복되지만 몇 가지 인자나, 테스트 제목이 다른 경우에 중복되지 않기 위해 리팩토링 한 과정에서 사용한 기능을 보자.

@ParameterizedTest


이전 포스팅에서 @ParameterizedTest의 기본적인 소개와 사용법은 적었으니 중복되는 내용은 생략했다. 코드가 중복돼서 하나의 함수를 구현하여 인자값을 받는 형태로 수정한다고 했을 때, 문제점이 하나 더 생긴다. 바로 Test 함수의 이름이 같아진다는 것인데, 놀랍게도 @ParameterizedTest 에서도 name 인자를 지정해서 넘겨줄 수 있다는 것을 이번 미션을 진행하며 처음 알게되었다.

@ValueSource

    @DisplayName("날짜가 1 미만이거나 31을 초과하거나 숫자 외의 문자를 포함하면 IllegalArgumentException 발생")
    @ValueSource(strings = {"0", "32", "2a"})
    @ParameterizedTest
    void OverRangeDateNumber(String number) {
        Assertions.assertThatThrownBy(() -> new Date(number))
            .isInstanceOf(IllegalArgumentException.class);
    }

테스트 함수 내에서 인자로 사용할 값들을 어노테이션을 통해 배열로 선언한다. 테스트를 실행하게 되면 배열을 순회하면서, 메소드 인자에 지정된 값들을 주입받고 테스트한다. 이 때, 하나의 테스트에는 하나의 인수(argument)만 전달받을 수 있다.



@CsvSource

    @ParameterizedTest(name = "총혜택 금액이 {0}라면, 배지 {1}를 반환")
    @CsvSource({"5000, 별", "10000, 트리", "20000, 산타"})
    void checkBadgeByTotalPrice(int totalDiscount, Badges badge) {
        Assertions.assertEquals(Event.checkBadge(totalDiscount), badge.name());
    }

@ValueSource 와 유사하게 하나의 테스트에 사용할 값들을 쉼표로 구분하여 배열로 선언한다. 이는 CSV(Comma Sperated Value)라는 이름을 보면 쉽게 알 수 있다. 컴마 뿐만 아니라 커스텀 구분자를 사용할 수도 있다. 이는 @CsvSource({"5000, 별", "10000, 트리", "20000, 산타"}, delimiterString="||") 와 같이 지정하면 된다.

Parameterized 적용 - 리팩토링 전후 비교


    @DisplayName("총혜택 금액이 5000 원이라면, 배지 별을 반환")
    @Test
    void checkBadgeStar(){
        Assertions.assertEquals(Event.checkBadge(5000), Badges.);
    }
    
    @DisplayName("총혜택 금액이 10000 원이라면, 배지 트리를 반환")
    @Test
    void checkBadgeTree(){
        Assertions.assertEquals(Event.checkBadge(10000), Badges.트리);
    }
    
    @DisplayName("총혜택 금액이 20000 원이라면, 배지 산타를 반환")
    @Test
    void checkBadgeSanta(){
        Assertions.assertEquals(Event.checkBadge(20000), Badges.산타);
    }
    @ParameterizedTest(name = "총혜택 금액이 {0}라면, 배지 {1}를 반환")
    @CsvSource({"5000, 별", "10000, 트리", "20000, 산타"})
    void checkBadgeByTotalPrice(int totalDiscount, Badges badge) {
        Assertions.assertEquals(Event.checkBadge(totalDiscount), badge.name());
    }

함수 3 개의 핵심 코드가 중복되었던 기존과 다르게 @Parameterized, @CsvSource를 적용함으로서 함수 하나로 줄였다. 상황에 따라 @NullSource, @EmptySource, @NullAndEmptySource 등도 참고하여 활용해보면 테스트 코드의 전반적인 퀄리티 역시 상승시킬 수 있을 것 같다.


[참고자료]