기본 annotation 테스트

package hello.test;

import org.junit.jupiter.api.*;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;

class StudyTest {

    @Test
     @DisplayName("학생 생성 테스트") //테스트 이름 정의
     void create() {
        Study  study = new Study();
        assertNotNull(study);
        System.out.println("create1");
        assertEquals(StudyStatus.NOTHING, study.getStatus(),"초기상태 WATING");
                                 //기대값                  //현재 상태
        assertEquals(StudyStatus.NOTHING, study.getStatus(), () -> "초기값은 NOTHING 이어야 합니다.");
         //lambda 식으로 변경(lambda로 변경하는 경우 해당 수행이 실패하는 경우에만 message연산을 수행
        
        assertAll(
                () -> assertNotNull(study),
                () -> assertEquals(StudyStatus.NOTHING, study.getStatus(), () -> "초기값은 NOTHING 이어야 합니다."),
                () -> assertTrue(study.getLimit() > 0, () -> "최대 참석인원은 0 명보다 커야합니다.")
        ); //람다식으로 3개의 assert문 실행결과 확인 가능 
    }

    @Test
    @Disabled  //전체 클래스 테스트 수행시 동작하지 않도록 정의
    void create2() {
         IllegalArgumentException exception =  assertThrows(IllegalArgumentException.class, ()-> new Study(-1));
        assertEquals("Limit은 0보다 커야함.",exception.getMessage());
        //해당 excpetion의 message가 기대하는 값과 같은지 확인
    }

    @Test
    @DisplayName("생성 timeout 확인")
    void create3() {
        assertTimeout(Duration.ofSeconds(1), () -> new Study());
        //1초안에 생성자 생성
        
        assertTimeout(Duration.ofMillis(100), () -> {
            new Study();
            Thread.sleep(30000);
        }); // 30000 millisecond 이후에 실패 처리

        assertTimeoutPreemptively(Duration.ofMillis(100), () -> {
            new Study();
            Thread.sleep(3000);
        }); // 100 millisecond가 지나면 바로 실패 처리
    }
    
     @Test
    void create4() {
        Study actual = new Study(10);
        assertThat(actual.getLimit()).isGreaterThan(0);  //3rd party assertjs
    }

    @BeforeAll  //테스트를 실행하기 전에 딱 1번 반드시 static 메소드로만 사용가능. 리턴타입 없음.
    static void BeforeAll() {
        System.out.println("BeforeALL");
    }

    @AfterAll  // 테스트를 실행한 이후 딱 1번만 수행(반드시 static 메소드로만 사용가능. 리턴타입 없음
    static void AfterAll() {  //모든 테스트가 실행된 이후에 1번만 실행
        System.out.println("AfterAll");
    }

    @BeforeEach //각 테스트 수행 전 1번 실행
    void BeforeEach() {
        System.out.println("BeforeEach");
    }

    @AfterEach // 각 테스트 수행 후 1번 실행
    void AfterEach() {
        System.out.println("AfterEach");
    }
}

 

condition에 따라서 테스트 실행

import org.junit.jupiter.api.*;

import java.time.Duration;
import java.util.function.Supplier;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assumptions.assumeTrue;


....

    @Test
    void conditionTest() {
        assumeTrue("LOCAL".equalsIgnoreCase(System.getenv("TEST_ENV")));
        //TEST_ENV라는 환경변수가 LOCAL인 경우에만 아래 테스트가 수행됨.
        Study study = new Study();
        assertNotNull(study);
    }
    
    @Test
    void conditionTest2() {
        String env = System.getenv("TEST_ENV");
        //TEST_ENV라는 환경변수가 LOCAL인 경우에만 아래 테스트가 수행됨.
        assumingThat(("LOCAL".equalsIgnoreCase(env)),()->{
            System.out.println("succeed to test");
        });
        //TEST_ENV라는 환경변수가 LOCAL가 아닌 경우에만 아래 테스트가 수행됨.
        assumingThat(!("LOCAL".equalsIgnoreCase(env)),()->{
            System.out.println("Failed to test");
        });

        Study study = new Study();
        assertNotNull(study);
    }
    
     @Test
    @EnabledOnOs(OS.WINDOWS)  //특정 OS에 특화된 테스트시 활용
    @EnabledOnJre(JRE.JAVA_11) //자바 11버전에서만 실행
    @EnabledIfEnvironmentVariable(named= "TEST_ENV", matches = "local") //환경변수 TEST_ENV가 local인 경우에만 실행
    void conditionTest3() {
        String env = System.getenv("TEST_ENV");
        //TEST_ENV라는 환경변수가 LOCAL인 경우에만 아래 테스트가 수행됨.
        assumingThat(("LOCAL".equalsIgnoreCase(env)),()->{
            System.out.println(env);
        });
        //TEST_ENV라는 환경변수가 LOCAL가 아닌 경우에만 아래 테스트가 수행됨.
        assumingThat(!("LOCAL".equalsIgnoreCase(env)),()->{
            System.out.println(env);
        });

        Study study = new Study();
        assertNotNull(study);
    }

 

 

