본문 바로가기
TIL

JUnit5 살펴보기 (22.09.08 TIL)

by winteringg 2022. 9. 8.

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 는 각 테스트 메서드마다 다음 순서대로 코드를 실행한다.

  1. 테스트 메서드를 포함한 인스턴스 생성
  2. @BeforeXXX 어노테이션이 붙은 메서드 실행 (Each 이면 각 테스트 메서드 실행 전, All 이면 모든 테스트 메서드 실행 전 한 번만 수행)
  3. @Test 어노테이션이 붙은 테스트 메서드 실행
  4. @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

댓글