自定义注解中的@ContextConfiguration是否可以合并?
Can @ContextConfiguration in a custom annotation be merged?
我正在开发自定义 Spring 启动器。在测试启动器中,我想要做的是实现一个组合注释,它将向 ApplicationContext
添加额外的 @Configuration
类(并可能在 TestExecutionListener
中使用此注释).例如:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@ContextConfiguration(classes = AdditionalTestConfiguration.class)
public @interface ComposedAnnotation {
}
并在我的 Spring 引导集成测试中使用它:
@RunWith(SpringJUnit4ClassRunner.class)
@WebIntegrationTest
@SpringApplicationConfiguration(Application.class)
@ComposedAnnotation
public class SomeTest {
}
不涉及继承。不幸的是,它似乎不起作用。我怀疑它是 Spring 启动的东西,而不是 Spring 测试框架本身。
有什么方法可以达到预期的效果吗?
你是对的:这不是 Spring Boot 的问题。但这也不是 spring-test
.
的问题
相反,这是 Spring 的一般预期行为。有关详细信息,请查看我对此问题的回答:@ActiveProfiles in meta annotation and on test class not working
总而言之,您无法通过在单个测试 class 上声明两个 @ContextConfiguration
注释(直接或作为元注释)来实现此目的。
不过,我想出了一个 技巧 可以让您实现这一目标。具体来说,您可以创建一个 ApplicationContextInitializer
(ACI) 来注册一个或多个 @Configuration
classes。然后,在您的组合注释中,您可以注册此 ACI 以注册 always present @Configuration
classes。并且在实际使用组合注解时,它可以声明额外的 @Configuration
class 像正常一样。
我刚刚在 this commit 中提交了一个工作示例。
基本上,代码看起来像这样:
@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);
}
}
你可以这样使用它:
@RunWith(SpringRunner.class)
@ComposedContextConfiguration(BarConfig.class)
public class InitializerConfiguredViaMetaAnnotationTests { /* ... */ }
然后将从 FooConfig
和 BarConfig
.
加载您的 ApplicationContext
上面的例子显然没有使用Spring引导,但同样的原理应该也适用于@SpringApplicationConfiguration
.
此致,
Sam(Spring TestContext Framework 的作者)
我正在开发自定义 Spring 启动器。在测试启动器中,我想要做的是实现一个组合注释,它将向 ApplicationContext
添加额外的 @Configuration
类(并可能在 TestExecutionListener
中使用此注释).例如:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@ContextConfiguration(classes = AdditionalTestConfiguration.class)
public @interface ComposedAnnotation {
}
并在我的 Spring 引导集成测试中使用它:
@RunWith(SpringJUnit4ClassRunner.class)
@WebIntegrationTest
@SpringApplicationConfiguration(Application.class)
@ComposedAnnotation
public class SomeTest {
}
不涉及继承。不幸的是,它似乎不起作用。我怀疑它是 Spring 启动的东西,而不是 Spring 测试框架本身。
有什么方法可以达到预期的效果吗?
你是对的:这不是 Spring Boot 的问题。但这也不是 spring-test
.
相反,这是 Spring 的一般预期行为。有关详细信息,请查看我对此问题的回答:@ActiveProfiles in meta annotation and on test class not working
总而言之,您无法通过在单个测试 class 上声明两个 @ContextConfiguration
注释(直接或作为元注释)来实现此目的。
不过,我想出了一个 技巧 可以让您实现这一目标。具体来说,您可以创建一个 ApplicationContextInitializer
(ACI) 来注册一个或多个 @Configuration
classes。然后,在您的组合注释中,您可以注册此 ACI 以注册 always present @Configuration
classes。并且在实际使用组合注解时,它可以声明额外的 @Configuration
class 像正常一样。
我刚刚在 this commit 中提交了一个工作示例。
基本上,代码看起来像这样:
@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);
}
}
你可以这样使用它:
@RunWith(SpringRunner.class)
@ComposedContextConfiguration(BarConfig.class)
public class InitializerConfiguredViaMetaAnnotationTests { /* ... */ }
然后将从 FooConfig
和 BarConfig
.
ApplicationContext
上面的例子显然没有使用Spring引导,但同样的原理应该也适用于@SpringApplicationConfiguration
.
此致,
Sam(Spring TestContext Framework 的作者)