[JUnit 5] JUnit 5을 배워보자

조유정·2024년 1월 31일

1. JUnit 5이란?

JetBrains에서 조사한 바(2023년 기준)로는 자바 개발자의 84%가 JUnit을 사용하며, 그 중 46›%는 Mockito를 사용한다고 한다.

자바 개발자가 가장 많이 사용하는 테스팅 프레임워크이다.

JUnit5는 JDK8 이상부터 지원을 한다.

SpringBoot 2.2.0 버전부터 기본으로 제공해주는 JUnit 버전을 5로 올리면서, JUnit 5에 대한 공부가 필수적이지 않아졌나!

JUnit 5은 다음과 같이 세부 모듈로 나누어져 있다.

  • JUnit Platform: 테스트를 실행해주는 런처를 제공해준다. TestEngine API를 지원해준다.
    • IDE에서 테스트 코드를 작성하고 실행해볼 수 있는 이유가 JUnit Platform을 지원해주고 있기 때문이다.
  • Jupiter: TestEngine API의 구현체로, JUnit 5를 지원해준다.
  • Vintage: TestEngine API의 구현체로, JUnit 3, 4를 지원해준다.

2. JUnit 5: 시작하기

SprinBoot 2.2.0 버전 이상을 사용한다면?

SpringBoot 2.2.0 버전부터 spring-boot-starter-test가 JUnit 5를 기본적으로 제공해준다.
즉, SpringBoot 2.2.0 프로젝트를 사용한다면 자동으로 JUnit5 의존성이 추가되어 바로 사용가능하다.

SpringBoot 2.2.0 버전을 사용하지 않는다면?

https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api

maven에서 원하는 JUnit5 버전을 선택 후, 자신의 빌드 도구에 맞춰 사용!

기본적인 어노테이션 익히기

  • @Test : 해당 메소드가 테스트 메소드임을 나타내며, 해당 메소드가 실행되면서 자동으로 단위 테스트가 수행된다.
  • @BeforeAll / @AfterAll : 모든 테스트가 실행되기 이전/이후에 딱 한번 호출된다.
    • JUnit5에서는 테스트 클래스의 life cycle이 기본적으로 PER_METHOD로 설정되어 있기 때문에, 테스트 내부의 테스트 메소드들이 실행될 때마다 테스트 클래스가 새로 생성되고 삭제된다. 때문에 static으로 선언되지 않는 한 테스트 메소드들이 공유하는 클래스 내부 요소들을 관리할 수는 없다.
    • 기본적으로 static으로 설정해주어야 한다.
    • 그러나, @TestInstance(TestInstance.LifeCycle.PER_CLASS)를 붙여 테스트 클래스의 생명주기를 클래스 단위로 바꿔주면 static을 사용하지 않아도 된다!
  • @BeforeEach / @AfterEach : 각 테스트가 실행되기 이전/이후에 딱 한번 호출된다.
  • @Disabled : 특정 메소드를 실행하고 싶지 않을 때 사용한다.
class StudyTest {

  @Test
  void create1() {
    Study study = new Study();
    assertNotNull(study);
    System.out.println("first create");
  }

  @Test
  void create2() {
    System.out.println("second create");
  }

  @Test
  @Disabled
  void create3() {
    System.out.println("third create");
  }

  // 모든 테스트를 실행하기 이전에 딱 한번만 호출된다.
  @BeforeAll
  static void beforeAll() {
    System.out.println("Before All");
  }

  // 모든 테스트를 실행한 이후에 딱 한번만 호출된다.
  @AfterAll
  static void afterAll() {
    System.out.println("After All");
  }

  // 각 테스트를 실행하기 이전에 한번 호출된다.
  @BeforeEach
  void beforeEach() {
    System.out.println("Before Each");
  }

  // 각 테스트를 실행한 이후에 딱 한번 호출된다.
  @AfterEach
  void afterEach() {
    System.out.println("After Each");
  }
}  

3. JUnit 5: 테스트 이름 표시하기

기본적으로는 메소드 이름으로 테스트 이름이 출력된다.
원하는 문자열로 테스트 이름을 보여주기 위한 방법은 다음과 같다.

@DisplayNameGeneration

  • 메소드와 클래스 레퍼런스를 사용해서 테스트 이름을 표기하는 어노테이션이다.
  • 기본 구현체로 ReplaceUnderscores을 제공한다.
    • Method 이름의 언더바(_)를 공백으로 치환해주는 설정이다.

