📚 참고자료

  • [10분 테코톡] 🌊 바다의 JUnit5 => 링크

 

1️⃣ JUnit이란?

  • 자바 개발자의 93%가 사용하는 단위 테스트 프레임워크
  • JUnit5는 2017년 10월 공개
  • 스프링 부트 2.2버전 이상부터 기본 제공

 

 

  • Platform : 테스트를 실행해주는 런처 제공. TestEngine API 제공
  • Jupiter : JUnit 5를 지원하는 TestEngine API 구현체
  • Vintage : Junit 4와 3을 지원하는 TestEngine 구현체

 

셋 다 JUnit5 세부 모듈이다

 

 

 

2️⃣ JUnit5 시작하기

 

  • 스프링 부트 프로젝트
    => 스프링 부트 2.2버전 이상부터는 기본적으로 JUnit5 의존성이 추가된다.

  • 스프링 부트 프로젝트가 아닐 경우
    => 다음과 같이 의존성을 추가해주면 된다.
 <dependency>
 	<groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.6.2</version>
    <scope>test</scope>
 </dependency>

 

 

 

3️⃣ 어노테이션들(Annotaions)

 

@Test

  • 테스트 메서드라는 것을 나타내는 어노테이션
  • JUnit4와 다르게 어떠한 속성도 선언하지 않는다.
// JUnit4
@Test(expected = Exception.class)
void create() throws Exception {
	...
}

// JUnit5
@Test
void create() {
	...
}

 

생명주기(LifeCycle) 어노테이션

  • @BeforeAll : 해당 클래스에 위치한 모든 테스트 메서드 실행 전에 딱 한번 실행되는 메서드
  • @AfterAll : 해당 클래스에 위치한 모든 테스트 메서드 실행 후에 딱 한번 실행되는 메서드
  • JUnit4의 @BeforeClass / @AfterClass 와 유사

  • @BeforeEach : 해당 클래스에 위치한 모든 테스트 메서드 실행 전에 실행되는 메서드
  • @AfterEach : 해당 클래스에 위치한 모든 테스트 메서드 실행 후에 실행되는 메서드
  • JUnit4의 @Before / @After와 유사
  • 매 테스트 메서드마다 새로운 클래스를 생성(new)하여 실행 (비효율적)

 

 

@Disabled

  • 테스트를 하고 싶지 않은 클래스나 메서드에 붙이는 어노테이션
  • JUnit4의 @Ignore 과 유사
class DisabledExample {
	@Test
    @Disabled("문제가 해결될 때까지 테스트 중단")
    void test() {
    	System.out.println("테스트");
    }
    
    @Test
    void test2() {
    	System.out.println("테스트2");
    }
}

 

 

@DisplayName

  • 어떤 테스트인지 쉽게 표현할 수 있도록 해주는 어노테이션
  • 공백, Emoji, 특수문자 등을 모두 지원
@DisplayName("특수 테스트\uD83D\uDE00")
class DisplayNameExample {
	@Test
    @DisplayName("굉장한 테스트입니다.")
    void test() {
    }
}

 

 

 

@RepeatedTest

  • 특정 테스트를 반복시키고 싶을 때 사용하는 어노테이션
  • 반복 횟수와 반복 테스트 이름을 설정가능
@RepeatedTest(10)
@DisplayName("반복 테스트")
void repeatedTest() {
	...
}

@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와 같은 테스트 생명주기에 관계된 메소드들도 계층에 맞춰 동작

 

 

Assertions

  • 사전적 의미: 주장, 행사, 단정문
  • 테스트 케이스의 수행 결과를 판별하는 메서드
  • 모든 Junit Jupiter Assertions는 static 메서드

 

 

Assertions - assertAll(executables...)

  • 매개변수로 받는 모든 테스트코드를 한 번에 실행
  • 오류가 나도 끝까지 샐행한 뒤 한 번에 모아서 출력
@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보다 커야한다.")
    );
}

 

 

 

Assertions - assertThrows(expectedType, executable)

  • 예외 발생을 확인하는 테스트
  • executable의 로직이 실행하는 도중 expectedType의 에러를 발생시키는지 확인
// JUnit4
@Test(expected = Exception.class)
void create() throws Exception {
	...
}

// JUnit5
@Test
void exceptionThrow() {
	Exception e = assertThrows(Exception.class, () -> new Test(-10));
    assertDoesNotThrow(() -> System.out.println("Do Something"));
}

 

 

Assertions - assertTimeout(duration, executable)

  • 특정 시간 안에 실행이 완료되는지 확인
  • Duration : 원하는 시간
  • Executable : 테스트할 로직
@Rule
public Timeout timeout = Timeout.seconds(5);

class TimeoutExample {
	@Test
    @DisplayName("타임아웃 준수")
    void timeoutNotExceeded() {
    	assertTimeout(ofMinutes(2), () -> Thread.sleep(10));
	}

	@Test
	@DisplayName("타임아웃 초과")
	void timeoutExceeded() {
		assertTimeout(ofMillis(10), () -> Thread.sleep(100));
	}
}

 

 

Assumption

  • 전제문이 true라면 실행, false라면 종료
  • assumeTrue : false일 때 이후 테스트 전체가 실행되지 않음
  • assumingThat : 파라미터로 전달된 코드블럭만 실행되지 않음
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");  // 단정문이 실행됨
}

 


느낀 점

  • 어노테이션을 단순히 적용하는 것이 아닌 좀 더 깊게 파고 들어가 공부 할 수 있도록 진행
  • 이론만 공부하면 확실히 해당 내용을 익힐 수 없다는 느낌을 받았습니다.
    => 정리를 하고 다음에 JUnit5를 사용할 때 이 글을 참고하면서 공부
반응형

+ Recent posts