[JUnit4] JUnitParams를 이용한 테스트 반복(@Parameters)
- Testing/JUnit
- 2020. 6. 14. 20:56
안녕하세요. 오늘은 JUnit4 버전을 사용해서 파라미터를 반복해서 테스트할 수 있는 방법에 대해서 포스팅해보고자 합니다.
이전 포스팅에서는 JUnit5의 테스트 반복에 대해서 다뤄봤는데요. JUnit5에서는 기본적으로 @ParameterizedTest 라는 어노테이션을 사용해서 @CsvSource, @ValueSource라는 어노테이션을 이용하여 파라미터를 전달하였습니다.
하지만 JUnit4버전에서는 별도의 의존성을 추가해주셔야 하는데요.
바로 JUnitParams라는 의존성입니다.
pom.xml에 JUnitParams의 의존성을 추가해줍니다.
<dependency>
<groupId>pl.pragmatists</groupId>
<artifactId>JUnitParams</artifactId>
<version>1.1.1</version>
<scope>test</scope>
</dependency>
해당 의존성을 추가하면 테스트 클래스를 생성할 때, @RunWith() 어노테이션의 argument로 JUnitParamsRunner.class 타입을 넣어줄 수 있습니다.
@RunWith(JUnitParamsRunner.class)
public class MyClassTest {
}
현재 테스트는 VO에 대한 테스트로 @SpringBootTest나 @WebMvcTest의 어노테이션이 필요가 없는 테스트로 진행하였습니다.
테스트 클래스의 내부를 작성하기 전에 MyClass 클래스를 작성해보겠습니다.
MyClass.java
@Getter
@Setter
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(of = "id")
public class MyClass {
private int startPrice;
private int endPrice;
private boolean free;
public void update() {
if (startPrice == 0 && endPrice == 0) {
this.free = true;
} else {
this.free = false;
}
}
}
기본적인 비즈니스는 일단 경매정도로 생각해보시면 좋을 것 같습니다. startPrice가 경매시작가이고, endPrice가 최대경매액 즉, 낙찰가가 됩니다. 그런데 startPrice가 0원이고 endPrice가 0원이면 원래는 유찰일텐데요. 그렇지 않고 무료로 나눔된다는 컨셉으로 가보겠습니다.
테스트 메소드를 작성해보겠습니다. 이미 눈치채셨겠지만 각 price들은 parameter들로써 넘어오고 제가 정의한 기준에 부합하는지 확인하는 테스트 케이스입니다. 테스트를 할 필드는 free이므로 myClassTestFree라는 이름을 가지는 테스트를 작성합니다.
@Test
@Parameters({
"0, 0, true",
"0, 100, false",
"10, 200, false"
})
public void myClassTestFree(int startPrice, int endPrice, boolean free) {
//Given
MyClass myClass = MyClass.builder()
.startPrice(startPrice)
.endPrice(endPrice)
.build();
//When
myClass.update();
//Then
assertThat(myClass.isFree()).isEqualTo(free);
}
@Parameters라는 어노테이션을 통해 String 타입의 문자열을 구분자 콤마(,)로 구분지어 넘깁니다. 그러면 JUnitParams 내부 로직을 거쳐 JUnit에서 파라미터로 각 price들과 free 값을 매핑시켜줍니다.
이렇게하면 테스트를 통과할테지만 String 타입으로 넘긴다는 점이 Type Safety가 확보가 된 상황이 아닌것 같습니다. 직접 문자열을 int와 boolean 타입으로 내부적으로 String -> int/boolean 파싱작업이 이루어질텐데요. true -> ture로 오타를 많이 내는 저로써는 오류가 나면 좀처럼 찾기가 힘들것입니다. 좀더 Type Safe한 방법을 소개해보고자 합니다.
메소드를 통한 파라미터 전달
@Parameters 어노테이션을 뜯어보면 다음과 같은 속성이 존재합니다.
method라는 속성이 존재하게 되는데 이는 특정 메소드를 호출하여 return 하는 Object 타입을 통해 파라미터를 전달할 수 있습니다.
parametersForMyClassTestFree 메소드 (파라미터 전달자)
public Object[][] parametersForMyClassTestFree() {
return new Object[][] {
new Object[] {0, 0, true},
new Object[] {0, 100, false},
new Object[] {10, 200, false}
};
}
이렇게 작성한 메소드를 사용해야합니다.
예상하신대로 @Parameters(method = "parametersForMyClassTestFree") 으로 어노테이션을 변경해줍니다.
@Test
/*@Parameters({
"0, 0, true",
"0, 100, false",
"10, 200, false"
})*/
@Parameters(method = "parametersForMyClassTestFree")
public void myClassTestFree(int startPrice, int endPrice, boolean free){
//Given
MyClass myClass = MyClass.builder()
.startPrice(startPrice)
.endPrice(endPrice)
.build();
//When
myClass.update();
//Then
assertThat(myClass.isFree()).isEqualTo(free);
}
이제 타입도 직접적으로 확인할 수 있을 뿐더러 좀더 명시적인 테스트 코드가 완성되었습니다.
* 참고로 method를 떼고도 Test 케이스의 파라미터를 가져올 수 있는데요. 이는 JUnitParams의 prefix 문자열이 parametersFor[테스트메소드이름] 으로 정해져있기 때문에 명시적으로 method에 적어놓지 않으시더라고 파라미터 메소드명 컨벤션을 굵은 글씨처럼 짓는다면 따로 method 속성에 명시하지 않으셔도 됩니다.
하지만 필자는 개인적으로 유지보수성과 명시성을 중요하게 생각하기 때문에 추후 실무에 응용할 수 있게 된다면 반드시 명시하고자 합니다.