@DisplayName (권장)

  • 어떤 테스트인지 테스트 이름을 보다 쉽게 표현할 수 있는 방법을 제공하는 어노테이션이다.
  • @DisplayNameGeneration 보다 우선 순위가 높다.

참고: https://junit.org/junit5/docs/current/user-guide/#writing-tests-display-names

4. JUnit 5: Assertion

org.junit.jupiter.api.Assertions.*

assertEquals(expected, actual)

  • 실제 값과 기대한 값이 같은지 확인한다.
  • 메소드를 사용할 때 expected, actual 위치 바뀌여도 상관은 없다.
  • message는 선택인데, 메세지를 설정해두면 나중에 어떤 오류인지 쉽게 파악이 가능하다.

assertNotNull(actual)

  • 값이 null이 아닌지 확인한다.

assertTrue(boolean)

  • 다음 조건이 참(true)인지 확인한다.

assertAll(executables...)

  • 모든 확인 구문 확인한다.
  • 하나의 assert문에서 테스트가 실패되면, 뒤에 있는 assert문은 실행되지 않는다. 따라서, 뒤에 있는 assert문에서 테스트가 성공하였는지 실패하였는지 알 수 없다.
  • assertAll()을 사용하여 한 번에 묶어주면, 모든 assert문에 대해 테스트가 성공하였는지 실패하였는지 알려준다.
assertAll(
        () -> assertNotNull(study),
        () -> assertEquals(StudyStatus.DRAFT, study.getStatus(),
            () -> "스터디를 처음 만들면 상태값이 " + StudyStatus.DRAFT + " 상태여야 한다."),
        () -> assertTrue(study.getLimit() > 0, "스터디 최대 참석 가능 인원은 0보다 커야 한다.")
    );

assertThrows(expectedType, executable)

  • 예외 발생 확인한다.
class Study {
	...
	public Study(int limit) {
    if (limit < 0) {
      throw new IllegalArgumentException("limit은 0보다 커야 한다.");
    }
    this.limit = limit;
  }
	...
}
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> new Study(-10));
assertEquals("limit은 0보다 커야 한다.", exception.getMessage());

assertTimeout(duration, executable)

  • 특정 시간 안에 실행이 완료되는지 확인한다.
  • 실행을 완료한 뒤 확인한다.
assertTimeout(Duration.ofMillis(100), () -> {
      new Study(10);
      Thread.sleep(300);
});

assertTimeoutPreemptively(duration, executable)

  • 특정 시간 안에 실행이 완료되는지 확인한다.
  • 실행을 완료하기 전에 확인하고 종료된다.
  • Thread를 사용하는 경우라면, 예상치못한 경우가 발생할 수 있기 때문에 사용하지 않도록 한다.
assertTimeoutPreemptively(Duration.ofMillis(100), () -> {
      new Study(10);
      Thread.sleep(300);
});

예외 정보 나타내기

각 Assertion 메소드를 사용할 때, 마지막 매개변수로 문자열이나 Supplier 타입의 인스턴스를 람다 형태로 정보를 제공할 수 있다.

[문자열]

assertEquals(StudyStatus.DRAFT, study.getStatus(), "스터디를 처음 만들면 상태값이 " + StudyStatus.DRAFT + " 상태여야 한다.");

[Supplier 타입의 인스턴스]

assertEquals(StudyStatus.DRAFT, study.getStatus(), new Supplier<String>() {
      @Override
      public String get() {
        return "스터디를 처음 만들면 상태값이 " + StudyStatus.DRAFT + " 상태여야 한다.");
      }
});

[Supplier 타입의 인스턴스(람다식)]

assertEquals(StudyStatus.DRAFT, study.getStatus(), () ->"스터디를 처음 만들면 상태값이 " + StudyStatus.DRAFT + " 상태여야 한다.");

💁🏻‍♀️ "편하게 문자열을 사용하면 되는데, 왜 굳이 인스턴스를 생성하나?"

문자열을 그대로 사용한다면, 해당 테스트가 성공하든 실패하든 문자열 연산이 무조건 실행된다.
그러나 인스턴스를 생성하는 방식은, 해당 테스트가 실패하였을 경우에만 문자열 연산이 실행되기 때문에 연산 횟수를 줄일 수 있다.
따라서, 인스턴스를 람다 형태로 작성하는 것을 권장한다.
추가적으로 AssertJ, Hemcrest, Truth 등의 라이브러리를 사용할 수도 있다.

