[ 공식 문서 ] JUnit 5 User Guide
소개JUnit4, JUnit5JUnit PlatformJUnit JupitorJUnit Vintage사용법(관련 어노테이션 정리)JUnit과 함께 사용할 수 있는 라이브러리Parameterized Test@ValueSource@NullSource , @EmptySource, @NullAndEmptySource@EnumSource이외에도 CsvSource, MethodSource, 등 많은 내용들 있으니 추가적으로 참고하기! @TestInstanceJacoco 이용한 테스트 커버리지 확인Junit에서 package-private class 어떻게 테스트할까protected-method testTroubleShooting
소개
- 매 단위 테스트시마다 테스트 클래스의 인스턴스가 생성되어 독립적인 테스트가 가능하게 합니다.
- 애노테이션(@Before, @BeforeEach, @After, @AfterEach)을 제공해서 테스트 라이프 사이클을 관리하게 해주고 테스트 코드를 간결하게 작성하도록 지원해줍니다.
- 테스트 러너를 제공해서 인텔리제이 / 이클립스 / 메이븐 등에서 테스트 코드를 쉽게 실행하 게 해줍니다.
- assert로 테스트 케이스의 수행 결과를 판별하게 해줍니다. → assertEquals(예상 값, 실제 값)
- 결과는 성공(녹색), 실패(붉은색) 중 하나로 표시해줍니다.
JUnit4, JUnit5


- JUni4를 일반 사용자들이 쓰기에는 좋았지만 이것을 연동해서 무엇을 개발해야하는 개발자들이 얘의 확장성이 떨어져서 연동하기에 어려움이 있었음
- JUnit5에서 확장성을 증가시키도록 아키텍처를 개선함
JUnit Platform
JVM 상에 테스팅 프레임워크를 런칭하기 위한 근간을 제공합니다. 테스트를 발견하고 테스트
계획을 생성하는 TestEngine 인터페이스를 가지고 있고 TestEngine을 통해서 테스트를 발경
하고 ,실행하고 ,결과를 보고합니다.
JUnit Jupitor
TestEngine의 실제 구현체는 별도 모듈입니다. 모듈 중 하나가 jupiter-engine입니다. 이 모듈
은 jupiter-api를 사용해서 작성한 테스트 코드를 발견하고 실행합니다. Jupiter API는 JUnit 5
에 새롭게 추가된 테스트 코드용 API로서, 개발자는 Jupiter API를 사용해서 테스트 코드를 작
성할 수 있습니다
JUnit Vintage
기존에 JUnit 4 버전으로 작성한 테스트 코드를 실행할 때에는 vintage-engine 모듈을 사용합
니다.

