How to use @ComponentScan together with test-specific ContextConfigurations in SpringJunit4TestRunner?

后端 未结 4 1898
心在旅途
心在旅途 2021-01-01 14:32

I am testing a Spring Boot application. I have several test classes, each of which needs a different set of mocked or otherwise customized beans.

Here is a sketch of

相关标签:
4条回答
  • 2021-01-01 15:16

    You may use additional explicit profiles to avoid such test configurations to be picked up (as suggested in another answer). I also did it and even created some library support for that.

    However, Spring-Boot is clever and it has a built-in "type filter" to resolve this issue automatically. For this to work, you need to remove your @ComponentScan annotation, which would find your test configurations, and let the @SpringBootApplication do the work. In your example, just remove this:

    @SpringBootApplication
    @ComponentScan(
        basePackageClasses = {
                MyApplication.class,
                ImportantConfigurationFromSomeLibrary.class,
                ImportantConfigurationFromAnotherLibrary.class})
    

    and replace it with:

    @SpringBootApplication(scanBasePackageClasses= {
                MyApplication.class,
                ImportantConfigurationFromSomeLibrary.class,
                ImportantConfigurationFromAnotherLibrary.class})
    

    You may also need to annotate your test as @SpringBootTest. This should avoid auto-scanning any inner-class configurations (and components) except for those residing in the current test.

    0 讨论(0)
  • 2021-01-01 15:23

    The following should help you to achieve your goal by introducing a new fake-communication profile that is applicable only to the current test class.

    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringApplicationConfiguration(classes = MyApplication.class)
    @WebAppConfiguration
    @ActiveProfiles({"test", "fake-communication"})
    public class Component1TestWithFakeCommunication {
    
        // @Autowired ...
    
        @Profile("fake-communication")
        @Configuration
        static class ContextConfiguration {
            @Bean
            @Primary
            public ServiceClient mockedServiceClient() {
                return mock(ServiceClient.class);
            }
        }
    }
    
    0 讨论(0)
  • 2021-01-01 15:24

    I would do a couple of things:

    1. Move your test classes into a different package to avoid @ComponentScaning them.
    2. In Component1TestWithFakeCommunication, change @SpringApplicationConfiguration(classes = MyApplication.class) to @SpringApplicationConfiguration(classes = {MyApplication.class, Component1TestWithFakeCommunication.ContextConfiguration.class})

    That should give Spring sufficient information to mock up the test beans, but it should prevent the runtime ApplicationContext from noticing your test beans as well.

    0 讨论(0)
  • 2021-01-01 15:29

    If you have a @SpringBootTest you can just annotate the service you want to mock with @MockBean. As simple as that.

    0 讨论(0)
提交回复
热议问题