简体   繁体   中英

Is there a way to prevent dependency injection from config in Spring?

I am working on a Spring project where the unit tests have their own config called UnitTestConfig which has several beans defined similar to the main application file (almost a replica). Keeping the structure intact, i am making some changes in main application server code, however this throws error in UnitTestConfig, because it doesnt have the required beans for injection. These beans are not used in Unit tests, is there a way I can prevent UnitTestConfig from trying to inject those? Its a big casacade effect, since A injects, B injects C, and so on, and it is expecting all those Beans. Any way I can tell Spring config that i dont want to inject those beans or have them as null ?

@Configuration
public class UnitTestConfig {

    @Inject
    private Environment env;

    @Bean
    public A a() {
        return new A();
    }

In order to not inject A's fields when required, i added a @Lazy over the field and it seemed to work, but I would prefer any modifications for this to be on the test config side, and not modify main application code just to fix test issues. Any suggestions?

This is a very common problem with most of the applications and as application grow, it becomes difficult to add unit tests having common configuration. And running a unit test becomes a nightmare as you have to take care of unnecessary context loading.

We eventually started having test profiles, to work-around the problem of having unnecessary beans being loaded. And loading beans only for certain profiles. Something like this-

How can I disable creating bean with @Component annotation in Spring?

But this can create its own issues - creation of multiple profiles and management of those profiles. This can help you though if managing profiles is not an issue.

Alternatively, we stopped using a common context for unit testing and started testing classes in isolation with a static test context class and mocking all non-required beans. Something like this -

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
public class SomeJavaClassTest {

    @Autowired
    private Bean1 bean1;
    @Autowired
    private Bean2 bean2;
    @Autowired
    private Bean3 bean3;
    
    @test
    public void method1Test() throws Exception {
    }
    
    @test
    public void method2Test() throws Exception {
    }
    
    @Configuration
    static class Config {
    
        @Bean
        public Bean1 bean1() {
            return Mockito.mock(Bean1.class);
        }

        @Bean
        public Bean2 bean2() {
            return new SomeJavaClass();
        }
        
        @Bean
        public Bean3 bean3() {
            return Mockito.mock(Bean3.class);
        }
    
        @Bean
        public PropertySourcesPlaceholderConfigurer properties() throws Exception {
            PropertySourcesPlaceholderConfigurer propertyPlaceholder = new PropertySourcesPlaceholderConfigurer();

            // setup properties that needs to be injected into the class under test

            Properties properties = new Properties();
            properties.setProperty("some.required.properties", "");
            
            propertyPlaceholder.setProperties(properties);

            return propertyPlaceholder;
    }
}

This is called cyclic bean dependency. There are many ways to resolve this issue. Annotate with @Lazy in constructor parameter. Instead of constructor injector use setter injection or In application.properties file write spring.main.allow-bean-definition-overriding=true

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM