gpt4 book ai didi

java - 从 @ComponentScan 中排除测试类中的配置

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:55:30 24 4
gpt4 key购买 nike

我遇到了 @ComponentScan @Configuration 的问题测试类——即 @ComponentScan无意中拉入 @Configuration在集成测试期间。

例如,假设您在 src/main/java 中有一些全局配置它在 com.example.service 中拉入组件, com.example.config.GlobalConfiguration :

package com.example.config;
...
@Configuration
@ComponentScan(basePackageClasses = ServiceA.class)
public class GlobalConfiguration {
...
}

它旨在引入两项服务,com.example.services.ServiceAcom.example.services.ServiceB , 注释为 @Component@Profile("!test") (为简洁起见省略)。

然后在 src/test/java 中,com.example.services.ServiceATest :

package com.example.services;
...
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ServiceATest.ServiceATestConfiguration.class)
public class ServiceATest {
...
@Configuration
public static class ServiceATestConfiguration {
@Bean
public ServiceA serviceA() {
return ServiceA(somemocking...);
}
}
}

还有com.example.ServiceBIntegrationTest , 需要拉入 GlobalConfiguration.class为了成为一个集成测试,但仍然避免使用 @ActiveProfiles("test") 引入危险的实现:

package com.example.services;
...
@RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles("test")
@ContextConfiguration(classes = {GlobalConfiguration.class, ServiceBIntegrationTest.ServiceBIntegrationTestConfiguration.class})
public class ServiceBIntegrationTest {
...
@Configuration
public static class ServiceBIntegrationTestConfiguration {
@Bean
public ServiceB serviceB() {
return ServiceB(somemocking...);
}
}
}

ServiceBIntegrationTest 的明显意图是拉入完整的src/main/java通过 GlobalConfiguration 配置应用程序, 通过 @ActiveProfiles("test") 排除危险成分并用自己的实现替换那些排除的组件。但是,在测试期间 src/main/java 的命名空间和 src/test/java合并,所以 GlobalConfiguration@ComponentScan在类路径中找到比通常更多的内容——即 ServiceAServiceA.ServiceATestConfiguration 中定义的 bean .这很容易导致冲突和意外结果。

现在,您可以在 GlobalConfiguration 上做一些事情喜欢@ComponentScan(..., excludeFilters= @ComponentScan.Filter(type = FilterType.REGEX, pattern = "\\.*(T|t)est\\.*")) ,但这有其自身的问题。依赖命名约定非常脆弱;尽管如此,即使你退出了 @TestConfiguration注释和使用 FilterType.ANNOTATION ,你实际上是在制作你的 src/main/java知道你的src/test/java ,它不应该是,IMO(见下面的注意)。

就目前而言,我已经通过使用附加配置文件解决了我的问题。在 ServiceA ,我添加了一个唯一的配置文件名称——这样它的配置文件注释就变成了类似 @ActiveProfiles("test,serviceatest") 的东西.然后,在 ServiceATest.ServiceATestConfiguration我添加注释 @Profile("serviceatest") .这有效地限制了 ServiceATestConfiguration 的范围。开销相对较小,但似乎是:

a) 我正在使用 @ComponentScan不正确,或者

b) 应该有一个更简洁的模式来处理这个问题

这是什么?


注意:是的,该应用程序是可测试的,因为它使用 @Profile("!test") ,但我认为让应用程序稍微具有测试意识以防止不当资源使用和使其具有测试意识以确保测试的正确性是完全不同的事情。

最佳答案

我看到您在集成测试期间试图伪造 Spring bean。如果您将 @Profile@ActiveProfiles 注释与 @Primary 注释结合使用,那么您的大部分头痛应该都会消失,并且您不需要标记带有 @Profile("!test") 的生产 bean。

我写了一个blog post on the topicGithub examples .

对评论的 react :

按包结构。组件扫描扫描当前包和子包中的所有包。如果您不想扫描 beans,只需修改您的包结构,使 bean 不在您的组件扫描范围内。

Spring 不区分来自 src/test/javasrc/main/java 的包。试图用 @Profile("!test") 排除生产 bean 是一种设计味道。你应该避免它。我建议给一个机会从提到的博客中获取方法。

请注意,当您使用 @Primary 注释覆盖 bean 时,您可能需要使用 @DirtiesContext 注释才能为其他测试提供干净的工作表。

关于java - 从 @ComponentScan 中排除测试类中的配置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36318473/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com