5. JUnit 5: 조건에 따라 테스트 실행하기

특정한 조건을 만족하는 경우에 테스트를 실행하는 방법은 다음과 같다.

org.junit.jupiter.api.Assumptions.*

assumeTrue(조건)

  • 특정 조건일 때 테스트 코드를 실행한다.
// 환경변수가 LOCAL인지 확인한다.
String test_env = System.getenv("TEST_ENV");
System.out.println(test_env);
assumeTrue("LOCAL".equalsIgnoreCase(test_env));

// 그렇다면 실행된다.
Study actual = new Study(10);
assertThat(actual.getLimit()).isGreaterThan(0);

assumingThat(조건, 테스트)

  • 특정 조건일 때, 주어진 테스트 코드를 실행한다.
// 환경변수가 LOCAL인지 확인하고, 그렇다면 실행된다.
String test_env = System.getenv("TEST_ENV");
assumingThat("LOCAL".equalsIgnoreCase(test_env), () -> {
	System.out.println(test_env);
	Study actual = new Study(10);
	assertThat(actual.getLimit()).isGreaterThan(0);
});

@Enabled___@Disabled___

  • OnOS : 운영체제
     	@Test
      @DisplayName("스터디 만들기 ~~")
      @EnabledOnOs({OS.MAC, OS.LINUX}) // 맥, 리눅스 운영체제에서만 실행 O
      void create1() {
        System.out.println("fisrt create");
      }
    
      @Test
      @DisplayName("스터디 만들기 !!")
      @DisabledOnOs(OS.MAC) // 맥 운영체제에서는 실행 X
      void create2() {
        System.out.println("second create");
      }
  • OnJre : JRE 자바 버전
     	@Test
      @DisplayName("스터디 만들기 ~~")
      @EnabledOnJRE({JRE.JAVA_11, JRE.JAVA_8}) // JAVA11, JAVA8에서만 실행 O
      void create1() {
        System.out.println("fisrt create");
      }
  • IfSystemProperty
  • IfEnvironmentVariable : 환경 변수
     	@Test
      @DisplayName("스터디 만들기 ~~")
      @EnabledIfEnvironmentVariable(named = "TEST_ENV", matches = "LOCAL") // 환경변수가 일치하면 실행 O
      void create1() {
        System.out.println("fisrt create");
      }
  • If

6. JUnit 5: 태깅과 필터링

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

@Tag

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

IntelliJ에서 특정 태그로 테스트 필터링 하는 방법

  1. @Tag 어노테이션을 붙이고 실행해도, 모든 테스트가 실행되고 있다. 내가 실행시키고 싶은 태그를 추가적으로 지정해주어야 한다.

  1. 상단 네모박스 클릭 후 Edit Configurations

  1. JUnit > Build and run에서 Tags를 선택하고 fast로 지정해준다.

  1. 실행해주면 fast 태그를 붙이고 있는 테스트만 실행되는 것을 확인할 수 있다.

Gradle에서 테스트 필터링 하는 방법

test {
    useuseJUnit()
    includeGroups 'fast', 'slow'
}

참고

7. JUnit 5: 커스텀 태그

JUnit 5 애노테이션을 조합하여 커스텀 태그를 만들 수 있다.

커스텀 태그 생성하기

@Target(ElementType.METHOD) // 메소드에서 사용 가능
@Retention(RetentionPolicy.RUNTIME) // 런타임동안에는 해당 어노테이션을 유지
@Test // 테스트 기능
@Tag("fast") // 태그는 fast
public @interface FastTest {

}

@Retention(RetentionPolicy.RUNTIME) : 테스트가 실행하는 시점에도 해당 애노테이션을 참조할 수 있어야 하기 때문에, 런타임 시점에도 남아있어야 한다.

커스텀 태그 활용하기

@FastTest // 커스텀 어노테이션을 사용
@DisplayName("스터디 만들기 fast")
void create1() {
	Study actual = new Study(10);
  assertThat(actual.getLimit()).isGreaterThan(0);
}

8. JUnit 5: 테스트 반복하기 (1)

랜덤값을 사용하거나, 테스트를 실행하는 타이밍에 따라 달라지는 조건이 있다면 테스트를 반복하여 실행하는 도움이 될 수 있다.

