다수의 테스트가 몇가지 하드코딩된 값만 다를 경우, 한 개의 “parameterized” 테스트로 리팩토링되어야 합니다. 이러한 방법은 버그를 추가할 가능성을 줄어들게 하고 더 쉽게 읽혀지게 합니다. Parameterized 테스트는 다양한 테스트 프레임워크에 존재합니다.(JUnit, TestNG, 등등…)
물론 적당한 균형은 찾아야됩니다. Parameterized 테스트가 기존 버전보다 더 복잡성을 가지게 된다면 분해하는 의미가 없습니다.
해당 규칙은 최소 3개의 테스트가 4개의 파라미터를 가지는 parameterized 테스트로 리팩토링이 가능할 때 문제를 제기합니다. 적어도 한개의 중복된 상태를 가지는 테스트 메소드만이 고려대상입니다.
규칙을 어긴 코드 예제
with JUnit5
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
public class AppTest
{
@Test
void test_not_null1() { // 규칙을 어긴 코드. 아래 3개의 테스트는 하드 코딩된 몇개의 숫자만 다름.
setupTax();
assertNotNull(getTax(1));
}
@Test
void test_not_null2() {
setupTax();
assertNotNull(getTax(2));
}
@Test
void test_not_nul3l() {
setupTax();
assertNotNull(getTax(3));
}
@Test
void testLevel1() { // 규칙을 어긴 코드. 규칙을 어긴 코드. 아래 3개의 테스트는 하드 코딩된 몇개의 숫자만 다름.
setLevel(1);
runGame();
assertEquals(playerHealth(), 100);
}
@Test
void testLevel2() { // Similar test
setLevel(2);
runGame();
assertEquals(playerHealth(), 200);
}
@Test
void testLevel3() { // Similar test
setLevel(3);
runGame();
assertEquals(playerHealth(), 300);
}
}
규칙을 준수한 해결책
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
public class AppTest
{
@ParameterizedTest
@ValueSource(ints = {1, 2, 3})
void test_not_null(int arg) {
setupTax();
assertNotNull(getTax(arg));
}
@ParameterizedTest
@CsvSource({
"1, 100",
"2, 200",
"3, 300",
})
void testLevels(int level, int health) {
setLevel(level);
runGame();
assertEquals(playerHealth(), health);
}
}
참고
- Modern Best Practices for Testing in Java - Philipp Hauer
- JUnit 5 documentation - Parameterized tests
- Writing Parameterized Tests With JUnit 4
- TestNG documentation - Parameters
If you like SONARKUBE, don’t forget to give me a star.