[JUnit4] JUnitParams를 이용한 테스트 반복(@Parameters)

안녕하세요. 오늘은 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 속성에 명시하지 않으셔도 됩니다.

 

하지만 필자는 개인적으로 유지보수성과 명시성을 중요하게 생각하기 때문에 추후 실무에 응용할 수 있게 된다면 반드시 명시하고자 합니다.

 

 

 

댓글

Designed by JB FACTORY