커스텀 테그

package hello.test;

import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Test
@Tag("slow")
public @interface SlowTest {
}

...........




//실제 사용 Test
    @SlowTest
    void conditionTest() {
        String env = System.getenv("TEST_ENV");
        assumeTrue("LOCAL".equalsIgnoreCase(env));
        //TEST_ENV라는 환경변수가 LOCAL인 경우에만 아래 테스트가 수행됨.
        assumingThat(("LOCAL".equalsIgnoreCase(env)),()->{
            System.out.println("succeed to test");
        });
        assumingThat(!("LOCAL".equalsIgnoreCase(env)),()->{
            System.out.println("succeed to test");
        });

        Study study = new Study();
        assertNotNull(study);
    }

 

 

테스트 반복 실행

package hello.test;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.RepetitionInfo;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.aggregator.AggregateWith;
import org.junit.jupiter.params.aggregator.ArgumentsAccessor;
import org.junit.jupiter.params.aggregator.ArgumentsAggregationException;
import org.junit.jupiter.params.aggregator.ArgumentsAggregator;
import org.junit.jupiter.params.converter.ArgumentConversionException;
import org.junit.jupiter.params.converter.ConvertWith;
import org.junit.jupiter.params.converter.SimpleArgumentConverter;
import org.junit.jupiter.params.provider.*;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class OtherTest {
    @RepeatedTest(10)
    @DisplayName("반복 테스트1")
    public void test1() {
        System.out.println("repeat test");
    }

    @DisplayName("반복 테스트 2")
    @RepeatedTest(value = 10, name= "{displayName},{currentRepetition}/{totalRepetitions}")
    public void ParameterizedTest1(RepetitionInfo repetitionInfo) {
        System.out.println("count:"+ repetitionInfo.getCurrentRepetition() +"total:"
        + repetitionInfo.getTotalRepetitions());
    }

    @DisplayName("파라미터 출력")
    @ParameterizedTest(name = "{index} {displayName} message={0}")
    @ValueSource(strings = {"1","2","3","4"})
    @EmptySource
    @NullSource
    @NullAndEmptySource //empty와 null을 동시에 파라미터로 넘김
    void ParameterizedTest2(String str) {
        System.out.println(str);
    }

    @DisplayName("파라미터 출력1")
    @ParameterizedTest(name = "{index} {displayName} message={0}")
    @ValueSource(ints ={10, 20, 30})
    void ParameterizedTest3(@ConvertWith(ArgumentConvert.class) Study study) {
        System.out.println(study.getLimit());
    }

    @DisplayName("파라미터 출력2")
    @ParameterizedTest(name = "{index} {displayName} message={0}")
    @CsvSource({"10, '자바 테스트1'" ,"20, '파이썬 테스트1'"})
    void ParameterizedTest4(Integer limit, String name) {
        System.out.println(new Study(limit,name));
    }


    static class ArgumentConvert extends SimpleArgumentConverter { //1개의 argument에 사용
        @Override
        protected Object convert(Object source, Class<?> targetType) throws ArgumentConversionException {
            assertEquals(Study.class, targetType,"can only covert to Study" );
            return new Study(Integer.parseInt(source.toString()));
        }
    }

    @DisplayName("파라미터 출력3")
    @ParameterizedTest(name = "{index} {displayName} message={0}")
    @CsvSource({"30, '자바 테스트2'" ,"40, '파이썬 테스트2'"})
    void ParameterizedTest5(ArgumentsAccessor argumentsAccessor) {
        System.out.println(new Study(argumentsAccessor.getInteger(0),argumentsAccessor.getString(1)));
    }

    @DisplayName("파라미터 출력4")
    @ParameterizedTest(name = "{index} {displayName} message={0}")
    @CsvSource({"50, '자바 테스트3'", "60, '파이썬 테스트3'"})
    void ParameterizedTest6(@AggregateWith(Aggregator.class) Study study) {
        System.out.println(study.getLimit()+" "+ study.getName());
        System.out.println(study);
    }

     static class Aggregator implements ArgumentsAggregator {
        @Override
        public Object aggregateArguments(ArgumentsAccessor accessor, ParameterContext context) throws ArgumentsAggregationException {
            Study study = new Study(accessor.getInteger(0),accessor.getString(1));
            return study;
        }
    }
}

 

 

