Test ‐ JUnit5 - dnwls16071/Backend_Summary GitHub Wiki
📚 JUnit5
- Platform : 테스트를 실행시켜주는 런처를 제공, TestEngine API 제공
- Jupiter : TestEngine API 구현체로 JUnit5를 제공
- Vintage : JUnit4와 JUnit3을 지원하는 TestEngine 구현체
지원되는 어노테이션 정리
@BeforeAll: Denotes that the annotated method should be executed before all@Test@AfterAll: Denotes that the annotated method should be executed after all@Test@BeforeEach: Denotes that the annotated method should be executed before each@Test@AfterEach: Denotes that the annotated method should be executed after each@Test@DisplayNameGeneration: Declares a custom display name generator for the test class. Such annotations are inherited.@DisplayName: Declares a custom display name for the test class or test method. Such annotations are not inherited.assertNotNull: 값이 null이 아닌지를 확인assertEquals: 실제 값이 기대한 값과 같은지를 확인assertTrue: 다음 조건이 true인지 확인assertAll: 모든 확인 구문 확인assertThrows: 지정한 예외가 발생했는지를 확인assertTimeout: 특정 시간 안에 실행이 완료되는지를 확인
❗회사에서 개발하면서 테스트 코드를 작성하는 것도 좋을 것 같다. 기회가 된다면 데드라인을 넘기지 않는 선에서 작성하는 버릇을 들여야겠다.
package com.example.test;
import com.example.test.domain.Study;
import org.junit.jupiter.api.*;
import static org.assertj.core.api.Assertions.assertThat;
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
class StudyTest {
@Test
@DisplayName("스터디 만들기 ╯°□°)╯")
void create_new_study() {
Study actual = new Study(10);
assertThat(actual.getLimit()).isGreaterThan(0);
}
@Test
@DisplayName("스터디 만들기 \uD83D\uDE31")
void create_new_study_again() {
System.out.println("create1");
}
@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");
}
}
📚 JUnit5 조건에 따라 테스트 실행하기
assumeTrue: 특정 조건을 만족하는 경우에 테스트를 실행하는 방법assumeThat: 특정 조건을 만족하는 경우에 테스트를 실행하는 방법@Enable__&@Disabled__:OnOS,OnJre,IfSystemProperty,IfEnvironmentVariable,If
📚 JUnit5 태깅과 필터링
@Tag: 테스트 메서드에 태그를 추가해 테스트 그룹을 만들어 원하는 테스트 그룹만을 실행할 수 있는 방법
📚 JUnit5 커스텀 태그
- JUnit5 어노테이션을 조합해 커스텀 태그를 만들 수 있다.
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Test
@Tag("fast")
public @interface CustomAnnotation {
}
📚 JUnit5 테스트 반복
@RepeatedTest: Denotes that a method is a test template for a repeated test. Such methods are inherited unless they are overridden.@ParameterizedTest: Denotes that a method is a parameterized test. Such methods are inherited unless they are overridden.
@DisplayName("스터디 만들기")
@RepeatedTest(value = 10, name = "{displayName} {currentRepetition}/{totalRepetitions}")
void repeatTest(RepetitionInfo repetitionInfo) {
System.out.println("test : " + repetitionInfo.getCurrentRepetition() + " / " + repetitionInfo.getTotalRepetitions());
}
@ParameterizedTest(name = "{index} {displayName} message={0}")
@ValueSource(strings = {"날씨가", "많이", "추워지고", "있네요"})
void parameterizedTest(String message) {
System.out.println("message = " + message);
}
@ValueSource: @ValueSource is one of the simplest possible sources. It lets you specify a single array of literal values and can only be used for providing a single argument per parameterized test invocation.@NullSource: provides a single null argument to the annotated @ParameterizedClass or @ParameterizedTest@EmptySource: provides a single empty argument to the annotated @ParameterizedClass or @ParameterizedTest for parameters@NullAndEmptySource: a composed annotation that combines the functionality of @NullSource and @EmptySource@EnumSource: @EnumSource provides a convenient way to use Enum constants@MethodSource: @MethodSource allows you to refer to one or more factory methods of the test class or external classes@CsvSource: @CsvSource allows you to express argument lists as comma-separated values@CsvFileSource: @CsvFileSource lets you use comma-separated value (CSV) files from the classpath or the local file system@ArgumentSource: @ArgumentsSource can be used to specify a custom, reusable ArgumentsProvider, Note that an implementation of ArgumentsProvider must be declared as either a top-level class or as a static nested class
@ParameterizedTest(name = "{index} {displayName} message={0}")
@ValueSource(ints = {10, 20, 40})
void parameterizedTest(@ConvertWith(StudyConverter.class) Study study) {
System.out.println("study = " + study.getLimit());
}
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()));
}
}
📚 JUnit5 테스트 인스턴스
- JUnit은 테스트 메서드마다 테스트 인스턴스를 새로 만든다.
- 테스트 메서드를 독립적으로 실행해 예상치 못한 부작용을 막기 위함이다. 이런 기본 전략을 JUnit5에서 변경할 수 있다.
@TestInstance(LifeCycle.PER_CLASS)- 테스트 클래스당 인스턴스를 하나만 만들어 사용한다.
- 필요에 따라 테스트 간 공유하는 모든 상태를 @BeforeEach 또는 @AfterEach에서 초기화 할 필요가 있다.
- 테스트 A가 테스트 B의 실행에 영향을 미치면 안되기 때문에 이런 것과 무관한 경우의 테스트라면 한 번쯤은 고민해 볼 필요가 있어보인다.
@TestInstance(value = TestInstance.Lifecycle.PER_CLASS)
📚 JUnit5 테스트 순서
- 경우에 따라 특정 순서대로 테스트를 실행하고픈 순간이 온다. 이런 경우에는 테스트 메서드를 원하는 순서에 따라 실행하도록
@TestInstance(LifeCycle.PER_CLASS)와 함께@TestMethodOrder를 사용할 수 있다. - MethodOrderer 구현체를 설정한다. -> 기본 구현체 : Alphanumeric, OrderAnnotation, Random
@TestInstance: Used to configure the test instance lifecycle for the annotated test class. Such annotations are inherited.
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
@TestInstance(value = TestInstance.Lifecycle.PER_CLASS)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) // 구현체 적용
class StudyTest {
@Test
@CustomAnnotation
@Order(1) // 순서 지정
@DisplayName("스터디 만들기 ╯°□°)╯")
void create_new_study() {
String test_env = System.getenv("TEST_ENV");
System.out.println("test_env = " + test_env);
assumeTrue("LOCAL".equalsIgnoreCase(test_env));
assumeThat(test_env).isEqualToIgnoringCase("LOCAL");
Study study = new Study(10);
assertThat(study.getLimit()).isGreaterThan(0);
}
@Test
@CustomAnnotation
@Order(2) // 순서 지정
@DisplayName("스터디 만들기 \uD83D\uDE31")
void create_new_study_again() {
System.out.println("create1");
}
}
📚 JUnit5 - junit-platform.properties
- JUnit5 설정 파일로 클래스패스 루트(
/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.DisplayNameGenerator$ReplaceUnderscores
📚 JUnit5 확장 모델
- JUnit4 확장 모델은
@RunWith(Runner),TestRule,MethodRule - JUnit5 확장 모델은
Extension - 확장팩을 등록하는 방법
- 선언적 등록 방법 :
@ExtendWith - 프로그래밍 등록 방법 :
@RegisterExtension
- 선언적 등록 방법 :