본문 바로가기

Java

JUnit5 Extension 정리

Extension

Extension은 테스트 실행 전후로 무언가 처리를 하고 싶을 때 사용한다.

위와 같이 언제 실행될 것인지 구체적으로 정할 수 있으며 Interface로 구성되어 implements를 선언 후 메서드를 작성해주어야 한다.

 

주요 인터페이스

  • AfterAllCallback : 모든 테스트 종료 후 실행  (가장 나중에 실행된다.)
  • AfterEachCallback : @AfterEach 적용된 메서드 종료 후 실행
  • AfterTestExecutionCallback : 각 테스트가 종료 후 실행
  • BeforeAllCallback - @BeforeAll 적용된 메서드 전에 실행(가장 먼저 실행된다.)
  • BeforeEachCallback - @BeforeEach 적용된 메서드 종료 후 실행
  • BeforeTestExecutionCallback - 각 테스트가 실행되기 직전에 실행

테스트 클래스에 Extension 적용 방법

1. @ExtendWith : 클래스에 적용하여 Extension 등록

@ExtendWith(FindSlowTestExtension.class)
public class ExtensionTest

 

2. @RegisterExtension : 필드에 적용하여 Extension 등록

    @RegisterExtension
    static FindSlowTestExtension findSlowTestExtension = new FindSlowTestExtension(3000L);

 

더 많은 방법이 있지만 크게 위 2가지를 사용하여 적용한다.

@ExtendWith를 적용할 경우 기본 생성자로 만들어지기 때문에 초기화 시 필드값을 넣어주어야 한다면 @RegisterExtension 을 적용하면 된다.

주요 인터페이스 순서 예시 

OrderTestExtension.java

package me.hoon.tdd.practice.extension;

import org.junit.jupiter.api.extension.*;

public class OrderTestExtension implements BeforeAllCallback, BeforeEachCallback, BeforeTestExecutionCallback, AfterAllCallback, AfterEachCallback, AfterTestExecutionCallback {

    @Override
    public void beforeAll(ExtensionContext extensionContext) throws Exception {
        System.out.println("BeforeAllCallback 실행");
    }

    @Override
    public void beforeEach(ExtensionContext extensionContext) throws Exception {
        System.out.println("BeforeEachCallback 실행");
    }

    @Override
    public void beforeTestExecution(ExtensionContext context) throws Exception {
        System.out.println("beforeTestExecution 실행");
    }

    @Override
    public void afterAll(ExtensionContext extensionContext) throws Exception {
        System.out.println("AfterAllCallback 실행");
    }

    @Override
    public void afterEach(ExtensionContext extensionContext) throws Exception {
        System.out.println("AfterEachCallback 실행");
    }

    @Override
    public void afterTestExecution(ExtensionContext context) throws Exception {
        System.out.println("afterTestExecution 실행");
    }
}

주요 인터페이스의 메서드를 Overried 하여 테스트 실행 시 메시지를 출력하게 하였다.

 

ExtensionTest.java

package me.hoon.tdd.practice.extension;

import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.ExtendWith;

@ExtendWith(OrderTestExtension.class)
public class ExtensionTest {

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

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

    @BeforeEach
    void beforeEach() {
        System.out.println("@beforeEach 실행");
    }

    @AfterEach
    void afterEach() {
        System.out.println("@AfterEach 실행");
    }

    @Test
    void test1() {
        System.out.println("test1 메서드 실행");
    }

    @Test
    void test2() {
        System.out.println("test2 메서드");
    }

    @Test
    void test3() {
        System.out.println("test3 메서드");
    }

}

 

테스트 메서드 구현

 

 

실행 순서

BeforeAllCallback 실행
@BeforeAll 실행
----------------------------------------
BeforeEachCallback 실행
@beforeEach 실행
beforeTestExecution 실행
test1 메서드 실행
afterTestExecution 실행
@AfterEach 실행
AfterEachCallback 실행
----------------------------------------
BeforeEachCallback 실행
@beforeEach 실행
beforeTestExecution 실행
test2 메서드
afterTestExecution 실행
@AfterEach 실행
AfterEachCallback 실행
----------------------------------------
BeforeEachCallback 실행
@beforeEach 실행
beforeTestExecution 실행
test3 메서드
afterTestExecution 실행
@AfterEach 실행
AfterEachCallback 실행
----------------------------------------
@AfterAll 실행
AfterAllCallback 실행

한번씩 실행 (가장먼저 실행)

BeforeAllCallback 실행

@BeforeAll 실행

 

각 테스트마다 실행

BeforeEachCallback 실행
@beforeEach 실행
beforeTestExecution 실행
test1~3 메서드 실행
afterTestExecution 실행
@AfterEach 실행
AfterEachCallback 실행

 

한번씩 실행 (모든 테스트 종료 후 실행)

@AfterAll 실행
AfterAllCallback 실행

ExtensionContext

상속 받은 모든 메서드에는 ExtensionContext 가 매개변수로 있다.

private void getExtensionContextInfo(ExtensionContext context) {
    //실행 중인 class명
    System.out.println(context.getRequiredTestClass().getName());
    
    //실행 중인 method명
    System.out.println(context.getRequiredTestMethod().getName());
}

 

실행 결과

me.hoon.tdd.practice.extension.ExtensionTest
test1

위와 같이 클래스의 정보를 담고 있으며 Reflection을 사용했을 때 클래스의 정보를 가져올 수 있는 것처럼 ExtensionContext에서도 가져올 수 있으며 필요시 테스트 하는데 활용 할 수도 있다.

 

또한 ExtensionContext.Store를 통해 테스트마다 특정한 값을 전달할 수 있다.

@Override
public void beforeEach(ExtensionContext context) throws Exception {
    System.out.println("BeforeEachCallback 실행");
    ExtensionContext.Store store = getStore(context);
    
    //값 저장
    store.put("key", "value");
}

@Override
public void afterEach(ExtensionContext context) throws Exception {
    System.out.println("AfterEachCallback 실행");
    ExtensionContext.Store store = getStore(context);
    
    //값 얻기
    System.out.println(store.get("key"));
}

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

 

실행 결과

BeforeEachCallback 실행
test1 메서드 실행
AfterEachCallback 실행
value

store을 사용해서 key, value 형태로 저장이 가능하고 저장된 값을 얻어올 수 있다.

마치 ThreadLocal 처럼 사용이 가능하며 별도로 자원을 해제할 필요는 없다.