Как выполнить некоторый код с использованием контекста до / после всех тестов с SpringExtension?

#java #spring #testing #junit

#java #весна #тестирование #junit

Вопрос:

Мне нужно выполнить некоторый код инициализации / деинициализации до / после всех тестов (во всех классах) с использованием контейнера DI, когда SpringExtension используется. Я попробовал два решения:

 @ExtendWith({BeforeAllAfterAll.class, SpringExtension.class})
@ContextConfiguration(classes = ContextConfig.class)
public class ServiceIT{..}

public class BeforeAllAfterAll implements BeforeAllCallback,
     ExtensionContext.Store.CloseableResource {...}
  

Однако в BeforeAllAfterAll классе я не могу получить ссылку на контекст приложения.

Я пытался использовать события:

 public class ContextEventHandler {
    
    @EventListener
    public void handleContextStartedEvent(ContextStartedEvent event) {
        System.out.println("Context Start Event received.");
    }
    
    @EventListener
    public void handleContextRefreshEvent(ContextRefreshedEvent event) {
        System.out.println("Context Refreshed Event received.");
    }
    
    @EventListener
    public void handleContextStoppedEvent(ContextStoppedEvent event) {
        System.out.println("Context Stopped Event received.");
    }
}
  

Однако, как я выяснил, когда SpringExtension используется StartedEvent и StoppedEvent не запускается.

Кто-нибудь может сказать, как это сделать? Я использую Spring5 и JUnit5.

Ответ №1:

После изучения исходного кода spring-test я принял следующее решение:

 public class BeforeAllAfterAll implements BeforeAllCallback, ExtensionContext.Store.CloseableResource {
    
    private static boolean started = false;
    
    private TestEnvironment testEnvironment;
    
    @Override
    public void beforeAll(ExtensionContext context) {
        if (!started) {
            started = true;
            // Your "before all tests" startup logic goes here
            Namespace springNamespace = Namespace.create(SpringExtension.class);
            Store store = context.getRoot().getStore(springNamespace);
            //we need to pass any test class
            TestContextManager testContextManager = 
                    store.getOrComputeIfAbsent(FooTest.class, TestContextManager::new, TestContextManager.class);
            ApplicationContext applicationContext = testContextManager.getTestContext().getApplicationContext();
            testEnvironment = applicationContext.getBean(TestEnvironment.class);
            testEnvironment.initialize();
            // The following line registers a callback hook when the root test context is shut down
            context.getRoot().getStore(GLOBAL).put("any unique name", this);
        }
    }
    
    @Override
    public void close() {
        testEnvironment.deinitialize();
    }
}
  

Может быть, кто-то может предложить что-то лучше.