본문 바로가기
Java

[Java] JUnit 5 사용법 (5) - @RepeatedTest, @ParameterizedTest, @ValueSource, @NullSource, @EmptySource, @NullAndEmptySource

by 노력남자 2022. 9. 6.
반응형

이번 포스팅에선 조건에 따라 반복 테스트를 할 수 있게 해주는 어노테이션에 대해 알아보겠습니다.

 

@RepeatedTest, @ParameterizedTest 처럼 어노테이션명이 Test로 끝나면 별도로 @Test 어노테이션이 없어도 테스트가 가능합니다.

 

@RepeatedTest

 

파라미터명 타입 설명
value int 반복 횟수 (반드시 0보다 커야함) (필수)
name String 반복할 때 나타나는 테스트명

기본값 : "repetition " + 현재 반복 횟수 + " of " + 총 반복 횟수

 

@ReapeatedTest를 사용하면 RepetitionInfo 타입의 인자를 받을 수 있습니다. 앞에서 설명했어야 했는데 추가로 말하자면 JUnit 테스트는 기본적으로 TestInfo 타입의 인자도 받을 수 있습니다.

 

TestInfo

 

메소드명 타입 설명
getDisplayName() String @DisplayName 값이랑 동일
getTags() Set<String> @Tag 배열 값
getTestClass() Optional<Class<?>> 패키지 + 테스트 클래스명
getTestMethod() Optional<Method> 패키지명 + 테스트 클래스명 + 테스트 메소드 

 

RepetitionInfo

 

메소드명 / 변수명 타입 설명
getCurrentRepetition() int 현재 반복 횟수
getTotalRepetitions() int 총 반복 횟수
DISPLAY_NAME_PLACEHOLDER String @DisplayName 값
SHORT_DISPLAY_NAME String 반복할 때 나타나는 테스트명

기본값 : "repetition " + 현재 반복 횟수 + " of " + 총 반복 횟수
LONG_DISPLAY_NAME String DISPLAY_NAME_PLACEHOLDER + " :: " + SHORT_DISPLAY_NAME
TOTAL_REPETITIONS_PLACEHOLDER String 현재 반복 횟수
CURRENT_REPETITION_PLACEHOLDER String 총 반복 횟수

 

RepetitionInfo는 반드시 @RepeatedTest가 있어야합니다. 만약! 없으면 아래와 같은 에러가 납니다.

 

org.junit.jupiter.api.extension.ParameterResolutionException: No ParameterResolver registered for parameter [org.junit.jupiter.api.RepetitionInfo repetitionInfo] in method [void com.effortguy.junit5.RepeatedTestAnnotation.testRepetitionInfo(org.junit.jupiter.api.RepetitionInfo)].

 

예시

 

package com.effortguy.junit5;

import org.junit.jupiter.api.*;

import static org.junit.jupiter.api.Assertions.assertEquals;

class RepeatedTestAnnotation {

    // 5번 반복
    @RepeatedTest(5)
    void repeatedTestWithRepetitionInfo(RepetitionInfo repetitionInfo) {
        assertEquals(5, repetitionInfo.getTotalRepetitions());
    }

    //{displayName} = @DisplayName (없으면 기본값)
    //{currentRepetition} = 현재 반복 횟수
    //{totalRepetitions} = 총 반복 횟수
    @RepeatedTest(value = 1, name = "{displayName} {currentRepetition}/{totalRepetitions}")
    @DisplayName("Repeat!")
    void customDisplayName(TestInfo testInfo) {
        assertEquals("Repeat! 1/1", testInfo.getDisplayName());
    }

    //RepeatedTest.LONG_DISPLAY_NAME = DISPLAY_NAME_PLACEHOLDER + " :: " + SHORT_DISPLAY_NAME
    @RepeatedTest(value = 1, name = RepeatedTest.LONG_DISPLAY_NAME)
    @DisplayName("Details...")
    void customDisplayNameWithLongPattern(TestInfo testInfo) {
        assertEquals("Details... :: repetition 1 of 1", testInfo.getDisplayName());
    }
}

 

결과

 

 

@ParameterizedTest

 

파라미터를 넣어서 테스트를 반복적으로 실행할 수 있게 해주는 어노테이션

 

파라미터명 타입 설명
name String @DisplayName 설정
DISPLAY_NAME_PLACEHOLDER String @DisplayName과 동일
INDEX_PLACEHOLDER String 현재 실행 인덱스
ARGUMENTS_PLACEHOLDER String 현재 실행된 파라미터 값
ARGUMENTS_WITH_NAMES_PLACEHOLDER String 현재 실행된 파라미터명 + "=" + 값
DEFAULT_DISPLAY_NAME String 기본값

