티스토리 뷰

예림언니와 페어 프로그래밍으로 테스트 코드를 작성하던 중 멘토님께서 알려주신 Prameterized Test를 적용해 보기로 했다.

사용자 이름에 1자 ~ 30자 제한이 있는 상황에서, 사용자 이름이 범위를 초과해 실패하는 테스트를 짜려고 @ValueSource(strings = {"", "a".repeat(31)})를 썼는데, @ValueSource에는 "a".repeat(31)와 같은 메서드는 사용할 수 없었다. 일단은 @ValueSource(strings = {"a", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"})로 사용을 했는데, 아무리 생각해도 이 문제를 해결할 수 있는 기능이 있을 것 같다는 강한 직감이 왔다..😂😂

그리고 

├─ 이름을 2 ~ 30자 범위를 초과 입력해 유저 생성에 실패한다.
│     │  ├─ [1] a
│     │  └─ [2] aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

 

이렇게 불친절한 Display Name도 좀 수정을 하고 싶어졌다..

 

그래서 이왕 찾아보는 김에 parameterized test에 대해 정리를 해보려 한다!

 

❓ parameterized test?

 : JUnit 5에 새로 추가된 기능으로, 다양한 매개변수로 단일 테스트 메서드를 여러 번 실행할 수 있는 기능이다.

 

간단한 예시를 살펴보자

public class Numbers {
    public static boolean isOdd(int number) {
        return number % 2 != 0;
    }
}

 

위와 같은 메서드가 있을 때, 아래와 같이 Parameterized 테스트 코드를 작성할 수 있다.

 

@ParameterizedTest
@ValueSource(ints = {1, 3, 5, -3, 15, Integer.MAX_VALUE})
void isOdd_ShouldReturnTrueForOddNumbers(int number) {
    assertTrue(Numbers.isOdd(number));
}

 

이런식으로 @ParameterizedTest 애너테이션을 붙인 뒤, @ValueSource 애너테이션으로 매개변수 값을 지정해주면

테스트 메서드의 매개변수에 설정해 준 값이 차례대로 들어간다! 그리고 해당 테스트 메서드는 총 6번 호출된다.

 

 

간단한 예시들과 함께 사용 방법을 익혀보자!

 

 

의존성 추가

1. Maven 사용 시 pom.xml에 다음을 추가

 

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-params</artifactId>
    <version>5.10.0</version>
    <scope>test</scope>
</dependency>

 

2. Gradle 사용 시 build.gradle에 다음을 추가

 

testCompile("org.junit.jupiter:junit-jupiter-params:5.10.0")

 

SpringBoot 2.2.0 이상을 사용하고 Spring-Web 의존성을 추가했다면, JUnit 5가 기본적으로 적용되어 있어 의존성 추가 과정을 생략 해도 된다.

 

 

파라미터 정보를 지정해주자 - Argument Sources

1️⃣ 기본형과 String, Class

 

@ValueSource(strings = {"", "  "})
@ValueSource(ints = {1, 3, 5, -3, 15, Integer.MAX_VALUE})

 

위와 같이 @ValueSource 애너테이션과 함께 문자열 값을 파라미터로 넘길 수 있다.

String을 넘기는 strings 외에도 

  • shorts, bytes, ints, longs, floats, doubles, chars, strings, classes를 사용할 수 있다!

❗@ValueSource 애너테이션으로는 null을 지정할 수 없다.

 

2️⃣ Null과 빈 값

 

@NullSource
@EmptySource
@NullAndEmptySource

 

@EmptySource를 사용하면 String 타입의 매개변수에 빈 문자열을 제공하거나 컬렉션 및 배열에 빈 값을 제공할 수 있다.

 

❗기본형 파라미터를 가진 테스트 메서드에는 @NullSource를 사용할 수 없다.

 

3️⃣ 열거형(Enum)

 

@EnumSource(Month.class)
@EnumSource(
  value = Month.class, 
  names = {"APRIL", "JUNE", "SEPTEMBER", "NOVEMBER"})
@EnumSource(
  value = Month.class,
  names = {"APRIL", "JUNE", "SEPTEMBER", "NOVEMBER", "FEBRUARY"},
  mode = EnumSource.Mode.EXCLUDE)
@EnumSource(value = Month.class, names = ".+BER", mode = EnumSource.Mode.MATCH_ANY)

 

▪️ mode 속성을 EnumSource.Mode.EXCLUDE로 두어서 names에 적힌 값을 제외한 나머지를 파라미터로 넘길 수 있다.

▪️ mede 속성을 EnumSource.Mode.MATCH_ANY로 두어서 names에 정규식을 작성할 수 있다.

 

파라미터를 여러개 전달 해보자

4️⃣ CSV 리터럴

 

@CsvSource({"test,TEST", "tEst,TEST", "Java,JAVA"})
@CsvSource(value = {"test:test", "tEst:test", "Java:java"}, delimiter = ':')

 

@CsvSource에는 쉼표로 구분된 값의 배열을 적을 수 있다. 각 배열의 항목이 CSV 파일의 한 줄에 해당한다.

@CsvSource를 사용하면 매번 하나의 배열 항목을 가져와 쉼표로 나누고 별도의 매개변수로 전달한다.

▪️ delimiter 속성을 사용하여 구분자를 지정할 수 있다.

 

예시로 살펴보자.

 

String의 toUpperCase() 메서드를 테스트 하기 위해서는 단순히 @ValueSource(strings = {"test", "tEst", "Java"})를 사용해서는 안된다. 예상되는 결과 값("TEST", "TEST", "JAVA")도 함께 필요하기 때문! 두개의 파라미터를 제공하기 위해서 @CsvSource를 사용할 수 있다.

 

@ParameterizedTest
@CsvSource({"test,TEST", "tEst,TEST", "Java,JAVA"})
void toUpperCase_ShouldGenerateTheExpectedUppercaseValue(String input, String expected) {
    String actualValue = input.toUpperCase();
    assertEquals(expected, actualValue);
}

 

 

5️⃣ CSV 파일

 

@CsvFileSource(resources = "/data.csv", numLinesToSkip = 1)

 

▪️ resources 속성에 CSV 파일의 경로를 지정해 줄 수 있다.

▪️ numLinesToSkip 속성을 통해 CSV 파일을 읽을 때 건너뛸 줄 수를 나타낼 수 있다. (헤더를 건너뛰는 데 유용)

▪️ lineSeparator 속성을 통해 줄 구분자를 지정할 수 있다. (기본값이 개행)

▪️ encoding 속성을 통해 인코딩 형식을 지정할 수 있다. (기본이 UTF-8)

 

6️⃣ 메서드

 

@ParameterizedTest
@MethodSource("provideStringsForIsBlank")
void isBlank_ShouldReturnTrueForNullOrBlankStrings(String input, boolean expected) {
    assertEquals(expected, Strings.isBlank(input));
}

 

@MethodSource에 제공하는 name은 사용하려는 메서드명과 일치해야 한다.

즉, 아래와 같은 메서드가 존재해야 한다.

 

private static Stream<Arguments> provideStringsForIsBlank() {
    return Stream.of(
      Arguments.of(null, true),
      Arguments.of("", true),
      Arguments.of("  ", true),
      Arguments.of("not blank", false)
    );
}

 

매개변수를 하나만 전달하고 싶다면 Arguments를 사용할 필요없이 다음과 같이 사용할 수 있다.

 

@ParameterizedTest
@MethodSource("provideLongString")
void isLoggerThan30(String input) {
    assertTrue(input.length() > 30);
}

private static List<String> provideLongString() {
    String string = "long name ";
    return List.of(string.repeat(4));
}

 

그 외에도 ArgumentsProvider를 구현해 @ArgumentsSource() 을 사용하거나, 커스텀 애너테이션을 만들수도 있다. 하지만 이런 기능은 있다는 것만 알아두고 나중에 필요할 때 더 공부해보자!

 

 

마지막으로..

 

 

Display Name을 바꿔보자

만약 아래와 같이 Parameterized Test에 @DisplayName를 설정 했다면,

 

@DisplayName("홀수를 입력하면 true를 리턴한다.")
@ParameterizedTest
@ValueSource(ints = {1, 3, 5, -3, 15, Integer.MAX_VALUE})
void isOdd_ShouldReturnTrueForOddNumbers(int number) {
    assertTrue(Numbers.isOdd(number));
}

 

기본적으로 아래와 같은 Display Name이 표시된다.

 

├─ 홀수를 입력하면 true를 리턴한다.
│     │  ├─ [1] 1
│     │  ├─ [2] 3
│     │  ├─ [3] 5
│     │  ├─ [4] -3
│     │  ├─ [5] 15
│     │  └─ [6] 2147483647

 

Display Name이 너무 불친절하다. 더 자세한 내용을 표시하도록 변경해보자!

 

@DisplayName("홀수를 입력하면 true를 리턴한다.")
@ParameterizedTest(name = "{index}. {0}은 홀수이다.")
@ValueSource(ints = {1, 3, 5, -3, 15, Integer.MAX_VALUE})
void isOdd_ShouldReturnTrueForOddNumbers(int number) {
    assertTrue(Numbers.isOdd(number));
}

 

위와 같이 @ParameterizedTest의 name 속성을 통해 사용자 정의 Display Name을 설정 할 수 있다.

그리고 {index}와 같이 name에서 사용할 수 있는 placeholder가 몇가지 있다.

  • {index} : 파라미터의 호출 순서
  • {arguments} : 모든 파라미터(인자) 리스트
  • {0}, {1}, ... : 개별 파라미터(인자)
├─ 홀수를 입력하면 true를 리턴한다.
│     │  ├─ 1. 1은 홀수이다.
│     │  ├─ 2. 3은 홀수이다.
│     │  ├─ 3. 5는 홀수이다.
│     │  ├─ 4. -3은 홀수이다.
│     │  ├─ 5. 15는 홀수이다.
│     │  └─ 6. 2147483647은 홀수이다.

 

이렇게 Display Name이 잘 변경된 것을 볼 수 있다!

 

참고링크

📎 Junit 5 공식문서 - parameterized tests

 

JUnit 5 User Guide

Although the JUnit Jupiter programming model and extension model do not support JUnit 4 features such as Rules and Runners natively, it is not expected that source code maintainers will need to update all of their existing tests, test extensions, and custo

junit.org

 

📎 벨덩(Baeldung) - Guide to JUnit 5 Parameterized Tests

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함