How to disable Spring autowiring in unit tests for @Configuration/@Bean usage

vuk picture vuk · Sep 24, 2014 · Viewed 18.2k times · Source

I want configure a component test using spring-test configuration inner class (@Configuration). Tested components has some services which I'd like to mock for the test. These services are classes (no interface used) and have spring annotations (@Autowired) in them. Mockito can easily mock them, however, I found no way of disabling spring autowiring.

Example how I can easily reproduce:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SomeTest.Beans.class)
public class SomeTest {

    // configured in component-config.xml, using ThirdPartyService
    @Autowired
    private TestedBean entryPoint;

    @Test
    public void test() {
    }

    @Configuration
    @ImportResource("/spring/component-config.xml")
    static class Beans {
        @Bean
        ThirdPartyService createThirdPartyService() {
            return mock(ThirdPartyService.class);
        }
    }
}

public class ThirdPartyService {
    @Autowired
    Foo bar;
}

public class TestedBean {
    @Autowired
    private ThirdPartyService service;
}

In this example "TestBean" represents the service to be mocked. I would NOT like "bar" to be injected by spring! @Bean(autowire = NO) does not help (in fact, that's the default value). (Please save me from "use interfaces!" comments - the mocked service can be 3rd party which I can't do anything with.)

UPDATE

Springockito partially solves the problem, as long as you don't have to have anything else to configure (so you can't use configuration class with Springockito - it does not support it), but use mocks only. Still looking for pure spring solution, if there's any...

Answer

Paweł Kaczorowski picture Paweł Kaczorowski · Oct 16, 2015

Here is my solution to your problem:

import static org.mockito.Mockito.mockingDetails;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MockitoSkipAutowireConfiguration {

@Bean MockBeanFactory mockBeanFactory() {
    return new MockBeanFactory();
}

private static class MockBeanFactory extends InstantiationAwareBeanPostProcessorAdapter {
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        return !mockingDetails(bean).isMock();
    }
}

} 

and then just

@Import(MockitoSkipAutowireConfiguration.class)

in your test @Configuration and you are all set