ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 1. JUnit5
    Test/더 자바, 테스트하는 다양한 방법 2022. 10. 27. 17:28

    JUnit5 기본 애노테이션

    @Test - test 메서드에 사용
    @BeforeAll - 모든 테스트가 실행하기 전에 딱 한번만 호출
    - static void로 작성
    @AfterAll - 모든 테스트가 실행된 후 딱 한번만 호출
    - static void로 작성
    @BeforeEach - 각각의 테스트 실행 전 실행
    @AfterEach - 각각의 테스트 실행 후 실행
    @Disabled - 테스트를 실행하고 싶지 않을 때 사용

     

    JUnit5 테스트 이름 표기

    @DisplaynameGeneration - Method와 Class 레퍼런스를 사용해서 테스트 이름을 표기하는 방법 설정
    - 기본 구현체로 ReplaceUnderscores 제공
    @DisplayName - 어떤 테스트인지 테스트 이름을 보다 쉽게 표현할 수 있는 방법을 제공하는 애노테이션
    - @DisplayNameGeneration 보다 우선순위가 높다.

     

    JUnit5 Assertion

    - org.junit.jupiter.api.Assertions.*

    assertEquals( expected, actual ) 실제 값이 기대한 값과 같은지 확인
    assertNotNull( actual ) 값이 null이 아닌지 확인
    assertTrue( boolean ) 다음 조건이 참(true)인지 확인
    assertAll( executables... ) 모든 확인 구문 확인
    assertThrows( expectedType, executable ) 예외 발생 확인
    assertTimeout( duration, executable ) 특정 시간 안에 실행이 완료되는지 확인

    - 마지막 매개변수(메시지)로 Supplier<String> 타입의 인스턴스를 람다 형태로 제공할 수 있다.

        ㆍ복잡한 메시지 생성해야하는 경우 사용하면 실패한 경우에만 해당 메시지를 만들 수 있다.

     

    JUnit5 조건에 따라 테스트 실행하기

    - org.junit.jupiter.api.Assumptions.*

        ㆍassumeTrue(조건)

    @Test
    @DisplayName("스터디 만들기")
    void create_new_study() {
        String test_env = System.getenv("TEST_ENV");
        System.out.println(test_env);
        assumeTrue("LOCAL".equalsIgnoreCase(test_env));    // 테스트 환경이 로컬일때만 다음 코드를 실행한다.
        Study study = new Study(-10);
        
        assumingThat("LOCAL".equalsIgnoreCase(test_env), () -> {
    
        }); // 조건에 따른 로직 수행
    }

        ㆍassumingThat(조건, 테스트)

    - @Enableed___ 와 @Disabled__

        ㆍOnOS

        ㆍOnJre

        ㆍIfSystemProperty

        ㆍIfEnvironmentVariable

        ㆍIf

    @EnabledOnOs({OS.MAC,OS.LINUX})
    
    @DisabledOnOs(OS.MAC)
    
    @EnabledOnJre({JRE.JAVA_8,JRE.JAVA_11})
    
    @EnabledIfEnvironmentVariable(named = "TEST_ENV", matches = "LOCAL")

     

    JUnit5 태깅과 필터링

    - 테스트 그룹을 만들고 원하는 테스트 그룹만 테스트를 실행할 수 있는 기능

    - @Tag

        ㆍ테스트 메소드에 태그를 추가할 수 있다

        ㆍ하나의 테스트 메소드에 여러 태그를 사용할 수 있다.

        ㆍtest kind - Tags 설정 / Tag expression - 태그 이름 설정

    <profiles>
        <profile>
            <id>default</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <build>
                <plugins>
                    <plugin>
                    	<artifactId>maven-surefilre-plugin</artifactId>
                        <configuration>
                        	<groups>fast</groups>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </profile>
        <profile>
            <id>ci</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <build>
                <plugins>
                    <plugin>
                    	<artifactId>maven-surefilre-plugin</artifactId>
                        <configuration>
                        	<groups>fast | slow</groups>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>

        ㆍmaven설정으로 @Tag("fast")인 것만 빌드 시 실행

     

    JUnit5 커스텀 태그

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME) // 이 애노테이션의 전략은 런타임
    @Test
    @Tag("fast")
    public @interface FastTest {
    }
    
    // -------------------------------
    
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @Test
    @Tag("slow")
    public @interface FastTest {
    }

     

    JUnit5 테스트 반복하기

    - @RepeatedTest

        ㆍ반복 횟수와 반복 테스트 이름을 설정할 수 있다

            º {displayName}

            º {currentRepetition}

            º {totalRepetitions}

        ㆍRepetitionInfo 타입의 인자를 받을 수 있다

    @DisplayName("스터디 만들기")
    @RepeatedTest(value = 10, name = "{displayName}, {currentRepetition}/{totalRepetitions}")
    void repeatTest(RepetitionInfo repetitionInfo) {
        System.out.println("test" + repetitionInfo.getCurrentRepetition() + "/" +
                repetitionInfo.getTotalRepetitions());
    }

    - @ParameterizedTest

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

            º {displayName}

            º {index}

            º {argument}

            º {0}, {1}, ...

    @DisplayName("스터디 만들기")
    @ParameterizedTest(name = "{index} {displayName} message={0}")
    @ValueSource(strings = {"날씨가", "많이", "추워지고", "있네요."})
    void parameterizedTest(String message){
        System.out.println(message);
    }

     

        ㆍ인자 값들의 소스

            º @ValueSource

            º @NullSource - null 인자 추가, @EmptySource - 비어있는 인자 추가, @NullAndEmptySource - 앞선 두개

            º @EnumSource

            º @MethodSource

            º @CvsSource

            º @CvsFileSource

            º @ArgumentSource 

        ㆍ인자 값 타입 변환

            º 암묵적인 타입 변환

    @DisplayName("스터디 만들기")
    @ParameterizedTest(name = "{index} {displayName} message={0}")
    @ValueSource(ints = {10,20,40})
    void parameterizedTest(Study study){
        System.out.println(study);
    }

            º 명시적인 타입 변환

                - SimpleArgumentConverter 상속 받은 구현체 제공

                - @ConvertWith

    @DisplayName("스터디 만들기")
    @ParameterizedTest(name = "{index} {displayName} message={0}")
    @ValueSource(ints = {10,20,40})
    void parameterizedTest(@ConvertWith(StudyConverter.class) Study study){
        System.out.println(study);
    }
    
    static class StudyConverter extends SimpleArgumentConverter {
    
        @Override
        protected Object convert(Object source, Class<?> targetType) throws ArgumentConversionException {
            assertEquals(Study.class, targetType, "Can only convert to Study");
            return new Study(Integer.parseInt(source.toString()));
        }
    }

        ㆍ인자 값 조합

            º ArgumentsAccessor

            º 커스텀 Accessor

                - ArgumentsAggregator 인터페이스 구현

                - @AggregateWith

    // 방법1
    @DisplayName("스터디 만들기")
    @ParameterizedTest(name = "{index} {displayName} message={0}")
    @CsvSource({"10, '자바 스터디'","20, '스프링'"})
    void parameterizedTest2(Integer limit, String name){
        Study study = new Study(limit, name);
        System.out.println(study);
    }
    
    // 방법2
    @DisplayName("스터디 만들기")
    @ParameterizedTest(name = "{index} {displayName} message={0}")
    @CsvSource({"10, '자바 스터디'","20, '스프링'"})
    void parameterizedTest2(ArgumentsAccessor argumentsAccessor){
        Study study = new Study(argumentsAccessor.getInteger(0),argumentsAccessor.getString(1));
        System.out.println(study);
    }
    
    // 방법3
    @DisplayName("스터디 만들기")
    @ParameterizedTest(name = "{index} {displayName} message={0}")
    @CsvSource({"10, '자바 스터디'","20, '스프링'"})
    void parameterizedTest2(@AggregateWith(StudyAggregator.class) Study study){
        System.out.println(study);
    }
    
    static class StudyAggregator implements ArgumentsAggregator {
        @Override
        public Object aggregateArguments(ArgumentsAccessor accessor, ParameterContext context) throws ArgumentsAggregationException {
            return new Study(accessor.getInteger(0),accessor.getString(1));
        }
    }

     

    JUnit5 테스트 인스턴스

    - JUnit은 테스트 메소드마다 테스트 인스턴스를 새로 만든다

        ㆍ이것이 기본 전략

        ㆍ테스트 메소드를 독립적으로 실행하여 예상치 못한 부작용을 방지하기 위함

        ㆍ이 전략을 JUnit 5에서 변경할 수 있다

    - @TestInstance(Lifecycle.PER_CLASS)

        ㆍ테스트 클래스당 인스턴스를 하나만 만들어 사용한다.

        ㆍ경우에 따라, 테스트 간에 공유하는 모든 상태를 @BeforeEach 또는 @AfterEach에서 초기화할 필요가 있다

        ㆍ@BeforeAll과 @AfterAll을 인스턴스 메소드 또는 인터페이스에 정의한 default 메소드로 정의할 수도 있다.

    @TestInstance(TestInstance.Lifecycle.PER_CLASS)
    class StudyTest {
        ...
    }

     

    JUnit5 테스트 순서

    - 실행할 테스트 메소드 특정한 순서에 의해 실행되지만 어떻게 그 순서를 정하는지는 의도적으로 분명히 하지 않는다.

      ( 테스트 인스턴스를 테스트마다 새로 만드는 것과 같은 이유 )

    - 경우에 따라, 특정 순서대로 테스트를 실행하고 싶을 때도 있다. 그 경우에는 테스트 메소드를 원하는 순서에 따라 실행하도록 @TestInstance(Lifycycle.PER_CLASS)와 함께 @TestMethodOrder를 사용할 수 있다

        ㆍMethodOrderer 구현체를 설정한다

        ㆍ기본 구현체

            º Alphanumeric

            º OrderAnnoation

            º Random

    @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
    class StudyTest {
    
        @Order(2)
        void test() {...}
        
        @Order(1)
        void test1() {...}
        
        ...
    }

     

    JUnit5 : junit-platform.properties

    - JUnit 설정 파일로, 클래스패스 루트(src/test/resources/)에 넣어두면 적용된다

    - 테스트 인스턴스 라이프사이클 설정

        ㆍjunit.jupiter.testinstance.lifecycle.default = per_class

    - 확장팩 자동 감지 기능

        ㆍjunit.jupiter.extensions.autodetection.enabled = true

    - @Disabled 무시하고 실행하기

        ㆍjunit.jupiter.conditions.deactivate = org.junit.*DisabledCondition

    - 테스트 이름 표기 전략 설정

        ㆍjunit.jupiter.displayname.generator.default = org.junit.jupiter.api.DisplayName.Generator$ReplaceUnderscores

     

    JUnit5 : 확장 모델

    - JUnit4의 확장 모델은 @RunWith(Runner), TestRule, MethodRule

    - JUnit5의 확장 모델은 단 하나, Extension

     

    - 확장팩 등록 방법

        ㆍ선언적인 등록 @ExtendWith

    @ExtendWith(FindSlowTestExtension.class)

        ㆍ프로그래밍 등록 @RegisterExtension

    class StudyTest {
    
        @RegisterExtension
        static FindSlowTestExtension findSlowTestExtension = new FindSlowTestExtension(1000L);
    
        ...
        
    }

        ㆍ자동 등록 자바 ServiceLoader 이용

    - 확장팩 만드는 방법

        ㆍ테스트 실행 조건

        ㆍ테스트 인스턴스 팩토리

        ㆍ테스트 인스턴스 후-처리기

        ㆍ테스트 매개변수 리졸버

        ㆍ테스트 라이플사이클 콜백

        ㆍ예외 처리

     

    JUnit5 : 마이그레이션

    - junit-vintage-engine을 의존성으로 추가하면, JUnit 5의 junit-platform으로 Junit 3과 4로 작성된 테스트를 실행할 수 있다

        ㆍ@Rule은 기본적으로 지원하지 않지만, junit-jupiter-migrationsupport 모듈이 제공하는

           @EnableRuleMigrationSupport를 사용하면 다음 타입의 Rule을 지원한다

                 º ExternalResource

                 º Verifier

                 º ExpectedException

    JUnit 4 JUnit 5
    @Category(Class) @Tag(String)
    @RunWith, @Rule, @ClassRule @ExtendWith, @RegisterExtension
    @Ignore @Disabled
    @Before, @After, @BeforeClass, @AfterClass @BeforeEach, @AfterEach, @BeforeAll, @AfterAll

     

     

     

    'Test > 더 자바, 테스트하는 다양한 방법' 카테고리의 다른 글

    2. Mockito  (0) 2022.11.11

    댓글

Designed by Tistory.