如何在所有测试之前/之后使用SpringExtension执行一些带有上下文的代码?

huangapple go评论69阅读模式
英文:

How to execute some code using context before/after all tests with SpringExtension?

问题

我需要在使用 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("接收到上下文启动事件。");
    }
        
    @EventListener
    public void handleContextRefreshEvent(ContextRefreshedEvent event) {
        System.out.println("接收到上下文刷新事件。");
    }
        
    @EventListener
    public void handleContextStoppedEvent(ContextStoppedEvent event) {
        System.out.println("接收到上下文停止事件。");
    }
}

然而,我发现当使用 SpringExtension 时,StartedEventStoppedEvent 并不会被触发。

有人可以说明如何做吗?我使用 Spring5 和 JUnit5。

英文:

I need to execute some initialization / deinitialization code before/after all tests (in all classes) using DI container when SpringExtension is used. I tried two solutions:

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

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

However, in BeforeAllAfterAll class I can't get reference to application context.

I tried to use events:

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.");
    }
}

However, as I found out when SpringExtension is used StartedEvent and StoppedEvent are not fired.

Could anyone say how to do it? I use Spring5 and JUnit5.

答案1

得分: 0

在研究了 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;
            // 在这里编写你的“所有测试之前”启动逻辑
            Namespace springNamespace = Namespace.create(SpringExtension.class);
            Store store = context.getRoot().getStore(springNamespace);
            // 需要传递任何测试类
            TestContextManager testContextManager =
                    store.getOrComputeIfAbsent(FooTest.class, TestContextManager::new, TestContextManager.class);
            ApplicationContext applicationContext = testContextManager.getTestContext().getApplicationContext();
            testEnvironment = applicationContext.getBean(TestEnvironment.class);
            testEnvironment.initialize();
            // 下面一行代码在根测试上下文关闭时注册回调钩子
            context.getRoot().getStore(GLOBAL).put("任何唯一名称", this);
        }
    }

    @Override
    public void close() {
        testEnvironment.deinitialize();
    }
}

也许有人可以提供更好的建议。

英文:

After studying spring-test source code I did the following solution:

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();
    }
}

Maybe someone can suggest something better.

huangapple
  • 本文由 发表于 2020年9月17日 18:55:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/63936529.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定