views:

2135

answers:

5

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

A: 

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.

Angelo Genovese
I understand your approach. However, I find myself in this situation on a large legacy code base that doesn't easily allow for this - yet.
teabot
I have found the Mockito/Spring combo to be very useful when I need to test code that depends heavily on Spring aspects/AOP (for instance, when testing spring security rules). Although one is perfectly justified in claiming that such tests should be a integration test.
Lars Tackmann
@Lars - agreed - the same could be said of the tests I am dealing with.
teabot
+4  A: 

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 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>
teabot
Updated link to Ronen's Solution: http://narkisr.com/blog/2008/2647754885089732945
Jeff Martin
+1  A: 

I can do the following using Mockito --

<bean id="stateMachine" class="org.mockito.Mockito" factory-method="mock"> <constructor-arg value="com.abcd.StateMachine"/> </bean>

With Regards, A

Alexander
Thanks for the answer @Alexander. May I ask: does it wire-up correctly? If so which versions of Spring/Mockito are you using?
teabot
+1  A: 

The best way is:

<bean id="dao" class="org.mockito.Mockito" factory-method="mock"> 
    <constructor-arg value="com.package.Dao" /> 
</bean> 
amra
I get an error: "Error creating bean with name 'mockito': bean definition is abstract"
tttppp
I updated the code. Try it now!
amra
A: 

Looks like the link to blog post you refer to in your answer has changed to http://narkisr.com/blog/2008/2647754885089732945

Cheers, Jim

Jim Bethancourt