自定义测试应用程序上下文

问题描述

我一直在拼命地尝试构建一个扩展,它需要来自 junit5 扩展模型和 Spring-Boot 测试框架的信息。具体来说,我想使用 ApplicationContextinitializer自定义注释挂钩 ApplicationContext 创建过程:

@Retention(RUNTIME)
@Target(TYPE)
@ContextConfiguration(initializers = CustomContextinitializer.class)
public @interface CustomAnnotation {
    String someOption();
}

测试看起来像这样:

@SpringBoottest
@CustomAnnotation(someOption = "Hello There")
public class SomeTest {
    ...
}

现在,如何从我的 CustomAnnotation 中访问测试类的 CustomContextinitializer 实例?

class CustomContextinitializer implements ApplicationContextinitializer<ConfigurableApplicationContext> {

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {

        // How to access the Test Class here?

        CustomAnnotation annotation = <Test Class>.getAnnotation(CustomAnnotation.class);
        System.out.println(annotation.someOption());
    }
}

在 ApplicationContext 的创建过程中是否有可能以某种方式访问​​ junit5 ExtensionContext?它不必来自 ApplicationContextinitializer 内。我只需要一个足够早执行的钩子,以便我可以在整个 bean 实例化过程实际开始之前注入一些动态生成属性

解决方法

查看 @DynamicPropertySource 以在 bean 初始化之前注入属性。然后,您可以使用 @RegisterExtension 注册一个自定义扩展,该扩展读取注释属性并通过某种方法使其可用:

@CustomAnnotation(someOption = "Hello There")
public class SomeTest {
    @RegisterExtension
    static CustomExtension extension = new CustomExtension();

    @DynamicPropertySource
    static void registerProperties(DynamicPropertyRegistry registry) {
        registry.add("property.you.need",() -> customExtension.getProperty());
    }
}

public class CustomExtension implements BeforeAllCallback {
    private String property;

    public String getProperty() {
        return property;
    }

    @Override
    public void beforeAll(ExtensionContext context) throws Exception {
        CustomAnnotation annotation = context.getRequiredTestClass()
            .getAnnotation(CustomAnnotation.class);
        property = annotation.someOption();
    }
}

我知道它没有回答关于将 JUnit 5 与 Spring 初始化机制挂钩的问题,但如果您只需要动态属性,这正好解决了这个问题。

,

您可以实现自己的 TestExecutionListener 并使用它来访问您提到的注释

@Retention(RUNTIME)
@Target(ElementType.TYPE)
@TestExecutionListeners(listeners = CustomTestExecutionListener.class,mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS)
@interface CustomAnnotation {
    String someOption();
}

static class CustomTestExecutionListener implements TestExecutionListener {
    @Override
    public void beforeTestClass(TestContext testContext) throws Exception {
       final CustomAnnotation annotation = testContext.getTestClass().getAnnotation(CustomAnnotation.class);
       System.out.println(annotation.someOption());
    }
}