springspring-bootjunit

Inner static class with @Configuration picked up by spring scanner for all tests. What is wrong?


Spring picks up inner @Configuration for Test1 from Test2. I need a mocked IService in Test2 but a real ServiceImpl in Test1. Also I want to have common TestConfiguration for all my tests. But I always have mocked IService in both tests. What is wrong?

How I can disable inner configurations picking up for sibling tests?

Here is my code :

ServiceImpl.java:

@Service
public class SeriviveImpl implements IService {
}

TestConfiguration.java:

@Configuration
@ComponentScan
public class TestConfiguration {
   // empty
}

Test1.java:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {TestConfiguration.class})
public class Test1 {
    @Autowired
    private IService service;
}

Test2.java

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {Test2.CustomConfiguration.class, TestConfiguration.class})
public class Test2 {
    @Autowired
    private IService service;

    @Configuration
    static class CustomConfiguration {
        @Bean
        IService service() {
            return mock(IService.class);
        }
    }
}

Solution

  • You can filter the inner class from the TestConfiguration @ComponentScan:

    @Configuration
    @ComponentScan(excludeFilters = {
         @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,
                               value = Test2.CustomConfiguration.class)
    })
    public class TestConfiguration {
       // empty
    }
    

    This will prevent it being picked up in Test1.

    EDIT Or if you have lots of inner configuration you can create your own annotation and filter all these annotated classes from your @ComponentScan:

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Configuration
    public @interface InnerConfiguration {
    }
    

    Then use this annotation on your inner classes instead of @Configuration:

    @InnerConfiguration
        static class CustomConfiguration {
            @Bean
            IService service() {
                return mock(IService.class);
            }
        }
    

    and filter these out of your component scan like this:

    @Configuration
    @ComponentScan(excludeFilters = {
         @ComponentScan.Filter(type = FilterType.ANNOTATION,
                               value = InnerConfiguration.class)
    })
    public class TestConfiguration {
       // empty
    }