"[" + INDEX_PLACEHOLDER + "] " + ARGUMENTS_WITH_NAMES_PLACEHOLDER

 

@ParameterizedTest는 단독으로 사용되진 않고 어떤 파라미터를 사용하는지에 관한 어노테이션을 추가로 선언해줘야합니다.

 

추가로 선언하지 않았을 경우 아래와 같은 에러가 발생합니다.

 

org.junit.platform.commons.PreconditionViolationException: Configuration error: You must configure at least one set of arguments for this @ParameterizedTest

 

파라미터 어노테이션은 총 9개가 있는데 이번 포스팅에선 4개만 정리하고 다음 포스팅에서 나머지를 정리하겠습니다.

 

@ValueSource

 

다양한 타입의 파라미터를 배열로 받아서 사용할 수 있게 해주는 어노테이션

 

지원 타입 : short[], byte[], int[], long[], float[], double[], char[], boolean[], String[], Class<?>[]

 

각 타입명의 소문자에 + "s" 를 붙혀주면 파라미터명입니다. (Strings X, strings O)

 

파라미터 인자는 1개입니다. 2개 이상 넣을 시 에러가 발생합니다.

 

예시

 

package com.effortguy.junit5;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import static org.junit.jupiter.api.Assertions.assertTrue;

public class ParameterizedTestAnnotation {

    @ParameterizedTest
    @ValueSource(ints = { 1, 2, 3 })
    void testWithValueSource(int intArg) {
        assertTrue(intArg > 0 && intArg < 4);
    }
    
    // @ValueSource 파라미터로 여러개 값을 넣을 수 없음
    // @ParameterizedTest
    // @ValueSource(ints = { 1, 2, 3 }, strings = {"a", "b", "c"})
    // void testWithValueSource(int intArg, string stringArg) {
    // }
}

 

결과

 

 

@NullSource

 

메소드 인자에 null 값을 넣어줍니다. 메소드 인자가 1개일 때만 사용할 수 있습니다.

 

primitive type (int, long 등)에는 사용할 수 없습니다. 사용하면 아래와 같은 에러 발생합니다.

 

org.junit.jupiter.api.extension.ParameterResolutionException: Error converting parameter at index 0: Cannot convert null to primitive value of type int

 

package com.effortguy.junit5;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.NullSource;
import org.junit.jupiter.params.provider.ValueSource;

import static org.junit.jupiter.api.Assertions.assertTrue;

public class ParameterizedTestAnnotation {
    
    @ParameterizedTest
    @NullSource
    void testWithNullSource(Integer integerArg) {
        assertTrue(integerArg == null);
    }

    // primitive type에는 @NullSource 사용 불가
    // @ParameterizedTest
    // @NullSource
    // void testWithNullSource(int intArg) {
    // }
}

 

결과

 

 

@EmptySource

 

메소드 인자에 빈 값 객체 값을 넣어줍니다. 메소드 인자가 1개일 때만 사용할 수 있습니다.

 

지원 타입 : java.lang.String, java.util.List, java.util.Set, java.util.Map, primitive arrays (e.g., int[], char[][], etc.), object arrays (e.g.,String[], Integer[][], etc.).

 

package com.effortguy.junit5;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EmptySource;
import org.junit.jupiter.params.provider.NullSource;
import org.junit.jupiter.params.provider.ValueSource;

import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertTrue;

public class ParameterizedTestAnnotation {

    @ParameterizedTest
    void testWithEmptySource(Map map) {
        assertTrue(map.isEmpty());
    }
}

 

결과

 

 

@NullAndEmptySource

 

@NullSource와 @EmptySource를 합쳐놓은 어노테이션

 

package com.effortguy.junit5;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EmptySource;
import org.junit.jupiter.params.provider.NullSource;
import org.junit.jupiter.params.provider.ValueSource;

import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertTrue;

public class ParameterizedTestAnnotation {

    @ParameterizedTest
    @NullSource
    @EmptySource
    @ValueSource(strings = { " ", "   ", "\t", "\n" })
    void nullEmptyAndBlankStrings(String text) {
        assertTrue(text == null || text.trim().isEmpty());
    }
}

 

결과

 

 

 

다음 포스팅에선 @ParameterizedTest 의 나머지 5개 부가적인 어노테이션에 대해 포스팅하겠습니다.

 

읽어주셔서 감사합니다.

 

참고

 

https://junit.org/junit5/docs/current/user-guide/#writing-tests-display-name-generator

반응형

댓글