¿Cómo usar @ComponentScan junto con ContextConfigurations específicas de prueba en SpringJunit4TestRunner?

Estoy probando una aplicación Spring Boot. Tengo varias clases de prueba, cada una de las cuales necesita un conjunto diferente de beans simulados o personalizados.

Aquí hay un boceto de la configuración:

src / main / java:

package com.example.myapp;

@SpringBootApplication
@ComponentScan(
        basePackageClasses = {
                MyApplication.class,
                ImportantConfigurationFromSomeLibrary.class,
                ImportantConfigurationFromAnotherLibrary.class})
@EnableFeignClients
@EnableHystrix
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

package com.example.myapp.feature1;

@Component
public class Component1 {
    @Autowired
    ServiceClient serviceClient;

    @Autowired
    SpringDataJpaRepository dbRepository;

    @Autowired
    ThingFromSomeLibrary importantThingIDontWantToExplicitlyConstructInTests;

    // methods I want to test...
}

src / prueba / java:

package com.example.myapp;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MyApplication.class)
@WebAppConfiguration
@ActiveProfiles("test")
public class Component1TestWithFakeCommunication {

    @Autowired
    Component1 component1; // <-- the thing we're testing. wants the above mock implementations of beans wired into it.

    @Autowired
    ServiceClient mockedServiceClient;

    @Configuration
    static class ContextConfiguration {
        @Bean
        @Primary
        public ServiceClient mockedServiceClient() {
            return mock(ServiceClient.class);
        }
    }

    @Before
    public void setup() {
        reset(mockedServiceClient);
    }

    @Test
    public void shouldBehaveACertainWay() {
        // customize mock, call component methods, assert results...
    }
}

package com.example.myapp;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MyApplication.class)
@WebAppConfiguration
@ActiveProfiles("test")
public class Component1TestWithRealCommunication {

    @Autowired
    Component1 component1; // <-- the thing we're testing. wants the real implementations in this test.

    @Autowired
    ServiceClient mockedServiceClient;

    @Before
    public void setup() {
        reset(mockedServiceClient);
    }

    @Test
    public void shouldBehaveACertainWay() {
        // call component methods, assert results...
    }
}

El problema con la configuración anterior es que la exploración de componentes configurada en MyApplication recoge Component1TestWithFakeCommunication.ContextConfiguration, por lo que obtengo un ServiceClient simulado incluso en Component1TestWithRealCommunication donde quiero la implementación real de ServiceClient.

Aunque podría usar constructores @Autowired y construir los componentes yo mismo en ambas pruebas, hay una cantidad suficiente de cosas con una configuración complicada que preferiría tener Spring TestContext configurado para mí (por ejemplo, repositorios Spring Data JPA, componentes de bibliotecas fuera de la aplicación que extrae beans del contexto Spring, etc.). Anidar una configuración Spring dentro de la prueba que puede anular localmente ciertas definiciones de bean dentro del contexto Spring parece que debería ser una forma limpia de hacerlo; La única desventaja es que estas configuraciones anidadas terminan afectando todas las pruebas de Spring TestContext que basan su configuración en MyApplication (qué componente escanea el paquete de la aplicación).

¿Cómo modifico mi configuración para que sigo obteniendo un contexto Spring "mayormente real" para mis pruebas con solo unos pocos beans anulados localmente en cada clase de prueba?

Respuestas a la pregunta(4)

Su respuesta a la pregunta