1. JUnit5 란 무엇인가?
자바 8 부터 사용 가능한 테스팅 기반 프레임워크이다. 테스트와 관련된 여러 메서드와 어노테이션을 지원한다.
- JUnit Platform: 테스팅 프레임워크를 실행해주는 런처와 테스트 엔진을 위한 API를 제공한다.
- Jupiter: JUnit5 을 위한 테스트 API 와 실행 엔진을 제공한다.
- Vintage: JUnit3, JUnit4 로 작성된 테스트를 JUnit5 에서 실행하기 위한 모듈을 제공한다.
JUnit5 에서 제공하는 API 는 Jupiter 이다. build.gradle 파일을 열어보면 dependencies 안에 Jupiter 를 로드해 놓은 것을 볼 수 있다.
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
}
JUnit5 는 JUnit4 와는 달리 클래스와 메서드에 public 을 붙일 필요가 없다. 왜냐하면 자바 리플렉션 (Reflection)을 사용하기 때문에 private 이나 default 도 접근하고 실행할 수 있기 때문에 꼭 public 일 필요가 없기 때문이다. 리플렉션이란, 구체적인 클래스 타입을 알지 못해도 그 클래스의 메서드, 타입, 변수들에 접근할 수 있도록 해주는 자바 API 이다.
테스트를 실행할 메서드는 static 메서드이며, @Test 어노테이션을 붙여 테스트 메서드임을 명시한다. private 접근 제어자로 정의된 메서드는 Test 의 대상이 될 수 없다.
2. 어노테이션
JUnit5 의 자주 사용되는 어노테이션은 아래와 같다.
| 어노테이션 | 설명 |
| @Test | 기본적인 테스트를 나타낸다. |
| @ParameterizedTest | 매개변수를 받는 테스트를 작성할 수 있다. |
| @RepeatedTest | 반복되는 테스트를 작성할 수 있다. |
| @TestFactory | @Test 로 선언된 정적 테스트가 아닌 동적으로 테스트를 사용한다. |
| @TestInstance | 테스트 클래스의 생명 주기를 설정한다. |
| @TestTemplate | 공급자에 의해 여러 번 호출될 수 있도록 설계된 테스트 케이스 템플릿임을 나타낸다. |
| @TestMethodOrder | 테스트 메서드 실행 순서를 구성하는 데 사용한다. |
| @DisplayName("name") | 테스트 클래스 또는 메서드의 실행 시, 콘솔에 표시 될 해당 테스트의 이름을 원하는 이름으로 붙일 수 있다. |
| @DisplayNameGeneration | 이름 생성기를 선언한다. 예를 들어 '_' 를 공백 문자로 치환해주는 생성기가 있다. ex) new_test -> new test |
| @BeforeEach | 각 테스트를 실행하기 이전에 실행되는 테스트이다. |
| @AfterEach | 각 테스트를 실행한 이후에 실행되는 테스트이다. |
| @BeforeAll | 모든 테스트들이 실행되기 전에 딱 한 번 먼저 실행되는 테스트이다. 반드시 static 으로 선언해야 하며, private 으로 만들 수 없고 return 타입이 있으면 안 된다. |
| @AfterAll | 모든 테스트들이 실행된 이후에 딱 한 번 실행되는 테스트이다. 반드시 static 으로 선언해야 하며, private 으로 만들 수 없고 return 타입이 있으면 안 된다. |
| @Nested | 클래스를 정적이 아닌 중첩 테스트 클래스임을 나타낸다. |
| @Tag | 클래스 또는 메서드 레벨에서 태그를 선언할 때 사용한다. |
| @Disabled | 만들어 놓은 클래스 또는 테스트를 무시할 때 사용한다. |
| @Timeout | 테스트 실행 시간을 선언한 후 초과되면 실패하도록 설정한다. |
| @ExtendWith | 확장을 선언적으로 등록할 때 사용한다. |
| @TempDir | 필드 주입 또는 매개변수 주입을 통해 임시 디렉토리를 제공하는데 사용한다. |
JUnit5 는 각 테스트 메서드마다 다음 순서대로 코드를 실행한다.
- 테스트 메서드를 포함한 인스턴스 생성
- @BeforeXXX 어노테이션이 붙은 메서드 실행 (Each 이면 각 테스트 메서드 실행 전, All 이면 모든 테스트 메서드 실행 전 한 번만 수행)
- @Test 어노테이션이 붙은 테스트 메서드 실행
- @AfterXXX 어노테이션이 붙은 메서드 실행 (Each 이면 각 테스트 메서드 실행이 끝나나 후, All 이면 모든 테스트 메서드 실행 후 한 번만 수행)
테스트 메서드 간 순서대로 작성되어 있어도 실행 순서는 보장되지 않는다. 테스트 코드 역시 유지보수가 들어가기 때문에 실행 순서 보장과 같은 의존이 생기지 않도록 작성해야 한다. 따라서 각 테스트 메서드는 독립적으로 실행되도록 하고, static field 를 사용하지 않는 방법으로 의존 관계를 없앨 수 있다.
3. 테스트 클래스와 메서드
테스트 클래스는 하나 이상의 테스트 메서드를 포함하는 최상위 클래스, static 클래스, 또는 중첩 클래스여야 한다. 또한, 테스트 클래스는 추상 클래스로 정의되서는 안 되며, 단일 생성자만 가져야 한다. 이때, 테스트 메소드는 '@Test, @RepeatedTest, @ParameterizedTest, @TestFactory, @TestTemplate' 중 하나의 어노테이션으로 선언된 메서드를 말한다.
생명 주기 메서드는 '@BeforeAll, @AfterAll, @BeforeEach, @AfterEach' 중 하나의 어노테이션으로 선언된 메서드이다. 테스트 메서드와 생명 주기 메서드는 모두 추상 메서드로 정의되면 안 되며, 값을 반환해서도 안 된다. 그리고 두 메소드는 non-static 인 인스턴스 메소드이어야만 한다.
4. 단언문 클래스 (Assertions)
JUnit5 의 Jupiter Assertions 메서드는 모두 static 메서드이다. 대표적인 메서드는 아래와 같다.
| Assertions | 설명 |
| assertEquals() | 기대하는 값과 실제 값이 같은 지 비교할 때 사용한다. 인자를 2개만 사용하면 그 두 개가 같은 값인 지 비교하고, 3개를 사용하면 테스트가 실패하였을 경우 3번째 인자를 메시지로 출력해준다. |
| assertNotEquals() | 기대하는 값과 실제 값이 확실히 다른 지 확인할 때 사용한다. |
| assertSame() | 두 객체가 동일한 객체인 지 검사한다. |
| assertTrue() | assertEquals() 와 같은 맥락으로, 인자를 1개만 사용하면 그 식이 true 인지 확인하고, 2개를 사용하면 테스트가 실패하였을 경우 2번째 인자를 메시지로 출력해준다. |
| assertFalse() | assertTrue() 와 같은 맥락으로 값이 false 인지 검사한다. |
| assertAll() | 여러 개의 assertions 가 만족할 경우에만 테스트를 통과하였다고 판단하고 싶을 경우에 사용한다. 인자로 람다식을 사용하며, 여러 개의 람다식이 동시에 실행되는 특징이 있다. |
| assertThrows() | 특정 예외가 발생하였는지 확인하고 싶을 때 사용한다. 첫 번째 인자는 확인 할 예외 클래스이고, 두 번째 인자는 테스트하고자 하는 코드를 작성하면 된다. |
| assertTimeout() | 특정 시간 안에 실행이 끝나는 지 확인하고 싶을 때 사용한다. 단순히 특정 시간 안에 실행이 끝나는 지만 확인한다. |
| assertTimeoutPreemtively() | 특정 시간 안에 실행이 끝나는 지 확인하고 싶을 때 사용한다. 특정 시간 안에 실행이 끝나지 않으면 바로 종료한다. |
assertXXX() 메서드는 실패하면 다음 코드는 실행하지 않고 바로 예외를 발생시킨다. 따라서 모든 검증을 실행하고 실패한 것만 확인하고 싶다면 assertAll() 의 매개변수로 assertXXX() 메서드들을 넘겨주면 가변 인자로 인식하여 처리 후, 에러 메시지로 보여준다.
참고 :
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
'TIL' 카테고리의 다른 글
| 약간의 뽀모도로를 곁들인 (22.09.10 TIL) (0) | 2022.09.10 |
|---|---|
| 추상화 레벨이란? (22.09.09 TIL) (0) | 2022.09.09 |
| Gradle 이란? (22.09.07 TIL) (0) | 2022.09.07 |
| replace() 와 replaceAll() 의 차이 (22.09.06 TIL) (0) | 2022.09.06 |
| 라이브러리와 프레임워크의 차이? (22.09.05 TIL) (1) | 2022.09.05 |
댓글