Wie verwende ich @ComponentScan zusammen mit testspezifischen ContextConfigurations in SpringJunit4TestRunner?

Ich teste eine Spring Boot-Anwendung. Ich habe mehrere Testklassen, von denen jede einen anderen Satz verspotteter oder anderweitig angepasster Bohnen benötigt.

Hier ist eine Skizze des Setups:

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 / test / 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...
    }
}

Das Problem mit dem obigen Setup besteht darin, dass der in MyApplication konfigurierte Komponentenscan Component1TestWithFakeCommunication.ContextConfiguration aufnimmt, sodass ich auch in Component1TestWithRealCommunication einen falschen ServiceClient erhalte, bei dem ich die echte ServiceClient-Implementierung möchte.

Obwohl ich in beiden Tests @Autowired-Konstruktoren verwenden und die Komponenten selbst aufbauen könnte, gibt es genügend Dinge mit kompliziertem Setup, für die ich Spring TestContext einrichten möchte (z. B. Spring Data JPA-Repositorys, Komponenten aus Bibliotheken außerhalb der App, die Beans aus dem Spring-Kontext ziehen, usw.). Das Verschachteln einer Spring-Konfiguration innerhalb des Tests, die bestimmte Bean-Definitionen im Spring-Kontext lokal überschreiben kann, scheint eine saubere Möglichkeit zu sein, dies zu tun. Der einzige Nachteil ist, dass diese verschachtelten Konfigurationen alle Spring TestContext-Tests betreffen, deren Konfiguration auf MyApplication basiert (welche Komponente das App-Paket durchsucht).

Wie ändere ich mein Setup, damit ich für meine Tests immer noch einen "meist echten" Spring-Kontext mit nur wenigen lokal überschriebenen Beans in jeder Testklasse erhalte?

Antworten auf die Frage(8)

Ihre Antwort auf die Frage