본문 바로가기
Java

JUnit5

by soro.k 2022. 9. 11.

 

JUnit 이란?

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

 

 

JUnit5

JUnit5는 java 8부터 지원하며, 이전 버전으로 작성된 테스트 코드여도 컴파일이 정상적으로 지원된다. 이전 버전과 다르게 JUnit5는 세 개의 서브 프로젝트로 이루어져있다.

 

JUnit Platform

                            - JVM에서 테스트 프레임워크를 실행하는 데 기초를 제공

                            - TestEngine API를 제공해 테스트 프레임워크를 개발할 수 있음

JUnit Jupiter

                            - JUnit5에서 테스트를 작성하고 확장하기 위한 모델 조합

JUnit Vintage

                            - JUnit3와 JUnit4를 기반으로 돌아가는 플랫폼에 테스트 엔진 제공

 

 

 

Annotation

 

@Test : 테스트 메소드라는 것을 나타낸다.

// JUnit4
@Test(expected = Exception.class)
void 테스트() throws Exception { ... }

// JUnit5
@Test
void 테스트() { ... }

 

@DisplayName : 테스트 클래스나 테스트 메소드에 이름을 붙여줄 때 사용한다.

@Test
@DisplayName("로그인 테스트")
void 로그인_테스트() { ... }

- 기본적으로 테스트 이름은 메소드 이름을 따라가지만 테스트 이름을 변경하고 싶을 때 이 어노테이션을 사용하면 된다.

- 공백이나 특수문자, 이모지도 가능하다.

 

@BeforeAll, @AfterAll

- 해당 클래스에 위치한 모든 테스트 메소드 실행 전/후로 딱 한 번만 실행된다.

- JUnit4의 @BeforeClass, @AfterClass 와 같은 역할을 한다.

 

@BeforeEach, @AfterEach

- 해당 클래스에 위치한 모든 테스트 메소드 실행 전에 실행된다.

- JUnit4의 @Before, @After와 같은 역할을 한다.

 

@Disabled : 테스트 클래스나 메소드의 테스트를 비활성화 한다.

// JUnit4
@Test
@Ignore
void test() {...}

// JUnit5
@Test
@Disabled("문제가 해결될 때까지 테스트 중단")
void test() { ... }

 

@RepeatedTest : 특정 테스트를 반복시킨다.

@RepeatedTest(10)
// @RepeatedTest(value = 10, 
// name = "{displayName} 중 {currentRepetition} of {totlaRepetitions}) 
@DisplayName("반복 테스트")
void repeatedTest() { ... }

 

@ParameterizedTest : 테스트에 여러 다른 매개변수를 대입해가며 반복 실행한다.

@ParameterizedTest
@CsvSource(value = {"ACE,ACE:12", "ACE,ACE,ACE:13"}, delimeter = ':')
@DisplayName("에이스 카드가 여러 개일 때")
void calculateSumWhenAceIsTwo(final String input, final int expected) { ... }

 

@Nested : 테스트 클래스 안에서 내부 클래스를 정의해 테스트를 계층화한다.

 

@Timeout : 주어진 시간 안에 테스트가 끝나지 않으면 실패한다.

 

 

테스트 클래스와 메소드

테스트 클래스

최상위 클래스, 스태틱 멤버 클래스, @Nested 클래스에 적어도 한 개의 @Test 어노테이션이 달린 테스트 메소드가 포함되있는 걸 말한다. 테스트 클래스는 abstract이면 안되고, 하나의 생성자가 있어야 한다.

 

테스트 메소드

@Test, @RepeatedTest, @ParameterizedTest, @TestFactory, @TestTemplate 같은 메타 어노테이션이 메소드에 붙여진 메소드를 말한다.

 

라이프사이클 메소드

@BeforeAll, @AfterAll, @BeforeEah, @AfterEach와 같은 메타 어노테이션이 붙여진 메소드를 말한다.

 

참고

- 테스트 메소드와 라이클 메소드는 abstract 선언하면 안되고, 어떠한 값도 리턴되선 안된다. 

- 접근제어자를 public으로 선언하지 않고 생략 가능하지만 private으로 선언하면 안된다.

 

 

Assertions

JUnit Jupiter에는 JUnit4로부터 온 assertion 메소드와 새롭게 자바 8 람다 표현식으로 추가된 메소드들이 있다. 모든 JUnit Jupiter assertion은 정적 메소드이며, org.junit.jupiter.api.Assertions 클래스 안에 있다.

class AssertionsTest {
	
    private final Calculator calculator = new Calculator();
    private final Person person = new Person("이병률", "김영하");
    
    @Test
    void standardAssertions() {
    	assertEquals(2, calculator.add(1, 1));
        assertEquals(4, calculator.multiply(2, 2),
        		"추가적인 실패 메세지는 마지막 파라미터에 넣는다.");
        assertTrue('a' < 'b', () -> "Assertion message는 지연로딩과 비슷하게 동작한다.");
    }
    
    @Test
    void groupedAssertions() {
    	assertAll("person",
        	() -> assertEquals("Jane", person.getFirstName()),
            () -> assertEquals("Doe", person.getLastName()));
    }
    
    @Test
    void exceptionTestng() {
    	Exception exception = assertThrows(ArithmeticException.class, () ->
        	calculator.divide(1, 0));
        assertEquals("/ by zero", exception.getMessage());
    }
    
    @Test
    void timeoutNotExceeded() {
    	assertTimeout(ofMinutes(2), () -> { // 2분 미만으로 실행되는 동작 실행 });
    }
}

 

 

Assumptions

JUnit Jupiter는 JUnit4에서 제공해주던 assumtion 메소드와 Java 8 람다 표현식과, 메소드 레퍼런스를 이용해 몇 개를 더 추가했다.

public class AssumtionTest {
	private final Calculator calculator;
    
    @Test
    void CI서버에서만_테스트() {
    	assumeTure("CI".equals(System.getenv("ENV"));
    }
    
    @Test
    void 개발환경에서만_테스트() {
    	assumeTrue("DEV".eqauls(System.getenv("ENV")),
        		() -> "...");
    }
}

- assumTrue : false일 때 이후 테스트 전체가 실행되지 않는다.

- assumingThat : 파라미터로 전달된 코드블럭만 실행되지 않는다.

 

 

 

참고

- JUnit5 완벽 가이드

- [10분 테크톡] 바다의 JUnit5 사용법