Study

ParameterizedTest 를 잘해보자

Hyunec 2020. 8. 21. 01:15
처음 ParameterizedTest를 본건 코드스쿼드 멤버의 코드를 리뷰하면서 였습니다. @CsvSource의 단순한 형태였던 것으로 기억하는데, 당시에는 러닝 커브의 이유로 공부하지 않았었습니다. 하지만 이제는 회사에서의 개발을 시작하면서, 몇 가지 시도를 해봤고 조금은 마음에 드는 코드가 나와 글을 써 봅니다.라고 하지만 이 글을 쓰는 순간에도 설정 에러가 나고 있습니다 🤣

영감을 준 Sunny에게 감사를.

ParameterizedTest에 대한 설명은 더 좋은 자료들이 많으니 Annotaion 만 정리하고 넘어가겠습니다.

Annotation
Description
@ValueSource
literal 배열 값으로 테스트
@EnumSource
Enum 값으로 테스트
@MethodSource
가공이 필요한 복잡한 형태의 값으로 테스트
@CsvSource
쉼표로 구분 된 값으로 테스트
@CsvFileSource
@CsvSource 형태의 파일로 값을 받아 테스트
@ArgumentSource ArgumentProvider 를 받아서 테스트

Code

ParameterizedTest을 선택한 이유는 가독성과 재사용성입니다. 그중에서도 제가 의도한 방식인 @ArgumentSource을 핵심 부분만 축약한 코드를 첨부합니다.

# FindUsersRequest

Client로부터 전달받는 User 정보 객체

public class FindUsersRequest {

  ...

  @Pattern(regexp = ValidateUtil.EmailRegExp)
  @Schema(description = "이메일")
  private String email;

  @Pattern(regexp = ValidateUtil.PhoneRegExpOnlyNumber)
  @Schema(description = "전화번호")
  private String phoneNumber;
}

# NormalFindUsersRequestProvider

정상 User 정보를 가진 FindUsersRequest 테스트 데이터 Provider

public class NormalFindUsersRequestProvider implements ArgumentsProvider {

  private final List<FindUsersRequest> normalFindUsersRequests = Arrays.asList(
      FindUsersRequest.builder()
          .email("choi@gmail.com").build()
      , FindUsersRequest.builder()
          .phoneNumber("01044445555").build()
  );

  @Override
  public Stream<Arguments> provideArguments(ExtensionContext context) {
    return normalFindUsersRequests.stream().map(Arguments::of);
  }
}

# WrongFindUsersRequestProvider

비정상 User 정보를 가진 FindUsersRequest 테스트 데이터 Provider

public class WrongFindUsersRequestProvider implements ArgumentsProvider {

  private final List<FindUsersRequest> wrongEmailFindUsersRequests = Arrays.asList(
      FindUsersRequest.builder()
          .email("choigmail.com").build()
      , FindUsersRequest.builder()
          .phoneNumber("010#24592711").build()
  );

  @Override
  public Stream<Arguments> provideArguments(ExtensionContext context) {
    return wrongEmailFindUsersRequests.stream().map(Arguments::of);
  }
}

# FindUsersRequestTest

FindUsersRequest를 검증

public class FindUsersRequestTest {

  private static Validator validator;
  ...

  @DisplayName("정상")
// 테스트 케이스마다 반복적으로 주석을 달아줍니다.
  @ParameterizedTest(name = "#")
  @ArgumentsSource(NormalFindUsersRequestProvider.class)
// NormalFindUsersRequestProvider 에 정의된 FindUsersRequest 테스트 값을 가져옵니다.
  public void normalFindUsersRequest(FindUsersRequest findUsersRequest) {
// FindUsersRequest 을 검증합니다.
    Set<ConstraintViolation<FindUsersRequest>> constraintViolations
        = validator.validate(findUsersRequest);
    assertEquals(0, constraintViolations.size());
  }

  @DisplayName("비정상 패턴의 입력 값")
  @ParameterizedTest(name = "#")
  @ArgumentsSource(WrongFindUsersRequestProvider.class)
  public void wrongFindUsersRequest(FindUsersRequest findUsersRequest) {
    ...
  }
}

좋은 점

  • Provider를 사용하여 테스트 케이스와 테스트 코드를 분리할 수 있습니다.
    • 나아가 Json 형태로 Import, Export 가 가능해 관리가 편해집니다.
  • ParameterizedTest의 주석 기능으로 테스트 결과 해석이 더 쉬워집니다.
 

Junit 5 - Parameterized Test

In this article we will see what are the Junit 5 Parameterized tests, how to create parameterized test cases, several kind of argument sources ...

javabydeveloper.com