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

微笑、不失礼 提交于 2019-11-30 17:29:34

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);
        }
    }
}

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

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.

Josh Ghiloni

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!