Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

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...

like image 210
vuk Avatar asked Sep 24 '14 11:09

vuk


People also ask

How do you make auto wiring as non mandatory for a specific bean property?

If you want to make specific bean autowiring non-mandatory for a specific bean property, use required=”false” attribute in @Autowired annotation.

How do you Excluding a bean from being available for Autowiring?

You can exclude a bean from autowiring in Spring framework per-bean basis. If you are using Spring XML configuration then you can exclude a bean from autowiring by setting the autowire-candidate attribute of the <bean/> element to false.

How do I stop Autowired?

You can just remove the @Autowired annotation from the constructor and it will still work (if you're not using a really old version of Spring).

How do I turn off Autowire in Spring?

To fix it, you can disable this checking feature by setting the “required” attribute of @Autowired to false. In the above example, if the Spring can't find a matching bean, it will leave the person property unset.


2 Answers

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

like image 87
Paweł Kaczorowski Avatar answered Sep 20 '22 14:09

Paweł Kaczorowski


I solved it by creating FactoryBean for my bean instead of just mocking bean. At this way Spring don't try to autowire fields.

Factory bean helping class:

public class MockitoFactoryBean<T> implements FactoryBean<T> {     private final Class<T> clazz;      public MockitoFactoryBean(Class<T> clazz) {         this.clazz = clazz;     }      @Override public T getObject() throws Exception {         return mock(clazz);     }      @Override public Class<T> getObjectType() {         return clazz;     }      @Override public boolean isSingleton() {         return true;     } } 

Actual test context part:

@Configuration public class TestContext {      @Bean     public FactoryBean<MockingService> mockingService() {         return new MockitoFactoryBean<>(MockingService.class);     } } 
like image 24
tr1cks Avatar answered Sep 22 '22 14:09

tr1cks