@RepeatedTest

  • 반복 횟수와 반복 테스트 이름을 설정할 수 있다.
    • {displayName} : 테스트 이름
    • {currentRepetition} : 현재 반복 횟수
    • {totalRepetitions} : 총 반복 횟수
  • RepetitionInfo 타입의 인자를 받을 수 있다.
@DisplayName("스터디 만들기")
@RepeatedTest(value = 10, name = "{displayName}, {currentRepetition}/{totalRepetitions}")
void repeatTest(RepetitionInfo repetitionInfo) { // RepetitionInfo 인자를 받아 정보 출력이 가능
  System.out.println("test" + repetitionInfo.getCurrentRepetition() + "/"
      + repetitionInfo.getTotalRepetitions());
}

@ParameterizedTest

  • 테스트에 여러 다른 매개변수를 대입해가며 반복 실행한다.
    • {displayName} : 테스트 이름
    • {index} : 현재 사용한 인자의 인덱스
    • {arguments} : 현재 사용한 인자의 값
    • {0}, {1}, ... : 해당 인덱스의 인자 값
@DisplayName("스터디 만들기")
@ParameterizedTest(name = "{index} {displayName} message={0}")
@ValueSource(strings = {"날씨가", "많이", "추워지고", "있네요"})
void parameterizedTest(String message) {
  System.out.println(message);
}

9. JUnit 5: 테스트 반복하기 (2)

인자 값들의 소스

  • @ValueSource
    • 단일 값 또는 문자열 리터럴의 배열을 제공한다.

    • 정수, 문자열 등의 값을 테스트 메서드에 전달할 때 사용한다.

      @ParameterizedTest
      @ValueSource(ints = {1, 2, 3})
      void testWithValueSource(int value) {
          // 테스트 로직
      }
  • @NullSource, @EmptySource, @NullAndEmptySource
    • null, 빈 문자열, null과 빈 문자열을 테스트 메서드에 전달할 때 사용한다.

      @ParameterizedTest
      @NullAndEmptySource
      void testWithNullAndEmpty(String input) {
          // 테스트 로직
      }
  • @EnumSource
    • Enum 상수를 테스트 메서드에 전달할 때 사용한다.

      @ParameterizedTest
      @EnumSource(value = DayOfWeek.class, names = {"MONDAY", "WEDNESDAY", "FRIDAY"})
      void testWithEnum(DayOfWeek day) {
          // 테스트 로직
      }
  • @MethodSource
    • 다른 메소드에서 제공되는 값을 테스트 메서드에 전달할 때 사용한다.

      @ParameterizedTest
      @MethodSource("provideStrings")
      void testWithMethodSource(String input) {
          // 테스트 로직
      }
      
      static Stream<String> provideStrings() {
          return Stream.of("apple", "banana", "orange");
      }
  • @CsvSource
    • CSV 형식의 문자열을 파싱하여 값을 테스트 메서드에 전달할 때 사용한다.

      @ParameterizedTest
      @CsvSource({"apple, 1", "banana, 2", "orange, 3"})
      void testWithCsvSource(String fruit, int count) {
          // 테스트 로직
      }
  • @CvsFileSource
    • CSV 파일에서 값을 읽어와 테스트 메서드에 전달할 때 사용한다.

      @ParameterizedTest
      @CsvFileSource(resources = "/data.csv")
      void testWithCsvFile(String fruit, int count) {
          // 테스트 로직
      }
  • @ArgumentSource
    • 사용자 지정 인수 소스에서 값을 가져와 테스트 메서드에 전달한다.

    • 사용자 정의 소스는 ArgumentSource 인터페이스를 구현해야 한다.

      @ParameterizedTest
      @ArgumentSource(MyArgumentsProvider.class)
      void testWithCustomArgumentSource(String argument) {
          // 테스트 로직
      }

