Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 524 Vote(s) - 3.42 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Injecting Mockito mocks into a Spring bean

#1
I would like to inject a Mockito mock object into a Spring (3+) bean for the purposes of unit testing with JUnit. My bean dependencies are currently injected by using the `@Autowired` annotation on private member fields.

I have considered using `ReflectionTestUtils.setField` but the bean instance that I wish to inject is actually a proxy and hence does not declare the private member fields of the target class. I do not wish to create a public setter to the dependency as I will then be modifying my interface purely for the purposes of testing.

I have followed some [advice][1] given by the Spring community but the mock does not get created and the auto-wiring fails:

<bean id="dao" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="com.package.Dao" />
</bean>

The error I currently encounter is as follows:

...
Caused by: org...NoSuchBeanDefinitionException:
No matching bean of type [com.package.Dao] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for this dependency.
Dependency annotations: {
@org...Autowired(required=true),
@org...Qualifier(value=dao)
}
at org...DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(D...y.java:901)
at org...DefaultListableBeanFactory.doResolveDependency(D...y.java:770)
If I set the `constructor-arg` value to something invalid no error occurs when starting the application context.

[1]:

[To see links please register here]

Reply

#2
Perhaps not the perfect solution, but I tend not to use spring to do DI for unit tests. the dependencies for a single bean (the class under test) usually aren't overly complex so I just do the injection directly in the test code.
Reply

#3
Today I found out that a spring context where I declared a <import> before the Mockito beans, was failing to load.
After moving the <import> AFTER the mocks, the app context was loaded successfully.
Take care :)
Reply

#4
**Update:** There are now better, cleaner solutions to this problem. Please consider the other answers first.

I eventually found an answer to this by ronen on his blog. The problem I was having is due to the method `Mockito.mock(Class c)` declaring a return type of `Object`. Consequently Spring is unable to infer the bean type from the factory method return type.

[Ronen's solution][1] is to create a `FactoryBean` implementation that returns mocks. The `FactoryBean` interface allows Spring to query the type of objects created by the factory bean.

My mocked bean definition now looks like:

<bean id="mockDaoFactory" name="dao" class="com.package.test.MocksFactory">
<property name="type" value="com.package.Dao" />
</bean>


[1]:

[To see links please register here]

Reply

#5
I found a similar answer as teabot to create a MockFactory that provides the mocks. I used the following example to create the mock factory (since the link to narkisr are dead):

[To see links please register here]


<bean id="someFacade" class="nl.package.test.MockFactory">
<property name="type" value="nl.package.someFacade"/>
</bean>

This also helps to prevent that Spring wants to resolve the injections from the mocked bean.
Reply

#6
I have a very simple solution using Spring Java Config and Mockito:

@Configuration
public class TestConfig {

@Mock BeanA beanA;
@Mock BeanB beanB;

public TestConfig() {
MockitoAnnotations.initMocks(this); //This is a key
}

//You basically generate getters and add @Bean annotation everywhere
@Bean
public BeanA getBeanA() {
return beanA;
}

@Bean
public BeanB getBeanB() {
return beanB;
}
}
Reply

#7
Posting a few examples based on the above approaches

With Spring:

@ContextConfiguration(locations = { "classpath:context.xml" })
@RunWith(SpringJUnit4ClassRunner.class)
public class TestServiceTest {
@InjectMocks
private TestService testService;
@Mock
private TestService2 testService2;
}

Without Spring:

@RunWith(MockitoJUnitRunner.class)
public class TestServiceTest {
@InjectMocks
private TestService testService = new TestServiceImpl();
@Mock
private TestService2 testService2;
}
Reply

#8
<bean id="mockDaoFactory" name="dao" class="com.package.test.MocksFactory">
<property name="type" value="com.package.Dao" />
</bean>

this ^ works perfectly well if declared first/early in the XML file. Mockito 1.9.0/Spring 3.0.5
Reply

#9
For the record, all my tests correctly work by just making the fixture lazy-initialized, e.g.:

<bean id="fixture"
class="it.tidalwave.northernwind.rca.embeddedserver.impl.DefaultEmbeddedServer"
lazy-init="true" /> <!-- To solve Mockito + Spring problems -->

<bean class="it.tidalwave.messagebus.aspect.spring.MessageBusAdapterFactory" />

<bean id="applicationMessageBus"
class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="it.tidalwave.messagebus.MessageBus" />
</bean>

<bean class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="javax.servlet.ServletContext" />
</bean>


I suppose the rationale is the one Mattias explains [here][1] (at the bottom of the post), that a workaround is changing the order the beans are declared - lazy initialization is "sort of" having the fixture declared at the end.


[1]:

[To see links please register here]

Reply

#10
The best way is:

<bean id="dao" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="com.package.Dao" />
</bean>

**Update**<br/>
In the context file this mock must be listed before any autowired field depending on it is declared.
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through