![](/img/trans.png)
[英]How can I use composition of the classes if they have common fields in java?
[英]How can I efficiently use nested configuration classes to inject dependencies when I have many SpringBootTest classes
公认的答案是在每个@SpringBootTest
测试夹具 class 中定义一个嵌套的 class,用@TestConfiguration
对其进行注释,并在其中为每个需要解析的 bean 定义一个工厂方法。 嵌套类的影响范围仅限于测试夹具,影响夹具中的所有测试,但不影响其他夹具中定义的测试。
当在每个测试夹具中运行测试时,这提供了对注入到组件中的依赖项的细粒度控制。
这种方法的问题在于,它需要在每个测试夹具 class 中添加嵌套解析器 class。 这是不可扩展的。 考虑一个有 10 个测试装置的项目。 其中 9 个使用相同的注入依赖项,只有第 10 个需要针对一个特定接口的不同实现。
在这种情况下,我需要将测试配置 class 复制到 9 个测试夹具类中,并仅在第 10 次测试中使用第二个配置 class。
我需要一种更具可扩展性的方式来做到这一点。 例如,在上面的例子中,我希望能够定义两个配置类,一个用于测试夹具使用的两个配置中的每一个。 然后我希望能够为每个测试夹具指定应该使用两个配置类中的哪一个。 我努力了:
@Import
注释将一个文本夹具的嵌套配置 class 导入另一个测试夹具,但是这样做时,配置 class 在后者中被忽略。因此,总而言之,我正在寻找一种有效的方法,它允许我只编写每个配置 class 一次,然后选择性地将一个配置应用于每个 SpringBootTest class 而无需复制它。
经过一些实验,我达到了以下解决方案。 我将添加所有细节来总结我在上一个问题中学到的东西。
测试夹具(在 test/java 中用 @SpringBootTest 注释)
从上面可以清楚地看出,模拟/真实客户端/服务器有四种组合,并且在代码的某些区域需要每种组合。
此解决方案利用 @Configuration 和 @TestConfiguration 注释来实现这些要求,而无需重复代码。
@Configuration
public class RealInjector {
@Bean
public IServer createServer(){
return new RealServer();
}
@Bean
public IClient createClient(){
return new RealClient();
}
}
@TestConfiguration
public class AllMockInjector {
@Bean
public IServer createServer(){
return new MockServer();
}
@Bean
public IClient createClient(){
return new MockClient();
}
}
@TestConfiguration
public class MockServerInjector{
@Bean
public IServer createServer(){
return new MockServer();
}
@Bean
public IClient createClient(){
return new RealClient();
}
}
@TestConfiguration
public class MockClientInjector{
@Bean
public IServer createServer(){
return new RealServer();
}
@Bean
public IClient createClient(){
return new MockClient();
}
}
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {AllMockInjector.class})
public class InterfaceTests { ... }
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {MockServerInjector.class})
public class ClientTests { ... }
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {MockClientInjector.class})
public class ServerTests { ... }
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {RealInjector.class})
public class IntegrationTests { ... }
为了让测试配置类覆盖来自 main/java 的 RealInjector 配置 class,我们需要设置属性:
spring.main.allow-bean-definition-overriding=true
一种方法是对上述每个测试夹具进行如下注释:
@SpringBootTest(properties = ["spring.main.allow-bean-definition-overriding=true"])
class TestFixture { ... }
但这非常冗长,特别是如果您有很多测试装置。 相反,您可以在 test/resources 下的 application.properties 文件中添加以下内容:
spring.main.allow-bean-definition-overriding=true
您可能还需要在 main/resources 下的 application.properties 中添加它。
此解决方案使您可以对注入到您的代码中以用于生产和测试的实现进行细粒度控制。 该解决方案不需要代码重复或外部配置文件(除了 test/resources/application.properties 中的一个属性)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.