JAVA/JAVA | Spring 학습기록

[TDD 리팩토링] @ParameterizedTest을 이용한 테스트 메소드에서의 여러 값 검증

kth990303 2022. 2. 11. 22:38
반응형

아래의 테스트 코드를 한 번 보자.

빈 문자열 또는 null일 경우 0을 반환해주게 하는 테스트 코드이다.

 

또 다른 테스트 코드도 한 번 보자.

계산기 프로그램에서 숫자 이외의 값, 또는 소수나 음수가 입력된 경우 예외를 던져주려 한다.

방금 보여준 두 개의 테스트 코드는 모두 어딘가에 하자(?)가 존재한다.

 

바로바로...

 

하나의 테스트 메소드에 불필요하게 너무 많은 assert문이 존재한다는 것이다!

이러한 경우는 보통, 검증을 제대로 못했거나, 하나의 메소드에 하나의 test라고 생각했지만 여러 개의 test를 묶어놓은 경우이다.

우리는 위 코드들을 알아보기 쉽게 리팩토링해볼 것이다.


1. @ParameterizedTest 이용

먼저 맨 처음 테스트코드 먼저 고쳐보자.

사실 리뷰어(이하 미르)의 피드백을 받기 전까진 @ParameterizedTest가 무엇인지도 몰랐다.

 

@ParameterizedTest은 같은 타입의 여러 value들을 하나의 파라미터에 담아,

하나의 assert문으로 여러 값을 테스트할 수 있는 엄청난 어노테이션이었다.

 

아래와 같이 고쳐주면 된다.

@ParameterizedTest
@NullAndEmptySource
void 빈_문자열_또는_null값_입력(String input) {
    assertThat(StringCalculator.calculate(input)).isEqualTo(0);
}

@Test 대신 @ParameterizedTest를,

그리고 @NullAndEmptySource를 붙이면 null일 때와 빈 문자열일 때를 input에 담아 모든 경우를 테스트해준다.

즉, 위 코드의 input은 ""와 null 두 개의 값을 모두 담고 있는 것이다. 

 

 

아래처럼 이용도 가능하다.

@ParameterizedTest
@ValueSource(strings = {"//;\\n1;2,3", "/;\n1;2;3", "//;1;2;3"})
void 잘못된_딜리미터_입력(String input) {
    assertThatThrownBy(() -> StringCalculator.calculate(input)).isInstanceOf(RuntimeException.class);
}

@ValueSource를 통해 여러 개의 문자열을 한 번에 input으로 담아서 테스트해볼 수도 있다.input에는 strings = {} 안에 담긴 "//;\\n1;2,3", "/;\n1;2;3", "//;1;2;3" 의 값들이 모두 들어있는 것이다.

다만, 이 input에 담긴 경우들의 결과가 모두 동일해야 한다.


2. 테스트 메소드 분리

@ParameterizedTest를 이용하기엔 결과값이 다 다르고,

assert문은 너무 많다면 

하나의 테스트 메소드에 너무 많은 검증을 하고 있는 것이 아닌지 의심을 해보아야 한다.

계산기 프로그램에서 숫자 이외의 값, 또는 소수나 음수가 입력된 경우 예외를 던져주려 한다.

따라서 위 테스트 코드는 아래처럼 바꿔주자.

@Test
void 숫자_이외의_타입_입력() {
    assertThatThrownBy(
            () -> StringCalculator.calculate("//;\n1:a,3"))
            .isInstanceOf(RuntimeException.class
            );
}

@Test
void 음수_입력() {
    assertThatThrownBy(
            () -> StringCalculator.calculate("-3,2:1"))
            .isInstanceOf(RuntimeException.class
            );

}

@Test
void 소수_입력() {
    assertThatThrownBy(
            () -> StringCalculator.calculate("0.5,1.2:2"))
            .isInstanceOf(RuntimeException.class
            );
}

이렇게 하면 특정 테스트가 failed가 됐을 때,

문제를 작은 단위로 바로 파악할 수 있어 더더욱 생산성이 높아지고 삶의 질 또한 달라진다! ㅎㅎ


확실히 피드백이 정말 중요한 것 같다.

피드백을 받으면서 내가 몰랐던 부분, 내가 놓쳤던 부분을 새롭게 알아가면서 성장해나갈 수 있다고 생각한다.

 

이제 테스트 코드를 더 멋지고 간결하게 작성할 수 있겠다~

반응형