- junit-platform-engine의 구현체가 junit-vintage-engine, junit-jupitor-engine임
사용법(관련 어노테이션 정리)
@TestMethodOrder(
MethodOrderer
.OrderAnnotation.
class
)
: 해당 annotation을 테스트 클래스에 붙이고, 각각의 메서드에 @Order
를 붙임으로써 메서드 실행 순서 설정이 가능함@BeforeAll
: 테스트 클래스가 만들어지면서 제일 처음에 한번만 실행됨 (static으로 선언되어야 함) → static으로 선언하지 않으려면 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
이것을 활용 가능함@BeforeEach
: 테스트 클래스의 메소드들 마다 한번씩 실행됨@Disabled
: 해당 테스트를 잠시 동작 안하게 만듦@ExtendWith
: 단위 테스트간에 공통적으로 사용할 기능을 구현하여 @ExtendWith를 통하여 적용할 수 있는 기능을 제공합니다. (junit 공식문서) - Junit 4에서는
@RunWith
이었고 이게@ExtendWith
으로 바뀜
ExtendWith에서 제공해주는 클래스들은 @Autowired
로는 연결 불가함. ApplicationContext 상에 올라가는 건 아닌가봄
@SpringBootTest @Import(RestDocsConfig.class) @ActiveProfiles("test") @ExtendWith(RestDocumentationExtension.class) public abstract class AbstractControllerTest { @Autowired protected RestDocumentationResultHandler restDocs; protected MockMvc mvc; @Autowired private WebApplicationContext context; /* 이 부분 안됨. Autowire 불가 @Autowired private RestDocumentationContextProvider provider */ // 대신 아래와 같이 parameter로 넣어줄 수 있음 @BeforeEach public void setup(RestDocumentationContextProvider provider) { this.mvc = MockMvcBuilders.webAppContextSetup(this.context) .apply(MockMvcRestDocumentation.documentationConfiguration(provider)) .alwaysDo(restDocs) .addFilter(new CharacterEncodingFilter("UTF-8", true)) .build(); }
[레이피엘의 블로그:티스토리]
@BeforeAll static void setup(){ logger.info("aaaa"); } @BeforeEach void init(){ logger.info("Before each test"); } @Test @ExtendWith(WebServerExtension.class) void getProductList(@WebServerUrl String serverUrl) { WebClient webClient = new WebClient(); // Use WebClient to connect to web server using serverUrl and verify response assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); } // @WebServerUrl이 WebServerExtension의 기능
JUnit과 함께 사용할 수 있는 라이브러리
hamcrest, assertj
package org.prgms.voucher; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import java.util.List; import static org.hamcrest.Matchers.*; import static org.hamcrest.MatcherAssert.*; import static org.junit.jupiter.api.Assertions.*; public class HamcrestAssertionTest { @Test @DisplayName("여러 hamcrest matcher 테스트") void hamcrestTest() { assertThat(1 + 1, equalTo(2)); assertThat(1 + 1, is(2)); assertThat(1 + 1, anyOf(is(1), is(2))); assertThat(1+1, not(equalTo(1))); } @Test @DisplayName("컬렉션에 대한 matcher 테스트") // list에 대한 검증이 hamcrest사용하는 가장 주요한 이유 void hamcrestListMacherTest() { var prices = List.of(2, 3, 4); assertThat(prices, hasSize(3)); assertThat(prices, everyItem(greaterThan(1))); assertThat(prices, containsInAnyOrder(3, 4, 2)); assertThat(prices, hasItem(2)); assertThat(prices, hasItem(greaterThanOrEqualTo(2))); } @Test @DisplayName("컬렉션에 대한 matcher 테스트2") // assertj를 활용한 리스트 검증 void assertjListMacherTest2() { var prices = List.of(2, 3, 4); org.assertj.core.api.Assertions.assertThat(prices).size().isEqualTo(3); org.assertj.core.api.Assertions.assertThat(prices).allSatisfy( elem -> org.assertj.core.api.Assertions.assertThat(elem).isGreaterThan(1) ); org.assertj.core.api.Assertions.assertThat(prices).contains(2); org.assertj.core.api.Assertions.assertThat(prices).anySatisfy( elem -> org.assertj.core.api.Assertions.assertThat(elem).isGreaterThanOrEqualTo(2) ); } }
Parameterized Test
Guide to JUnit 5 Parameterized Tests — Baeldung
- 하나의 테스트 메서드를 여러 파라미터에 대해 여러번 실행될 수 있도록 해줌
@ValueSource
@ParameterizedTest @ValueSource(strings = {"", " "}) void isBlank_ShouldReturnTrueForNullOrBlankStrings(String input) { assertTrue(Strings.isBlank(input)); }
- ValueSource를 이용하여 array of literal values 를 전달할 수 있음
@NullSource , @EmptySource, @NullAndEmptySource
@ParameterizedTest @NullSource void isBlank_ShouldReturnTrueForNullInputs(String input) { assertTrue(Strings.isBlank(input)); } @ParameterizedTest @EmptySource void isBlank_ShouldReturnTrueForEmptyStrings(String input) { assertTrue(Strings.isBlank(input)); }
- Null Source는 primitive type은 당연히 못넘김. 둘다 하나의 null 값과 Empty 값을 넘기게 됨
- EmptySource 는 Empty String도 가능하고 Collection type과 배열에도 가능함
- @NullAndEmptySource 는 null과 empty값 둘 다를 넘김
@EnumSource
- enumeration의 다른 값을 여러개 넣고 싶을 때 사용함
이외에도 CsvSource, MethodSource, 등 많은 내용들 있으니 추가적으로 참고하기!
@TestInstance
- LifeCycle.PER_CLASS → 클래스에 한번 인스턴스 만듦. 따라서 필드들도 한번만 초기화됨
- LifeCycle.PER_METOHD → 메서드 실행 시 마다 테스트 인스턴스를 만드는 것. 테스트 인스턴스가 매 메소드 마다 만들어지면서 변수들 초기화 됨
Jacoco 이용한 테스트 커버리지 확인
plugins { id 'jacoco' // 추가 후 }

- 위에서 test를 클릭하면 테스트됨
- ./build/reports/jacoco 아래에 index.html 켜보면 테스트 커버리지도 확인가능함
Junit에서 package-private class 어떻게 테스트할까
- Junit에서 만드는 테스트 클래스도 확인해보면 제일 위에 package가 선언되어 있음
- 이 package가 pakcage-private class의 package와 동일하면 접근이 가능함!
protected-method test
- protected method를 테스트할 때에도 같은 package에 두면 테스트 가능함