12월 26, 2023

JUnit @ParameterizedTest를 활용하여 Test code 간략하게 작성하기

 JUnit의 @ParameterizedTest를 사용하여 TestCode를 간략하게 작성할 수 있는 방법에 대해 알아보겠다. 

1. Dependency 추가


먼저 Gradle에 다음과 같은 Dependency를 추가해준다. 

testImplementation 'org.junit.jupiter:junit-jupiter-params:5.4.2'


2. @ParameterizedTest 사용법


2.1 @ParameterizedTest 사용이유

Test 코드를 사용하다 보면 test 인자로 들어오는 값이 무엇이냐에 따라 Test 결과값이 바뀐다. 특히 예를 들어 몇 자리에서 몇자리까지 validation으로 들어오는 경우에는 그 경계값에 해당되는 숫자를 test 코드에 넣고 일일히 테스트해야 하기 때문에 소스의 중복이 많아진다. 


테스트 코드의 중복을 줄이고 모든 경계값에 대한 테스트를 진행할 때 @ParameterizedTest를 사용하면 아주 유용하다. 


@ParameterizedTest는 다양한 annotation과 함께 사용할 수 있다. 


2.2 @ValueSource annotation 사용

@ValueSource는 literal 값의 단일 배열을 지정할 수 있고, 테스트 시마다 단일 인자를 제공할 경우 사용할 수 있다. 


short, byte, int, long, float, double, char, boolean 뿐 아니라 java.lang.String, java.lang.Class에 대해서도 지원이 가능하다. 


@ValueSource 뒤에 (strings = { } ) 이런 식으로 원하는 타입을 적은 뒤 그 뒤에 literal을 넣어주면 된다. string 인자일 경우 strings = { } , int 인자일 경우 ints = {} 이런식으로 적을 수 있다.  

@DisplayName("비밀번호가 7자 미만 또는 13자 초과하는 경우 IllegalArgumentException 예외를 발생시킨다.")
@ParameterizedTest
@ValueSource(strings = {"aabbcc", "abcdefdeeffeeg"})
void validatePasswordTest(String password) {
assertThatCode(()->PasswordValidator.validate(password))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("비밀번호는 최소 7자 이상 13자 이하로 설정되어야 한다.");
}


여기서는 password가 단일인자 string의 형태로 들어왔으므로 strings = { } 의 형태로 @ValueSource를 설정해줄 수 있는 것이다. 


만약 @ParameterizedTest를 하지 않았다면 6글자의 password, 14자리의 password를 가지는 Test method를 각각 하나씩 적었어야 할 것이다. 


동일 기능을 수행하고 있는 Test Code의 여러 test case를 @ParameterizedTest와 @ValueSource를 사용하여 간략하게 작성할 수 있다. 


2.3 @MethodSource

위의 @ValueSource의 경우 parameter를 하나만 넘겨주기 때문에 인자가 여러 개인 경우는 테스트가 어렵다. 


@MethodSource annotation을 사용하면 우리가 사용하고자 하는 method를 새롭게 만들고 그 메서드의 복합인자를 가져와 test에 사용할 수 있어서 다각도로 테스트가 가능하다. 

import java.util.stream.Stream;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
@DisplayName("사칙 연산 (+, -, *, /) 을 수행한다.")
@ParameterizedTest
@MethodSource("formulaCalculation")
void calculateTest(int operand1, String operator, int operand2, int result) {
int formulaResult = Calculator.calculate(operand1, operator, operand2);
assertThat(formulaResult).isEqualTo(result);
}

private static Stream<Arguments> formulaCalculation(){
return Stream.of(
arguments(3, "+", 4, 7),
arguments(5, "-", 2, 3),
arguments(2, "*", 2, 4),
arguments(8, "/", 2, 4)
);
}


이런 식으로 적어주면 formulaCalulation() 이라고 우리가 따로 정의한 static method의 인자를 넣어줄 수 있다. 


이런 식으로 사용하면 인자가 여러개 일 때도 손쉽게 테스트 할 수 있다.