테스트 인스턴스

package hello.test;

import org.hibernate.resource.transaction.spi.DdlTransactionIsolator;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.RegisterExtension;

//@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
//@TestInstance(TestInstance.Lifecycle.PER_CLASS)  //테스트클래스의 테스트메소드간 인스턴스 공유
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)  //테스트 순서 지정
//@ExtendWith(TestExtension.class) // extension 을 선언적으로 등록하는 방법
public class InstanceTest {

    int value = 1;

    @RegisterExtension //extension 을 프로그래밍하여 등록하는 방법
    static TestExtension testExtension = new TestExtension(500L);

    @DisplayName("인스턴스 테스트")
    @Test
    @Order(2) //2번째로 실행
    void instance_Test1() {
        System.out.println("instance test1:" + value++);
    }

    @DisplayName("인스턴스 테스트")
    @Test
    @Order(1) //첫번째로 실행
    @Disabled
    void instance_Test2() {
        System.out.println("instance test2:" + value++);
    }

    @Test
    @Order(3) //세번째로 실행
    void instance_Test3() {
        System.out.println("instance test3:" + value);
    }

    @BeforeAll
    void beforeAll() {
        System.out.println("beforeAll");
    }

    @AfterAll
    void afterAll() {
        System.out.println("afterAll");
    }

    @Test
    void create_new() {
        try {
            Thread.sleep(1005L);
            System.out.println(this);
            System.out.println("test");
        } catch(Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

 

Extension 클래스

package hello.test;

import org.junit.jupiter.api.extension.AfterTestExecutionCallback;
import org.junit.jupiter.api.extension.BeforeTestExecutionCallback;
import org.junit.jupiter.api.extension.ExtensionContext;

import java.lang.reflect.Method;

public class TestExtension implements BeforeTestExecutionCallback, AfterTestExecutionCallback {

    private long THRESHOLD;

    public TestExtension(long THRESHOLD) {
        this.THRESHOLD = THRESHOLD;
    }

    @Override
    public void beforeTestExecution(ExtensionContext context) throws Exception {
        ExtensionContext.Store store = getStore(context);
        store.put("startTime", System.currentTimeMillis());
    }

    @Override
    public void afterTestExecution(ExtensionContext context) throws Exception {
        Method requiredTestMethod = context.getRequiredTestMethod();
        SlowTest annotation = requiredTestMethod.getAnnotation(SlowTest.class);
        String testMethodName = requiredTestMethod.getName();
        ExtensionContext.Store store = getStore(context);
        long start_time = store.remove("startTime", long.class);
        long duration = System.currentTimeMillis() - start_time;
        if (duration > THRESHOLD && annotation == null) {
            System.out.printf("please consider mark method [%s] with @SlowTest.\n", testMethodName);
        }
    }

    private ExtensionContext.Store getStore(ExtensionContext context) {
        String testClassName = context.getRequiredTestClass().getName();
        String testMethodName = context.getRequiredTestMethod().getName();
        ExtensionContext.Store store = context.getStore(ExtensionContext.Namespace.create(testClassName, testMethodName));
        return store;
    }
}

' > JUnit5' 카테고리의 다른 글

JUnit5  (0) 2022.02.27

JUnit5 란?

자바 개발자가 단위테스트 작성시 가장 많이 사용하는 테스트 프레임워크

https://junit.org/junit5/docs/current/user-guide/#overview-what-is-junit-5

 

JUnit 5 User Guide

Although the JUnit Jupiter programming model and extension model will not support JUnit 4 features such as Rules and Runners natively, it is not expected that source code maintainers will need to update all of their existing tests, test extensions, and cus

junit.org

JUnit5 구조

  • JUnit Platform
    • JVM에서 테스트 프레임워크를 시작하기 위한 기반 역할
  • Vintage
    • JUnit3, JUnit4 지원하기 위한 TestEngine
  • Jupiter
    • JUnit5를 제공

' > JUnit5' 카테고리의 다른 글

샘플 테스트  (0) 2022.02.27

+ Recent posts