들어가기 전에
- < 이전 포스트 : JUnit 5 (3)
- 모든 소스코드는 JUnit 5 공식 유저 가이드의 것을 사용하였다.
- 3장은 내용이 길어서, 몇 개의 포스트로 나눌 예정이고, 작성 과정에서 내용의 순서가 변경되거나 빠질 수 있다.
- 번역이라기 보다는 요약정리
공식 유저 가이드 의 3장, 테스트 작성법 일부 를 정리하였다.
@Test 와 기본적인 테스트
@Test
는 가장 기본적인 어노테이션으로서, 테스트 메서드를 지정할 수 있다. JUnit 4 시절과 달리, 사용 가능한 옵션도, 추가적인 인자도 정의되어 있지 않다.
import static org.junit.jupiter.api.Assertions.fail;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
class StandardTests {
@BeforeAll
static void initAll() {
}
@BeforeEach
void init() {
}
@Test
void succeedingTest() {
}
@Test
void failingTest() {
fail("a failing test");
}
@Test
@Disabled("for demonstration purposes")
void skippedTest() {
// not executed
}
@AfterEach
void tearDown() {
}
@AfterAll
static void tearDownAll() {
}
}
- 참고 : 테스트 클래스와 메서드는 반드시 퍼블릭일 필요는 없다.
테스트 이름
@DisplayName
어노테이션을 사용하여 테스트 클래스와 메서드에 이름을 붙여줄 수 있다.
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
@DisplayName("A special test case")
class DisplayNameDemo {
@Test
@DisplayName("Custom test name containing spaces")
void testWithDisplayNameContainingSpaces() {
}
@Test
@DisplayName("╯°□°)╯")
void testWithDisplayNameContainingSpecialCharacters() {
}
@Test
@DisplayName("😱")
void testWithDisplayNameContainingEmoji() {
}
}
- 그런데 왜 밥상을 엎는 것일까?
검증
검증Assertion
메서드는 JUnit 4 에서 친숙하게 보아왔던 것들이 거의 그대로 넘어왔고, 람다 지원을 위한 몇 가지 메서드들이 추가되었다. 자세한 내용은 여기 에서 확인 가능하다.
JUnit 5는 Java 8의 추가 기능을 받아들이며, 사용자가 테스트를 작성할 때 람다 를 적극적으로 사용하도록 유도하였다. 기존에는 테스트 메서드를 생성해야 할 수 있던 일을, JUnit 5에서는 람다가(그리고 우리는, 람다를 익명 함수 라고 읽을 수도 있다.) 할 수도 있다. 아래 코드는 예제 코드에서 그러한 부분만 추출한 것이다.
import static java.time.Duration.ofMillis;
import static java.time.Duration.ofMinutes;
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTimeout;
import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
class AssertionsDemo {
// 기본적으로는 람다를 활용하여 여러 개의 테스트 케이스를 검증할 수 있다.
@Test
void groupedAssertions() {
// In a grouped assertion all assertions are executed, and any
// failures will be reported together.
assertAll("person",
() -> assertEquals("John", person.getFirstName()),
() -> assertEquals("Doe", person.getLastName())
);
}
// JUnit 4에서는 테스트 메서드 외부(@Test 어노테이션의 인자)에서 정의해야 했던 여러 '옵션'도, 람다를 활용하여 해결하고 있다.
@Test
void exceptionTesting() {
Throwable exception = assertThrows(IllegalArgumentException.class, () -> {
throw new IllegalArgumentException("a message");
});
assertEquals("a message", exception.getMessage());
}
// 람다로부터 결과값 또한 확인할 수 있다.
@Test
void timeoutNotExceededWithResult() {
// The following assertion succeeds, and returns the supplied object.
String actualResult = assertTimeout(ofMinutes(2), () -> {
return "a result";
});
assertEquals("a result", actualResult);
}
}
추정
검증 메서드들과 같이, 추정Assumption
메서드 또한 JUnit 4의 친숙한 모습을 거의 가져왔으며, 람다 지원을 위한 약간의 변경사항이 있다. 자세한 사항은 여기 에서 확인 가능하다.
@ParameterizedTest 와 인자를 제공받는 테스트
@Test
어노테이션과 달리, @ParameterizedTest
어노테이션은 테스트 메서드가 인자를 받을 수 있도록 한다.
@Test
void test() {
fail();
}
// 위 테스트 메서드와 비교하라.
@ParameterizedTest
void testWithStringParameter(String argument) {
assertNotNull(argument);
}
인자를 제공받는 테스트 메서드는 인자를 획득하기 위해 @ValueSource
등의 어노테이션을 추가로 요구한다. 아래는 그 예시이다.
// @ValueSource 어노테이션은 문자열, 정수 등, 원시 자료형(primitive types)의 배열을 메서드에 전달할 수 있다.
@ParameterizedTest
@ValueSource(strings = { "Hello", "World" })
void testWithStringParameter(String argument) {
assertNotNull(argument);
}
JUnit이 제공할 수 있는 인자의 종류와 제공 방법은 다양하며, 사용 가능한 어노테이션은 아래와 같다.
어노테이션 | 설명 |
---|---|
@ValueSource | 테스트 메서드에 원시 자료형 배열을 제공한다. |
@EnumSource | 테스트 메서드에 열거형 배열을 제공한다. 특정 열거형 타입으로부터 모든 객체를 가져오거나, 일부 객체만 가져올 수도 있으며, 옵션에 따라 일부 제외 및 정규표현식을 이용한 선택이 가능하다. |
@MethodSource | 테스트 메서드가 요구하는 인자 타입의 스트림Stream (혹은 Iterable , Iterator )을 반환하는 메서드를 지정하여 인자를 제공한다. 스트림을 제공하는 메서드는 클래스 단위 생명주기가 아닌 경우, 정적 메서드여야 한다. |
@CsvSource | 이 어노테이션은 쉼표로 분리된 데이터(문자열)를 가지는 배열을 테스트 메서드에 제공한다. 테스트 메서드는 한 개 이상의 인자를 제공받을 수 있다. |
@CsvFileSource | 이 어노테이션은 CSV 파일을 사용하여 테스트 메서드에 인자를 제공한다. |
@ArgumentsSource | 이 어노테이션은 @MethodSource 어노테이션과 유사한 동작을 한다. 차이점은, 인자 제공자Provider 가 메서드 대신 재사용 가능한 정적 클래스라는 것이다. |
@RepeatedTest 와 반복 테스트
@RepeatedTest
어노테이션은 특정 테스트 케이스를 반복 실행할 수 있도록 한다.
// 이 테스트 케이스는 열 번 실행된다.
@RepeatedTest(10)
void repeatedTest() {
// ...
}