인자 값 타입 변환

  • 암묵적인 타입 변환
  • 명시적인 타입 변환 : 단일 일자
    • SimpleArgumentConverter 상속 받은 구현체 제공

    • @ConvertWith

      @DisplayName("스터디 만들기")
      @ParameterizedTest(name = "{index} {displayName} message={0}")
      @ValueSource(ints = {10, 20, 40})
      void parameterizedTest(@ConvertWith(StudyConvertor.class) Study study) {
        System.out.println(study.getLimit());
      }
      
      // 커스텀 클래스의 하나의 인자를 테스트 메소드가 전달받을 수 있도록 Convertor 작성
      static class StudyConvertor 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

      DisplayName("스터디 만들기")
      @ParameterizedTest(name = "{index} {displayName} message={0}")
      @CsvSource({"10, '자바 스터디'", "20, '스프링'"})
      void parameterizedTest(@AggregateWith(StudyAggregator.class) Study study) {
        System.out.println(study);
      }
      
      // 커스텀 클래스의 여러 개의 인자를 테스트 메소드가 전달받을 수 있도록 Convertor 작성
      static class StudyAggregator implements ArgumentsAggregator {
      
        @Override
        public Object aggregateArguments(ArgumentsAccessor accessor, ParameterContext context)
            throws ArgumentsAggregationException {
          return new Study(accessor.getInteger(0), accessor.getString(1));
        }
      }

참고

10. JUnit 5: 테스트 인스턴스

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

  • 이것이 기본 전략!
  • 테스트 메소드를 독립적으로 실행하여 예상치 못한 부작용을 방지하기 위함이다.
  • 이 전략을 JUnit 5에서 변경할 수 있다.
class StudyTest {
  int value = 1;

  @FastTest
  @DisplayName("스터디 만들기 fast")
  void create1() {
		System.out.println(this); // 이 테스트 메소드를 실행할 때, 인스턴스를 새로 생성
    System.out.println(value++); // 그래서 그냥 1이 찍힘
    Study actual = new Study(10);
    assertThat(actual.getLimit()).isGreaterThan(0);
  }

  @SlowTest
  @DisplayName("스터디 만들기 slow")
  void create2() {
		System.out.println(this); // 이 테스트 메소드를 실행할 때, 인스턴스를 새로 생성
    System.out.println(value++); // 여기도 그냥 1이 찍힘
    System.out.println("second create");
  }
}

@TestInstance(Lifecycle.PER_CLASS)

  • 테스트 클래스당 인스턴스를 하나만 만들어 사용한다!
  • @BeforeEach/@AfterEach를 static으로 설정하지 않아도 된다! default 메소드로 정의할 수도 있다.
    • 경우에 따라, 테스트 간에 공유하는 모든 상태를 @BeforeEach/@AfterEach에서 초기화 할 필요가 있다.

11. JUnit 5: 테스트 순서

실행되는 테스트 메소드는 특정한 순서에 의해 실행되기는 하지만, 그 순서를 어떻게 정하는지는 분명하지 않다.
테스트 메소드마다 테스트 인스턴스를 새로 만드는 것처럼, 유닛 테스트 간의 의존성을 없애기 위해서이다.
그러나! 경우에 따라, 특정 순서대로 테스트를 실행해야하는 경우가 있다.
예를 들어, 회원가입 후 로그인을 하는 비즈니스 로직을 작성하는 경우라면 순서에 따라 테스트 메소드가 실행되어야 한다.
이러한 경우에는 테스트 메소드를 원하는 순서에 따라 실행하도록 @TestInstance(Lifecycle.PER_CLASS)와 함께 @TestMethodOrder를 사용할 수 있다.

  • MethodOrderer 구현체를 설정한다.
  • 기본 구현체
    • Alphanumeric
    • OrderAnnoation
    • Random
@TestInstance(Lifecycle.PER_CLASS)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class StudyTest {

  int value = 1;

  @Order(2)
  @FastTest
  @DisplayName("스터디 만들기 fast")
  void create1() {
		System.out.println(this);
    System.out.println(value++);
	}

	@Order(1)
  @FastTest
  @DisplayName("스터디 만들기 fast")
  void create1() {
		System.out.println(this);
    System.out.println(value++);
	}
}

[실행 결과]

  • 테스트 인스턴스의 해쉬값이 @6156496으로 동일하다.
  • 순서도 지정한대로 실행되었다.
  • value값도 순서대로 증가되어 출력되었다.

12. JUnit 5: junit-platform.properties

JUnit 테스트 설정 파일 생성하기

  1. src > test > resources 디렉토리 생성 후 junit-platform.properties 파일 생성

  1. 설정파일로 안 잡히는 경우, 클래스패스 루트 (src/test/resources/)에 넣어두면 적용된다.
  • File > Project Properties > Project Settings > Modules

