[JUnit5] JUnit5
in Development on Server, Junit5
“해당 포스팅은 우아한Tech의 [10분 테코톡] 🌊 바다의 JUnit5 사용법을 참고하여 포스팅하였습니다. 영상을 제작해주신 우아한Tech와 바다님에게 감사드립니다.”
#목차
JUnit5
단위 테스트(Unit Test) 란?
“프로그래밍에서 소스 코드의 특정 모듈이 의도된 대로 정확히 작동하는지 검증하는 절차이다.”
- 모든 함수와 메서드에 대한 테스트 케이스(Test case)를 작성하는 절차를 말한다.
- 이를 통해서 언제라도 코드 변경으로 인해 문제가 발생할 경우, 단시간 내에 이를 파악하고 바로 잡을 수 있도록 해준다.
JUnit 이란?
“JetBrains 조사에 따르면 단위 테스트를 수행하는
Java
개발자의93%
가JUnit
을 사용하고,51%
는Mockito
를 사용한다.”
Java
개발자의93%
가 사용하는 단위 테스트 프레임워크이다.
JUnit5 란?
JUnit5
는 2017년 10월에 공개 되었으며,SpringBoot 2.2
버전 이상부터 기본으로 제공하고 있다.
“
JUnit4
는 하나의jar
파일로 의존성을 불러와 다른 라이브러리를 참조해서 사용하는 구조였는데,JUnit5
부터는JUnit5
그 자체로 모듈화가 되어있다.JUnit5
는 3개의 하위 프로젝트, 즉JUnit Platform
,JUnit Jupiter
,JUnit Vintage
로 구성이 되며Java8
부터 사용가능하다.”
JUnit Platform
: 테스트를 발견하고 테스트 계획을 생성하는TestEngine
인터페이스를 가지고 있다.Platform
은TestEngine
을 통해서 테스트를 발견하고, 실행하며, 결과를 보고한다.JUnit Jupiter
:TestEngine
의 실제 구현체는 별도 모듈이며, 그 중 하나가Jupiter-Engine
이다. 이 모듈은Jupiter-API
를 사용해서 작성한 테스트 코드를 발견하고 실행한다.Jupiter API
는JUnit5
에 새롭게 추가된 테스트 코드용API
로서, 개발자는Jupiter API
를 사용해서 테스트 코드를 작성할 수 있다.JUnit Vintage
: 기존에JUnit4
버전으로 작성한 테스트 코드를 실행할 때에는Vintage-Engine
모듈을 사용한다.
JUnit5 설정 방법
SpringBoot
프로젝트SpringBoot
2.2버전 이상부터는 기본적으로JUnit5
의존정이 자동으로 추가되어 따로 설정할 필요 없이 바로 사용 가능하다.
// file: "build.gradle"
// spring boot 3.0.6 버전 (2023-05-03 기준)
dependencies {
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
tasks.named('test') {
useJUnitPlatform()
}
SpringBoot
프로젝트가 아닐 경우- 다음과 같이 의존성을 추가해주면 된다.
Maven Setup
<!-- file: "pom.xml"-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.9.1</version>
<scope>test</scope>
</dependency>
Gradle Setup
// file: "build.gradle"
test {
useJUnitPlatform()
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
}
JUnit5 @Annotations
“
JUnit Jupiter
에는 테스트 구성 및 프레임워크 확장을 위해 다음과 같은 어노테이션을 지원한다. 달리 명시되지 않는 한, 모든 핵심 어노테이션은junit-jupiter-api
모듈의org.junit.jupiter.api
패키지에 있다.”
Annotation | description |
---|---|
@Test | 메서드가 테스트 메서드임을 나타낸다. JUnit4 의 @Test 어노테이션과 달리 이 어노테이션은 attributes(속성) 를 선언하지 않는데, 이는 JUnit Jupiter 의 테스트 확장이 자체 전용 어노테이션을 기반으로 작동하기 때문이다. 이러한 메서드는 재정의하지 않는 한 상속된다. |
@ParameterizedTest | 메서드가 매개변수화된 테스트임을 나타낸다. 이러한 메서드는 재정의되지 않는 한 상속된다. |
@RepeatedTest | 메서드가 반복 테스트에 대한 테스트 템플릿임을 나타낸다. 이러한 메서드는 재정의되지 않는 한 상속된다. |
@TestFactory | 메서드가 동적 테스트를 위한 테스트 팩토리임을 나타낸다. 이러한 메서드는 재정의되지 않는 한 상속된다. |
@TestTemplate | 메서드가 등록된 프로바이더가 반환하는 호출 컨텍스트의 수에 따라 여러 번 호출되도록 설계된 테스트 케이스용 템플릿임을 나타낸다. 이러한 메서드는 재정의되지 않는 한 상속된다. |
@TestClassOrder | 어노테이션된 테스트 클래스에서 @Nested 테스트 클래스에 대한 테스트 클래스 실행 순서를 구성하는 데 사용된다. 이러한 어노테이션은 상속된다. |
@TestMethodOrder | 어노테이션된 테스트 클래스에 대한 테스트 메서드 실행 순서를 구성하는 데 사용되며, JUnit4 의 @FixMethodOrder 와 유사하다. 이러한 어노테이션은 상속된다. |
@TestInstance | 어노테이션된 테스트 클래스에 대한 테스트 인스턴스 라이프사이클을 구성하는 데 사용된다. 이러한 어노테이션은 상속된다. |
@DisplayName | 테스트 클래스 또는 테스트 메서드의 사용자 지정 디스플레이 이름을 선언한다. 이러한 어노테이션은 상속되지 않는다. |
@DisplayNameGeneration | 테스트 클래스에 대한 사용자 지정 디스플레이 이름 생성기를 선언한다. 이러한 어노테이션은 상속된다. |
@BeforeEach | @BeforeEach 어노테이션이 달린 메서드가 현재 클래스의 각각 @Test , @RepeatedTest , @ParameterizedTest 또는 @TestFactory 어노테이션이 달린 메서드 전에 실행되어야 함을 나타낸다(JUnit4 의 @Before 와 유사). 이러한 메서드는 재정의되거나 대체되지 않는 한 상속됩니다(즉, Java 의 표시 규칙에 관계없이 서명만 기준으로 대체됨). |
@AfterEach | @AfterEach 어노테이션이 달린 메서드가 현재 클래스의 각각 @Test , @RepeatedTest , @ParameterizedTest 또는 @TestFactory 어노테이션이 달린 메서드 이후에 실행되어야 함을 나타낸다(JUnit4 의 @After 와 유사). 이러한 메서드는 재정의되거나 대체되지 않는 한 상속된다(즉, Java 의 표시 규칙에 관계없이 서명만 기준으로 대체됨). |
@BeforeAll | @BeforeAll 어노테이션이 달린 메서드가 현재 클래스의 모든 @Test , @RepeatedTest , @ParameterizedTest 및 @TestFactory 어노테이션이 달린 메서드보다 먼저 실행되어야 함을 나타낸다(JUnit4 의 @BeforeClass 와 유사). 이러한 메서드는 숨겨지거나 재정의되거나 대체되지 않는 한(즉, Java 의 표시 규칙에 관계없이 서명만 기준으로 대체되지 않는 한) 상속되며, per-class 테스트 인스턴스 라이프사이클이 사용되지 않는 한 정적(static) 이어야 합니다. |
@AfterAll | @AfterAll 어노테이션이 달린 메서드가 현재 클래스의 모든 @Test , @RepeatedTest , @ParameterizedTest , @TestFactory 어노테이션이 달린 메서드 다음에 실행되어야 함을 나타낸다(JUnit4 의 @AfterClass 와 유사). 이러한 메서드는 숨겨지거나 재정의되거나 대체되지 않는 한(즉, Java 의 표시 규칙에 관계없이 서명만 기준으로 대체되지 않는 한) 상속되며, per-class 테스트 테스트 인스턴스 라이프사이클이 사용되지 않는 한 정적(static) 이어야 합니다. |
@Nested | @Nested 어노테이션이 달린 클래스가 정적(static) 이 아닌 중첩된 테스트 클래스임을 나타낸다. Java8 부터 Java15 까지에서는 “클래스-별” 테스트 인스턴스 라이프사이클을 사용하지 않는 한 @BeforeAll 및 @AfterAll 메서드를 @Nested 테스트 클래스에서 직접 사용할 수 없다. Java16 부터는 테스트 인스턴스 라이프사이클 모드 중 하나를 사용하여 @Nested 테스트 클래스에서 @BeforeAll 및 @AfterAll 메서드를 정적(static) 으로 선언할 수 있다. 이러한 어노테이션은 상속되지 않는다. |
@Tag | Class 또는 Method 수준에서 테스트를 필터링하기 위한 태그를 선언하는 데 사용되며, TestNG 또는 JUnit4 의 범주에 있는 테스트 그룹과 유사하다. 이러한 어노테이션은 클래스 수준에서는 상속되지만, 메서드 수준에서는 상속되지 않는다. |
@Disabled | Test Class 또는 Test Method 를 비활성화하는 데 사용되며, JUnit4 의 @Ignore 와 유사하다. 이러한 어노테이션은 상속되지 않는다. |
@Timeout | @Test , @TestFactory , @TestTemplate 또는 lifecycle method 의 실행이 지정된 기간을 초과하는 경우 실패하는 데 사용된다. 이러한 어노테이션은 상속된다. |
@ExtendWith | 확장을 선언적으로 등록하는 데 사용된다. 이러한 어노테이션은 상속된다. |
@RegisterExtension | 필드를 통해 확장을 프로그래밍 방식으로 등록하는 데 사용된다. 이러한 필드는 음영 처리되지 않는 한 상속된다. |
@TempDir | lifecycle method 또는 test method 에서 필드 주입 또는 매개변수 주입을 통해 임시 디렉터리를 제공하는 데 사용되며, org.junit.jupiter.api.io 패키지에 있다. |
Continue with [JUnit5] JUnit5 어노테이션 ver1
Continue with [JUnit5] JUnit5 어노테이션 ver2
JUnit4 vs JUnit5 @Annotations 생명주기(LifeCycle)
Feature | JUnit4 | JUnit5 |
---|---|---|
Test Method임을 선언 | @Test | @Test |
해당 클래스에 위치한 모든 테스트 메서드 실행 전에 딱 한 번 실행되는 메서드. @BeforeAll 어노테이션을 사용하기 위해선 static 을 선언해줘야 한다. | @BeforeClass | @BeforeAll |
해당 클래스에 위치한 모든 테스트 메서드 실행 후에 딱 한 번 실행되는 메서드 @AfterAll 어노테이션을 사용하기 위해선 static 을 선언해줘야 한다. | @AfterClass | @AfterAll |
해당 클래스에 위치한 모든 테스트 메서드 실행 전에 실행되는 메서드 | @Before | @BeforeEach |
해당 클래스에 위치한 모든 테스트 메서드 실행 후에 실행되는 메서드 | @After | @AfterEach |
Test Method 나 Class 를 비활성화 | @Ignore | @Disabled |
동적 테스트에 사용 | N/A | @TestFactory |
중첩 테스트에 사용 | N/A | @Nested |
태그 지정 및 필터링 | @Category | @Tag |
확장을 선언적으로 등록할 때 사용 | N/A | @ExtendWith |
@BeforeAll vs @BeforeEach 와 @AfterAll vs @AfterEach
- 두 개 어노테이션 모두 하나 혹은 여러 개의 테스트 조건을
setup
할 때 사용하지만 하나의 테스트 클래스 안에 여러 개의 테스트가 있는 경우@BeforeEach
와@AfterEach
는 여러번 실행되지만,@BeforeAll
와@AfterAll
은 딱 한 번만 실행된다. @BeforeEach
와@AfterEach
는@Test
어노테이션이 붙은 메서드가 실행이 되기 전(@BeforeEach
)과 후(@AfterEach
) 실행이 된다.@BeforeAll
과@AfterAll
은 해당 클래스 내에 처음 시작(@BeforeAll
)과 맨 마지막 끝(@AfterAll
)에 실행이 된다.
JUnit5 LifeCycle 예시
import static org.assertj.core.api.Assertions.assertThat;
class JUnit5LifecycleTest {
@BeforeAll
static void BeforeAll() {
System.out.println("@BeforeAll");
}
@BeforeEach
void BeforeEach() {
System.out.println("@BeforeEach");
}
@AfterEach
void afterEach() {
System.out.println("@AfterEach");
}
@AfterAll
static void AfterAll() {
System.out.println("@AfterAll");
}
@Test
void 라이프사이클_테스트1() {
String str = "abc";
System.out.println("라이프사이클_테스트1 = " + str);
assertThat(str).contains("a");
}
@Test
void 라이프사이클_테스트2() {
String str = "abc";
System.out.println("라이프사이클_테스트2 = " + str);
assertThat(str).contains("b");
}
}
결과 출력
Assertions
- 실제 테스트에서 검증하고자 하는 내용을 확인하는 기능을 제공하는 패키지이다.
- 실제 값(
actual
)이 기대한 값(expected
)과 같은지 확인하는 메서드이다. Assertions
에 대해서는 아래 포스팅에서 자세히 다루고 있습니다.
Continue with [JUnit5] JUnit5 AssertJ