После некоторых экспериментов я достиг следующего решения. Я добавлю все детали, суммирующие то, что я узнал в предыдущем вопросе тоже.
Фон
- У нас есть два интерфейса: IClient и IServer
- Существует две реализации IClient: RealClient и MockClient.
- Существует две реализации IServer: RealServer и MockServer.
Требования
- Производствокод (в main / java) должен использовать реальные реализации обоих.
Test Fixtures (аннотирован @SpringBootTest в test / java)
- 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();
}
}
В рамках теста / 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 { ... }
Наконец
Чтобы классы конфигурации теста переопределили класс конфигурации RealInjector из main / java, нам нужноустановите свойство:
spring.main.allow-bean-definition-overriding=true
Один из способов сделать это - аннотировать каждое из приведенных выше тестовых приспособлений следующим образом:
@SpringBootTest(properties = ["spring.main.allow-bean-definition-overriding=true"])
class TestFixture { ... }
, но это довольно многословно, особенно если у вас много тестов. светильники. Вместо этого вы можете добавить следующее в файл application.properties в разделе test / resources:
spring.main.allow-bean-definition-overriding=true
Вам также может понадобиться добавить его в application.properties в разделе main / resources.
Сводка
Это решение предоставляет вам точный контроль над реализациями, которые внедряются в ваш код для производства и тестирования. Решение не требует дублирования кода или внешних файлов конфигурации (кроме одного свойства в test / resources / application.properties).