JUnit : Java 8부터 제공하는 단위테스트 프레임워크
JUnit 5란?
JUnit 5 시작하기
@Test
// JUnit4
@Test(expected = Exception.class)
void create() throws Exception {
...
}
//JUnit5
@Test
void create() {
...
}
생명주기 어노테이션
@Disabled
class DisabledExample {
@Test
@Disabled("문제가 해결될 때까지 테스트 중단")
void test() {
System.out.println("테스트");
}
@Test
void test2() {
System.out.println("테스트2);
}
}
@DisplayName
@Test
@DisplayName("100, 100, {10, 10} → 102")
void t02() {
assertThat(
new Solution().solution(100, 100, new int[]{10, 10})
).isEqualTo(
102
);
}
@RepeatedTest
@RepeatedTest(10)
@DisplayName("반복 테스트")
void repeatedTest() {
...
}
// 각 iteration의 display name을 커스텀하게 출력할 수 있음
@RepeatedTest(value = 10, name = "{displayName} 중 {currentRepetition} of {totalRepetitions}")
@DisplayName("반복 테스트")
void repeatedTest2() {
...
}
@ParameterizedTest
@ParameterizedTest
@CsvSource(value = {"ACE, ACE:12", "ACE, ACE, ACE:13", "ACE, ACE, TEN:12", delimiter = ":")
@DisplayName("에이스 카드가 여러 개일 때 합 구하기")
void calculateCardSumWhenAceIsTwo(final String input, final int expected) {
final String[] inputs = input.split(", ");
for (final String number : inputs) {
final CardNumber cardNumber = CardNumber.valueOf(number);
dealer.receiveOneCard(new Card(cardNumber, CardType.CLOVER));
}
assertThat(dealer.calculateScore()).isEqualTo(expected);
}
@Nested
테스트 클래스 안에서 내부 클래스를 정의해 테스트를 계층화 할 때 사용
내부 클래스는 부모 클래스의 멤버 필드에 접근 가능
Before / After와 같은 테스트 생명주기에 관계된 메소드들도 계층에 맞춰 동작
@DisplayName("findResult 메서드는")
@Nested
class findResult {
@DisplayName("플레이어가 블랙잭일 때")
@Nested
class findWhenPlayerBlackjack {
private Result findResult(){
...
}
}
@DisplayName("딜러가 블랙잭이면 DRAW 반환한다")
@Test
void returnDraw() {
...
}
}
Assertions
JUnit5 추가된 메서드
assertAll(executables...)
// 기존에는 중간에 오류나면 남은 assert 메서드 실행하지 않음
// ex) 2번째 assertEquals에서 오류나면 assertTrue는 실행하지 않고 실패 처리
@Test
public void create_study() {
Study study = new Study();;
assertNotNull(study);
assertEquals(Status.STARTED, study.getStatus(), "처음 상태값이 DRAFT");
assertTrue(study.getLimit() > 0, () -> "최대 인원은 0보다 커야한다.");
}
// 세 테스트케이스 모두 다 실행하고 결과를 알려준다.
// 중간에 실패하더라도 모두 다 실행하여 발생한 오류를 모아서 확인 가능
@Test
public void create_study() {
Study study = new Study();
assertAll(
() -> assertNotNull(study),
() -> assertEquals(Status.STARTED, study.getStatus(), "처음 상태값이 DRAFT"),
() -> assertTrue(study.getLimit() > 0, () -> "최대 인원은 0보다 커야한다.")
);
}
asserThrows(expectedType, executable)
// JUnit4
// 단순히 예외 발생 여부만 검증
@Test(expected = Exception.class)
void create() throws Exception {
...
}
// JUnit5
// 예외 발생을 검증하고 예외를 반환받아서 예외의 상태까지 검증 가능
// assertDoesNotThrow : 예외가 발생하지 않았는지 검증하는 단정문
@Test
void exceptionThrow() {
Exception e = assertThrows(Exception.class, () -> new Test(-10)); // 람다 표현식 뒤에가 예외가 있는지 검증
assertDoesNotThrow(() -> System.out.println("Do Something")); // Junit 5.2부터 추가됨, 람다 표현식 뒤에 부분 실행 결과가 예외가 없는지 검증
}
assertTimeOut(duration, executable)
@Rule
public Timeout timeout = Timeout.seconds(5); // 이전 버전에서 Rule 어노테이션으로 검증 가능하긴 했음
// 테스트 메소드 전체에 대한 시간 제한만 가능하다는 단점
// 특정 부분의 실행 시간 제한 불가
class TimeoutExcample {
@Test
@DisplayName("타임아웃 준수")
void timeoutNotExceeded() {
// 단정문을 사용함으로 테스트 메서드 내부 처리 뿐 아니라 데이터 생성 부분과 같은 것들을 좀 더 유연하게 테스트 할 수 있어 사용성 개선
assertTimeout(ofMinutes(2), () -> Thread.sleep(10));
}
@Test
@DisplayName("타임아웃 초과")
void timeoutExceeded() {
assertTimeout(ofMillis(10), () -> Thread.sleep(100));
}
}
Assumtion
void dev_env_only() {
assumeTrue ("DEV".equals(System.getenv("ENV")), () -> "개발 환경이 아닙니다.");
assertEquals("A", "A"); // 단정문이 실행되지 않음
}
void some_test() {
assumingThat("DEV".equals(System.getenv("ENV")),
() -> {
assertEquals("A", "B"); // 단정문이 실행되지 않음
});
assertEquals("A", "A"); // 단정문이 실행됨
표현 | JUnit4 | JUnit5 | 비고 |
---|---|---|---|
import문 수정 | org.junit.* | org.junit.jupiter.* | jupiter로 변경 |
어노테이션수정 | @BeforeClass | @BeforeAll | |
@Before | @BeforeEach | ||
@After | @AfterEach | ||
@AfterClass | @AfterAll | ||
@Ignore | @Disabled | ||
Assert | Assert | Assertions | Assert -> Assertions |
|