ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [JUnit] JUnit5 기초지식 annotation 정리
    IT/JAVA | Spring 2023. 2. 25. 17:26

    Junit5의 요약된 기초지식에 대한 내용은 아래에서 확인 가능하다.

    2023.02.18 - [IT/JAVA | Spring] - [JUnit] JUnit5 기초지식 정리( 설정, annotation, assertions )

     

    [JUnit] JUnit5 기초지식 정리( 설정, annotation, assertions )

    java 개발자가 가장 많이 사용하는 테스트 프레임워크 JUnit에 대한 기초지식 많은 개발 방법론이 있지만 TDD의 핵심인 Test Code 작성을 위한 프레임워크 중 java 개발자들이 가장 많이 이용하는 프레

    kangyb.tistory.com

     

    Junit5 User guide에서 확인 가능한 annotation은 아래와 같이 있다.

     

    JUnit Jupiter는 테스트 구성 및 프레임워크 확장을 위해 다음 주석을 지원합니다.

    달리 명시되지 않는 한 모든 핵심 주석은 junit-jupiter-api 모듈 의 패키지에 있습니다.

    annotation 설명
    @Test
    메서드가 테스트 메서드임을 나타냅니다. JUnit 4의 @Test 주석과 달리 JUnit Jupiter의 테스트 확장은 자체 전용 주석을 기반으로 작동하므로 이 주석은 속성을 선언하지 않습니다. 이러한 메서드는 재정의하지 않는 한 상속됩니다.
    @ParameterizedTest
    메서드가 매개 변수가 있는 테스트임을 나타냅니다. 이러한 메서드는 재정의하지 않는 한 상속됩니다.
    @RepeatedTest
    메서드가 반복 테스트를 위한 테스트 템플릿임을 나타냅니다. 이러한 메서드는 재정의하지 않는 한 상속됩니다.
    @TestFactory
    메서드가 동적 테스트를 위한 테스트 팩터리임을 나타냅니다. 이러한 메서드는 재정의하지 않는 한 상속됩니다.
    @TestTemplate
    메서드는 등록된 공급자가 반환한 호출 컨텍스트 수에 따라 여러 번 호출되도록 설계된 테스트 사례의 템플릿임을 나타냅니다. 이러한 메서드는 재정의하지 않는 한 상속됩니다.
    @TestClassOrder
    주석이 달린 테스트 클래스의 @Nested 테스트 클래스에 대한 테스트 클래스 실행 순서를 구성하는 데 사용됩니다. 이러한 주석은 상속됩니다
    @TestMethodOrder
    주석이 달린 테스트 클래스에 대한 테스트 메서드 실행 순서를 구성하는 데 사용됩니다. JUnit 4의 @FixMethodOrder와 유사합니다. 이러한 주석은 상속됩니다.
    @TestInstance
    주석이 달린 테스트 클래스의 테스트 인스턴스 수명 주기를 구성하는 데 사용됩니다. 이러한 주석은 상속됩니다.
    @DisplayName
    테스트 클래스 또는 테스트 메서드에 대한 사용자 지정 표시 이름을 선언합니다. 이러한 주석은 상속되지 않습니다.
    @DisplayNameGeneration
    테스트 클래스에 대한 사용자 지정 표시 이름 생성기를 선언합니다. 이러한 주석은 상속됩니다.
    @BeforeEach
    주석이 달린 메서드는 현재 클래스의 각 @Test, @RepeatedTest, @ParameterizedTest 또는 @TestFactory 메서드 전에 실행되어야 함을 나타냅니다. JUnit 4의 @Before와 유사합니다. 이러한 메서드는 재정의되거나 대체되지 않는 한 상속됩니다(즉, Java의 가시성 규칙에 관계없이 서명에 따라 대체됨).
    @AfterEach
    주석이 달린 메서드는 현재 클래스의 각 @Test, @RepeatedTest, @ParameterizedTest 또는 @TestFactory 메서드 후에 실행되어야 함을 나타냅니다. JUnit 4의 @After와 유사합니다. 이러한 메서드는 재정의되거나 대체되지 않는 한 상속됩니다(즉, Java의 가시성 규칙에 관계없이 서명에 따라 대체됨).
    @BeforeAll
    현재 클래스의 모든 @Test, @RepeatedTest, @ParameterizedTest 및 @TestFactory 메서드보다 먼저 주석이 달린 메서드를 실행해야 함을 나타냅니다. JUnit 4의 @BeforeClass와 유사합니다. 이러한 메서드는 상속되거나, 숨겨지거나, 재정의되거나, 대체되지 않는 한(즉, Java의 가시성 규칙에 관계없이 서명만을 기반으로 대체됨) "클래스별" 테스트 인스턴스 수명 주기가 사용되지 않는 한 static이어야 합니다.
    @AfterAll
    주석이 달린 메서드는 현재 클래스의 모든 @Test, @RepeatedTest, @ParameterizedTest 및 @TestFactory 메서드 후에 실행되어야 함을 나타냅니다. JUnit 4의 @AfterClass와 유사합니다. 이러한 메서드는 상속되거나, 숨겨지거나, 재정의되거나, 대체되지 않는 한(즉, Java의 가시성 규칙에 관계없이 서명만을 기반으로 대체됨) "클래스별" 테스트 인스턴스 수명 주기가 사용되지 않는 한 static이어야 합니다.
    @Nested
    주석이 달린 클래스가 비정적 중첩 테스트 클래스임을 나타냅니다. Java 8에서 Java 15까지의 경우 "클래스별" 테스트 인스턴스 수명 주기를 사용하지 않는 한 @BeforeAll 및 @AfterAll 메서드를 @Nested 테스트 클래스에서 직접 사용할 수 없습니다. Java 16부터 @BeforeAll 및 @AfterAll 메서드는 테스트 인스턴스 수명 주기 모드 중 하나를 사용하여 @Nested 테스트 클래스에서 static으로 선언될 수 있습니다. 이러한 주석은 상속되지 않습니다.
    @Tag
    클래스 또는 메서드 수준에서 테스트 필터링을 위한 태그를 선언하는 데 사용됩니다. TestNG의 테스트 그룹 또는 JUnit 4의 범주와 유사합니다. 이러한 주석은 클래스 수준에서 상속되지만 메서드 수준에서는 상속되지 않습니다.
    @Disabled
    테스트 클래스 또는 테스트 메서드를 비활성화하는 데 사용됩니다. JUnit 4의 @Ignore와 유사합니다. 이러한 주석은 상속되지 않습니다.
    @Timeout
    실행이 지정된 기간을 초과하는 경우 테스트, 테스트 팩터리, 테스트 템플릿 또는 수명 주기 메서드를 실패하는 데 사용됩니다. 이러한 주석은 상속됩니다.
    @ExtendWith
    확장을 선언적으로 등록하는 데 사용됩니다. 이러한 주석은 상속됩니다
    @RegisterExtension
    필드를 통해 프로그래밍 방식으로 확장을 등록하는 데 사용됩니다. 이러한 필드는 가려지지 않는 한 상속됩니다.
    @TempDir
    수명 주기 메서드 또는 테스트 메서드에서 필드 주입 또는 매개 변수 주입을 통해 임시 디렉터리를 제공하는 데 사용됩니다. org.junit.jupiter.api.io 패키지에 있습니다.

     

    위 표 중 자주 사용되고 기본적인 내용을 정리한다.

     

    1. @Test

    @Test가 붙어있는 메서드가 테스트 메소드

    테스트 메서드는 private 또는 static이면 안된다.

    테스트 메소드는 반환값을 갖지 않는다.

    기본적으로 테스트 메서드들의 실행 순서는 대부분 위에서 아래로 실행되지만 그렇다고 순서가 보장되지 않는다. 

    테스트 메서드의 실행 순서를 보장하고 싶다면 별도의 @TestMethodOrder으로 순서를 정해주어야 한다.

    Junit 4와 다른 점은 메서드 앞에 접근제어자를 붙이지 않아도 된다. 

    @Test
    void testAnnotation() {
        assertEquals("test","test");
    }

     

    2. @DisplayName

    테스트 메서드의 이름 혹은 설명을 추가할 수 있다.

    해당 annotation이 없어도 실행되는데 문제는 없다.

    한글 사용이 가능하기에 영어를 써야 하는 게 아니라면 이해하기 쉬운 한글로 적어도 무방하다.

    해당 annotation이 없으면 테스트 메서드명을 출력한다.

    @DisplayName("출력되는 테스트 명을 입력한다.")
    @Test
    void testAnnotation() {
        assertEquals("test","test");
    }

    as-is

    to-be

     

    3. @DisplayNameGeneration

    테스트 클래스에 적용하여 테스트메서드들의 출력되는 이름을 일괄로 변경한다.

    @DisplayName이 있다면 @DisplayName이 우선권을 갖고 세팅된 이름을 출력한다.

     
    DisplayNameGenerator.* 를 구현하여 커스텀 클래스를 만들 수 있다.
    DisplayNameGenerator. 에서 사용할 수 있는 몇 가지 기본 항목
    DisplayNameGenerator.* 설명
    Standard JUnit Jupiter 5.0이 릴리스된 이후에 적용된 표준 표시 이름 생성 동작과 일치합니다.
    기존 클래스,메소드명을 사용합니다.
    Simple 매개 변수가 없는 메서드의 후행 괄호를 제거합니다.
    ReplaceUnderscores 밑줄을 공백으로 바꿉니다.
    IndicativeSentences 테스트명과 클래스 명을 연결하여 완전한 문장을 생성합니다.

    ReplaceUnderscores 사용 예제

    @Slf4j
    @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
    class JunitTest {
        @DisplayName("출력되는 테스트 명을 입력한다.")
        @Test
        void testAnnotation() {
            assertEquals("test","test");
        }
    
        @Test
        void test_under_scores() {
            assertEquals("test","test");
        }
        
        @DisplayName("출력되는_테스트_명을_입력한다.")
        @Test
        void test_display_name_under_scores() {
            assertEquals("test","test");
        }
    }

    위에서 설명했듯이

    우선권은 @DisplayName > @DisplayNameGeneration이기에 @DisplayName만 출력되는 경우가 있다.

     

    4. @BeforeEach, @AfterEach

    테스트 메서드가 실행되지 전, 실행된 후 반복적으로 호출된다.

    해당 annotation이 붙은 메서드에서 변수를 할당하는 경우 테스트 메서드가 동일한 값의 변수로 테스트 가능하다.

    @Slf4j
    @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
    class JunitTest {
    
        @BeforeEach
        void testBeforeEach() {
            log.info("BeforeEach");
        }
    
        @AfterEach
        void testAfterEach() {
            log.info("AfterEach");
        }
    
        @DisplayName("출력되는 테스트 명을 입력한다.")
        @Test
        void testAnnotation() {
            log.info("testAnnotation");
            assertEquals("test","test");
        }
    
        @Test
        void test_under_scores() {
            log.info("test_under_scores");
            assertEquals("test","test");
        }
    
        @DisplayName("출력되는_테스트_명을_입력한다.")
        @Test
        void test_display_name_under_scores() {
            log.info("test_display_name_under_scores");
            assertEquals("test","test");
        }
    }

     

    5. @BeforeAll, @AfterAll

    테스트 메소드가 실행되기 전, 테스트 메소드가 모두 실행된 후 실행되는 메서드에 붙인다.

    해당 클래스의 테스트가 실행되기 전 한번, 모두 실행된 후 한번 실행된다.

    클래스와 생성주기를 같이하며 static method로 선언한다.

    @Slf4j
    @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
    class JunitTest {
    
        @BeforeAll
        static void testBeforeAll() {
            log.info("BeforeAll");
        }
    
        @AfterAll
        static void testAfterAll() {
            log.info("AfterAll");
        }
    
        @DisplayName("출력되는 테스트 명을 입력한다.")
        @Test
        void testAnnotation() {
            log.info("testAnnotation");
            assertEquals("test","test");
        }
    
        @Test
        void test_under_scores() {
            log.info("test_under_scores");
            assertEquals("test","test");
        }
    
        @DisplayName("출력되는_테스트_명을_입력한다.")
        @Test
        void test_display_name_under_scores() {
            log.info("test_display_name_under_scores");
            assertEquals("test","test");
        }
    }

     

    6. @Disabled

    테스트 메서드를 실행하지 않는 상태로 만든다.

    @Slf4j
    @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
    class JunitTest {
    
        @BeforeAll
        static void testBeforeAll() {
            log.info("BeforeAll");
        }
    
        @AfterAll
        static void testAfterAll() {
            log.info("AfterAll");
        }
    
        @DisplayName("출력되는 테스트 명을 입력한다.")
        @Test
        void testAnnotation() {
            log.info("testAnnotation");
            assertEquals("test","test");
        }
    
        @Test
        @Disabled
        void test_under_scores() {
            log.info("test_under_scores");
            assertEquals("test","test");
        }
    
        @DisplayName("출력되는_테스트_명을_입력한다.")
        @Test
        void test_display_name_under_scores() {
            log.info("test_display_name_under_scores");
            assertEquals("test","test");
        }
    }

     

    7.  @TestMethodOrder

    테스트 클래스내 테스트 메서드의 실행 순서를 정의한다.

    실행순서를 정의하는 annotation은 2개가 있어 주의해서 사용해야 한다.

    이너클래스 실행순서를 정의하는 TestClassOrder와 클래스내 메서드의 순서를 정의하는 TestMethodOrder이다.

    jupiter.api.내에TestClassOrder와 TestMethodOrder가 같은 이름의 메서드로 순서를 정의하고있어 import를 잘해야한다.

    MethodOrderer.* 설명
    MethodOrderer.DisplayName
    표시 이름을 기준으로 영숫자순으로 테스트 메서드를 정렬합니다.
    MethodOrderer.MethodName 
    메서드이름과 공식 매개변수 목록을 기준으로 영숫자순으로 테스트 메서드를 정렬합니다.
    MethodOrderer.OrderAnnotation
    @Order 주석을 통해 지정된 값을 기준으로 테스트 메서드를 숫자로 정렬합니다.
    MethodOrderer.Random 테스트 방법을 의사 무작위로 주문하고 사용자 정의 시드 구성을 지원합니다.
    MethodOrderer.Alphanumeric
    이름과 공식 매개변수 목록을 기준으로 영숫자순으로 테스트 방법을 정렬합니다.
    더 이상 사용되지 않으며 MethodOrderer.MethodName 6.0에서 제거됩니다.

    MethodOrderer.OrderAnnotation 예제

    import static org.junit.jupiter.api.Assertions.*;
    
    import lombok.extern.slf4j.Slf4j;
    import org.junit.jupiter.api.AfterAll;
    import org.junit.jupiter.api.BeforeAll;
    import org.junit.jupiter.api.DisplayName;
    import org.junit.jupiter.api.DisplayNameGeneration;
    import org.junit.jupiter.api.DisplayNameGenerator;
    import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
    import org.junit.jupiter.api.Order;
    import org.junit.jupiter.api.Test;
    import org.junit.jupiter.api.TestMethodOrder;
    
    @Slf4j
    @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
    @TestMethodOrder(OrderAnnotation.class)
    class JunitTest {
        @DisplayName("출력되는 테스트 명을 입력한다.")
        @Order(1)
        @Test
        void testAnnotation() {
            log.info("testAnnotation");
            assertEquals("test","test");
        }
    
        @Order(3)
        @Test
        void test_under_scores() {
            log.info("test_under_scores");
            assertEquals("test","test");
        }
    
        @DisplayName("출력되는_테스트_명을_입력한다.")
        @Order(2)
        @Test
        void test_display_name_under_scores() {
            log.info("test_display_name_under_scores");
            assertEquals("test","test");
        }
    }

     

    8. @Timeout

    메서드, 클래스 등 실행시간에 제약을 두고 해당 제약시간을 초과하면 테스트를 실패처리한다.

    테스트 메서드 내 assertions을 모두 통과하여도 실패처리한다.

    기본은 초로 측정하지만 설정을 통해서 변경가능하다.

    설정
    42 @Timeout(42)
    42 ns @Timeout(value = 42, unit = NANOSECONDS)
    42 μs @Timeout(value = 42, unit = MICROSECONDS)
    42 ms @Timeout(value = 42, unit = MILLISECONDS)
    42 s @Timeout(value = 42, unit = SECONDS)
    42 m @Timeout(value = 42, unit = MINUTES)
    42 h @Timeout(value = 42, unit = HOURS)
    42 d @Timeout(value = 42, unit = DAYS)
    @Slf4j
    @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
    class JunitTest {
    
        @BeforeAll
        static void testBeforeAll() {
            log.info("BeforeAll");
        }
    
        @AfterAll
        static void testAfterAll() {
            log.info("AfterAll");
        }
    
        @DisplayName("출력되는 테스트 명을 입력한다.")
        @Timeout(1)
        @Test
        void testAnnotation() throws InterruptedException {
            log.info("testAnnotation");
            assertEquals("test","test");
            Thread.sleep(2000);
        }
    }

     

    9. @Tag

    2023.03.12 - [으어으어] - [JUnit] JUnit5 @Tag 를 이용한 필터링 및 그룹만들기

     

    [JUnit] JUnit5 @Tag 를 이용한 필터링 및 그룹만들기

    Junit5의 요약된 기초지식에 대한 내용은 아래에서 확인 가능하다. 2023.02.18 - [IT/JAVA | Spring] - [JUnit] JUnit5 기초지식 정리( 설정, annotation, assertions ) [JUnit] JUnit5 기초지식 정리( 설정, annotation, assertions

    kangyb.tistory.com

     

    10. @SpringBootTest

    2023.04.30 - [IT/JAVA | Spring] - [JUnit] spring boot 테스트하기 ( Migration from JUnit4 to JUnit5 )

     

    [JUnit] spring boot 테스트하기 ( Migration from JUnit4 to JUnit5 )

    Junit5의 요약된 기초지식에 대한 내용은 아래에서 확인 가능하다. 2023.02.18 - [IT/JAVA | Spring] - [JUnit] JUnit5 기초지식 정리( 설정, annotation, assertions ) [JUnit] JUnit5 기초지식 정리( 설정, annotation, assertions

    kangyb.tistory.com

     

    해당 블로그에서 설명하지 않았지만 자주 사용되는 annotation은 조금 더 자세한 설명과 이해가 필요하기에 다루지 않는다.

    좀 더 이해가 필요한 annotation은 별도의 블로그에서 설명하며 아래 링크를 달아두겠다.

     

     

     

    Reference

    https://junit.org/junit5/docs/current/user-guide/

    https://www.baeldung.com/junit-5

    https://junit.org/junit5/docs/current/user-guide/#writing-tests

    댓글

Designed by Tistory.