JUnit 테스트 설정 파일 사용하기

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

    • junit.jupiter.testinstance.lifecycle.default = per_class
    • 테스트 메소드마다 테스트 인스턴스를 생성하지 않도록 함
    • default는 테스트 메소드마다 테스트 인스턴스를 생성함
  • 확장팩 자동 감지 기능

    • junit.jupiter.extensions.autodetection.enabled = true
    • default는 확장팩 자동 감지를 하지 않음
  • @Disabled 무시하고 실행하기

    • junit.jupiter.conditions.deactivate = org.junit.*DisabledCondition
    • default는 @Disabled는 실행하지 않음
  • 테스트 이름 표기 전략 설정

    • junit.jupiter.displayname.generator.default = org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores

13. JUnit 5: 확장 모델

JUnit 5는 JUnit4보다 확장하는 방법이 단순해졌다.

  • JUnit 4의 확장 모델 - @RunWith(Runner), TestRule, MethodRule.
  • JUnit 5의 확장 모델 - 단 하나, Extension.

확장팩 등록 방법

실행 시간이 오래 걸리는 테스트 메서드가 있을 때, @SlowTest 어노테이션을 붙이는 확장 모델을 만들어보자.

  1. 선언적인 등록 @ExtendWith

    • 단점은 Extension 인스턴스를 생성자를 사용하여 생성하여야 할 경우, 인스턴스를 생성할 수 없다.
    @ExtendWith(FindSlowExtension.class)
    class StudyTest {
    	...
    }
    public class FindSlowExtension implements BeforeTestExecutionCallback, AfterTestExecutionCallback {
    
      private static final long THRESHOLD = 1000L;
    
      @Override
      public void beforeTestExecution(ExtensionContext context) throws Exception {
        ExtensionContext.Store store = getStore(context);
        store.put("START_TIME", 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 startTime = store.remove("START_TIME", long.class);
        long duration = System.currentTimeMillis() - startTime;
        if(duration > THRESHOLD && annotation == null) {
          System.out.printf("Please consider mark method [%s] with @SlowTest\n", testMethodName);
        }
      }
    
      private static Store getStore(ExtensionContext context) {
        String testClassName = context.getRequiredTestClass().getName();
        String testMethodName = context.getRequiredTestMethod().getName();
        return context.getStore(Namespace.create(testClassName, testMethodName));
      }
    }
  2. 프로그래밍 등록 @RegisterExtension

  • Extension 인스턴스를 생성자를 사용하여 생성하여야 할 경우에도, 인스턴스를 생성할 수 있다.
    class StudyTest {
    	...
    	@RegisterExtension
      static FindSlowExtension findSlowExtension = new FindSlowExtension(1000L);
    	...
    }
    public class FindSlowExtension implements BeforeTestExecutionCallback, AfterTestExecutionCallback {
    
      private long THRESHOLD;
    
      public FindSlowExtension(long THRESHOLD) {
        this.THRESHOLD = THRESHOLD;
      }
    	
    	...
    }
  1. 자동 등록 자바 ServiceLoader 이용

확장팩 만드는 방법

  • 테스트 실행 조건
  • 테스트 인스턴스 팩토리
  • 테스트 인스턴스 후-처리기
  • 테스트 매개변수 리졸버
  • 테스트 라이프사이클 콜백
  • 예외 처리
  • ...

참고

14. JUnit 5: JUnit 4 마이그레이션

기본적으로 SpringBoot 2.2.0 버전 이상 프로젝트를 생성하면 JUnit 5를 사용할 수 있다.

그러나, JUnit 4를 사용하기 위해서는 junit-vintage-engine을 의존성으로 추가해야지 사용할 수 있다.

→ JUnit 5의 junit-platform으로 JUnit 3과 4로 작성된 테스트를 실행할 수 있다.

  • @Rule은 기본적으로 지원하지 않지만, junit-jupiter-migrationsupport 모듈이 제공하는 @EnableRuleMigrationSupport를 사용하면 다음 타입의 Rule을 지원한다.
    • ExternalResource
    • Verifier
    • ExpectedException
JUnit 4JUnit 5
@Category(Class)@Tag(String)
@RunWith, @Rule, @ClassRule@ExtendWith, @RegisterExtension
@Ignore@Disabled
@Before, @After, @BeforeClass, @AfterClass@BeforeEach, @AfterEach, @BeforeAll, @AfterAll

💡 인프런 강의 <더 자바, 애플리케이션을 테스트하는 다양한 방법> 수강 후 정리한 글입니다.
: https://www.inflearn.com/course/the-java-application-test/dashboard

profile
나는 아직 멍청하다

0개의 댓글