JUnit 5는 차세대 JUnit 프레임워크로, JVM 환경에서 개발자가 테스트를 작성할 수 있도록 최신 기반을 제공하는 것이 목표입니다. Java 8 이상을 지원하며 다양한 스타일의 테스트 작성을 가능하게 해줍니다.
JUnit 5 시작하기: 의존성 설정
JUnit 5는 Maven과 Gradle 모두에서 사용할 수 있습니다.
Maven을 사용한다면 pom.xml 파일에 아래 의존성을 추가하세요:
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.3.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.3.1</version>
<scope>test</scope>
</dependency>
</dependencies>
JUnit 5에서 눈에 띄는 가장 큰 변화 중 하나는 테스트 클래스와 메서드가 더 이상 public일 필요가 없다는 점입니다. 패키지 수준으로 선언해도 정상적으로 동작합니다.
이제 가장 자주 사용되는 JUnit 5 어노테이션들을 하나씩 살펴보겠습니다.
@Test
@Test 어노테이션은 해당 메서드가 테스트 메서드임을 나타냅니다. 이 어노테이션은 별도의 속성을 받지 않습니다.
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class JUnit5Test {
@Test
void helloJUnit5() {
assertEquals(10, 5+5);
}
}
@ParameterizedTest
@ParameterizedTest를 사용하면 서로 다른 인자를 넘겨 하나의 테스트를 여러 번 실행할 수 있습니다. 일반적인 @Test 메서드처럼 선언하지만, 대신 @ParameterizedTest 어노테이션을 사용합니다.
또한 각 실행에 전달할 인자를 제공하는 소스(source)를 최소 한 개 이상 선언하고, 테스트 메서드에서 해당 인자들을 소비(consume)해야 합니다.
아래 예제는 @ValueSource 어노테이션을 사용해 문자열 배열을 인자 소스로 지정하는 파라미터화된 테스트를 보여줍니다.
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import static org.junit.jupiter.api.Assertions.assertTrue;
class JUnit5Test {
@ParameterizedTest
@ValueSource(strings = { "cali", "bali", "dani" })
void endsWithI(String str) {
assertTrue(str.endsWith("i"));
}
}
@RepeatedTest
JUnit 5에서는 메서드에 @RepeatedTest 어노테이션을 붙이고 원하는 반복 횟수를 지정하는 것만으로 테스트를 여러 번 반복 실행할 수 있습니다.
반복 테스트의 각 실행은 일반적인 @Test 메서드의 실행과 동일하게 동작합니다.
특히 Selenium을 활용한 UI 테스트에서 유용하게 활용됩니다.
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.RepetitionInfo;
import org.junit.jupiter.api.TestInfo;
import static org.junit.jupiter.api.Assertions.assertEquals;
class JUnit5Test {
@RepeatedTest(value = 5, name = "{displayName} {currentRepetition}/{totalRepetitions}")
@DisplayName("RepeatingTest")
void customDisplayName(RepetitionInfo repInfo, TestInfo testInfo) {
int i = 3;
System.out.println(testInfo.getDisplayName() +
"-->" + repInfo.getCurrentRepetition()
);
assertEquals(repInfo.getCurrentRepetition(), i);
}
}
테스트 결과에서 확인할 수 있듯이, i==3일 때만 테스트가 통과하고 그 외에는 실패합니다.
@DisplayName
테스트 클래스와 테스트 메서드에는 커스텀 표시 이름을 지정할 수 있으며, 이 이름은 테스트 러너와 테스트 리포트에 그대로 노출됩니다.
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
@DisplayName("DisplayName Demo")
class JUnit5Test {
@Test
@DisplayName("Custom test name")
void testWithDisplayName() {
}
@Test
@DisplayName("Print test name")
void printDisplayName(TestInfo testInfo) {
System.out.println(testInfo.getDisplayName());
}
}
@BeforeEach
@BeforeEach 어노테이션이 붙은 메서드는 각 테스트 메서드가 실행되기 전에 매번 실행됩니다. JUnit 4의 @Before와 동일한 역할을 합니다.
import org.junit.jupiter.api.*;
class JUnit5Test {
@BeforeEach
void init(TestInfo testInfo) {
String callingTest = testInfo.getTestMethod().get().getName();
System.out.println(callingTest);
}
@Test
void firstTest() {
System.out.println(1);
}
@Test
void secondTest() {
System.out.println(2);
}
}
실행 결과:
firstTest
1
secondTest
2
@AfterEach
@AfterEach 어노테이션이 붙은 메서드는 각 테스트 메서드가 실행된 후에 매번 실행됩니다. JUnit 4의 @After에 해당합니다. 예를 들어 각 테스트가 끝난 후 특정 속성을 초기화해야 한다면, 해당 작업을 수행하는 메서드에 @AfterEach를 붙이면 됩니다.
import org.junit.jupiter.api.*;
class JUnit5Test {
@Test
void firstTest() {
System.out.println(1);
}
@Test
void secondTest() {
System.out.println(2);
}
@AfterEach
void after(TestInfo testInfo) {
String callingTest = testInfo.getTestMethod().get().getName();
System.out.println(callingTest);
}
}
실행 결과:
1
firstTest
2
secondTest
@BeforeAll
@BeforeAll은 모든 테스트가 시작되기 전에 단 한 번 실행됩니다. JUnit 4의 @BeforeClass와 유사하며, 주로 테스트에 필요한 각종 리소스나 설정을 초기화할 때 사용합니다.
import org.junit.jupiter.api.*;
class JUnit5Test {
@BeforeAll
static void init() {
System.out.println("Only run once before all tests");
}
@Test
void firstTest() {
System.out.println(1);
}
@Test
void secondTest() {
System.out.println(2);
}
}
실행 결과:
Only run once before all tests
1
2
@AfterAll
@AfterAll 어노테이션이 붙은 메서드는 모든 테스트가 종료된 후 단 한 번 실행됩니다. JUnit 4의 @AfterClass에 해당하며, 모든 테스트가 끝난 시점에 프로세스를 정리하거나 종료할 때 사용합니다.
import org.junit.jupiter.api.*;
class JUnit5Test {
@Test
void firstTest() {
System.out.println(1);
}
@Test
void secondTest() {
System.out.println(2);
}
@AfterAll
static void after() {
System.out.println("Only run once after all tests");
}
}
실행 결과:
1
2
Only run once after all tests
@Tag
@Tag 어노테이션을 사용하면 클래스 또는 메서드 수준에서 태그를 선언해 테스트를 필터링할 수 있습니다.
선택한 테스트들만 묶어 별도의 테스트 팩(test pack)을 구성하고 싶을 때 특히 유용합니다.
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
@Tag("smoke")
class JUnit5Test {
@Test
@Tag("login")
void validLoginTest() {
}
@Test
@Tag("search")
void searchTest() {
}
}
@Disabled
@Disabled 어노테이션은 클래스 또는 메서드 수준에서 테스트를 비활성화하거나 건너뛸 때 사용합니다. JUnit 4의 @Ignore에 해당합니다.
클래스 수준에서 선언하면 해당 클래스의 모든 @Test 메서드가 건너뛰어지고, 메서드 수준에서 사용하면 해당 메서드만 비활성화됩니다.
테스트 클래스를 비활성화하는 예제:
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@Disabled
class DisabledClassDemo {
@Test
void testWillBeSkipped() {
}
}
테스트 메서드를 비활성화하는 예제:
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
class DisabledTestsDemo {
@Disabled
@Test
void testWillBeSkipped() {
}
@Test
void testWillBeExecuted() {
}
}