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 中的一個屬性)。
添加回答
舉報