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() 메서드들을 넘겨주면 가변 인자로 인식하여 처리 후, 에러 메시지로 보여준다.
참고 :
'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 |
댓글