1 回答
TA贡献1829条经验 获得超9个赞
经过一些实验,我得到了以下解决方案。
背景
我们有两个接口:IClient 和 IServer
IClient 有两种实现:RealClient 和 MockClient。
IServer 有两种实现:RealServer 和 MockServer。
要求
生产代码(在 main/java 中)应该使用两者的 Real 实现。
测试夹具(在test/java中用@SpringBootTest注释)
InterfaceTests 定义了应该使用 MockServer 和 MockClient 的测试
ClientTests 定义了应该使用 MockServer 和 RealClient 来测试 RealClient 的测试。
ServerTests 定义了应该使用 MockClient 和 RealServer 来测试 RealServer 的测试。
IntegrationTests 定义应使用 RealServer 和 RealClient 的测试
从上面可以清楚地看出,模拟/真实客户端/服务器有四种组合,并且每种组合在代码的某些区域都需要。
解决方案
该解决方案利用 @Configuration 和 @TestConfiguration 注释来实现这些要求,而无需重复代码。
不要使用 @Component 注释接口及其实现
在main/java下实现一个配置类如下:
@Configuration
public class RealInjector {
@Bean
public IServer createServer(){
return new RealServer();
}
@Bean
public IClient createClient(){
return new RealClient();
}
}
在test/java下实现这三个测试配置类
@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();
}
}
将 InterfaceTests 测试装置注释如下:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {AllMockInjector.class})
public class InterfaceTests { ... }
将 ClientTests 测试装置注释如下:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {MockServerInjector.class})
public class ClientTests { ... }
将 ServerTests 测试装置注释如下:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {MockClientInjector.class})
public class ServerTests { ... }
按如下方式注释 IntegrationTests 测试装置:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {RealInjector.class})
public class IntegrationTests { ... }
最后
为了让测试配置类覆盖 main/java 中的 RealInjector 配置类,我们需要设置属性:
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 中的一个属性)。
添加回答
举报