Can @ContextConfiguration in a custom annotation be merged?

余生颓废 提交于 2019-12-23 04:58:19

问题


I am working on custom Spring Boot starters. In a test starter what I wanted do to is to implement a composed annotation, which would add additional @Configuration classes to the ApplicationContext (and possibly use this annotation in a TestExecutionListener). ex:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@ContextConfiguration(classes = AdditionalTestConfiguration.class)
public @interface ComposedAnnotation {
}

And use that in my Spring Boot integration test:

@RunWith(SpringJUnit4ClassRunner.class)
@WebIntegrationTest
@SpringApplicationConfiguration(Application.class)
@ComposedAnnotation
public class SomeTest {
}

No inheritance is involved. Unfortunately, it does not seem to work. I doubt it's a Spring Boot thing, rather Spring testing framework itself.

Is there any way I can achieve expected result?


回答1:


You're right: this is not an issue with Spring Boot. But it's also not an issue with spring-test.

Rather, it's the intended behavior of Spring in general. For details, check out my answer to this question: @ActiveProfiles in meta annotation and on test class not working

In summary, you cannot achieve this with two @ContextConfiguration annotations declared on an individual test class (either directly or as meta-annotations).

However, I just came up with a trick that will allow you to achieve this. Specifically, you can create an ApplicationContextInitializer (ACI) that registers one or more @Configuration classes. In your composed annotation, you can then register this ACI to register the always present @Configuration classes. And when the composed annotation is actually used, it can declare additional @Configuration classes like normal.

I just submitted a working example in this commit.

Basically, the code would look something like this:

@ContextConfiguration(loader = AnnotationConfigContextLoader.class, initializers = FooConfigInitializer.class)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComposedContextConfiguration {

    @AliasFor(annotation = ContextConfiguration.class, attribute = "classes")
    Class<?>[] value() default {};
}
public class FooConfigInitializer implements ApplicationContextInitializer<GenericApplicationContext> {

    @Override
    public void initialize(GenericApplicationContext applicationContext) {
        new AnnotatedBeanDefinitionReader(applicationContext).register(FooConfig.class);
    }
}

And you can use it like this:

@RunWith(SpringRunner.class)
@ComposedContextConfiguration(BarConfig.class)
public class InitializerConfiguredViaMetaAnnotationTests { /* ... */ }

Your ApplicationContext will then be loaded from FooConfig and BarConfig.

The above examples obviously do not use Spring Boot, but the same principles should also be applicable to @SpringApplicationConfiguration.

Regards,

Sam (author of the Spring TestContext Framework)



来源:https://stackoverflow.com/questions/35733344/can-contextconfiguration-in-a-custom-annotation-be-merged

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!