views:

332

answers:

4

I am using Spring annotations in my code to do the DI. So lets say I have a class class1 that depends on another class class2, I define class1 as below:

@Component
public class class1 {

@Resource
private interface2 object2;

}

class2 is an implementation of interface2.

Now lets say I want to mock class2 and pass it to class1, I dont see any constructor or setter in class1. I think Spring uses reflection to inject object2. How can I mock it? Should I add a setter in class1? Or can I reuse the same way spring is doing it - I mean does spring itself have a mock object framework or something, I was planning to use EasyMock for the mocking.

Thanks

A: 

AFAIK, there is no mocking framework built into Spring, so you need to use something like EasyMock. The way I have done this in the past is to

  • Define the Spring config using XML instead of annotations*
  • The config for the main app is defined in appContext-main.xml and the test config (the mock objects) is defined in appContext-test.xml
  • A mock bean in appContext-test.xml must have the same ID as the corresponding bean in appContext-main.xml
  • When the app runs only appContext-main.xml is loaded
  • When the tests run both appContext-main.xml and appContext-test.xml are loaded. Make sure that they are loaded in this order so that the mocks 'override' any beans of the same name

* You don't need to need to convert all your Spring configuration to XML to use this approach. Only those beans that have mock implementations or have mock implementations injected into them need to be changed. The others bean can continue to be defined with annotations.

Don
I want to have many mocks of the same class for various tests (lets say simulate throwing an exception or returning null, etc) so I am not sure if it is good to create that many xmls and keep overriding them.
Arvind
A: 

Injecting yourself via reflection is very easy, so you can avoid the setter method.

To do it yourself is like this:

    for (Field field : injectable.getClass().getDeclaredFields()) {
        MyAnnotation annotation = field.getAnnotation(MyAnnotation.class);
        if (annotation != null) {
            field.setAccessible(true);
            Object param = generateMockObject();
            field.set(injectable, param);
        }
    }
Yishai
+4  A: 

The ReflectionTestUtils (http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/test/util/ReflectionTestUtils.html#setField%28java.lang.Object,%20java.lang.String,%20java.lang.Object%29) class in Spring might also be helpful. It seems to do what you are looking for... at least the injection part :-)

cjstehno
I used this and it worked perfectly, thanks a lot :)
Arvind
Glad it helped... happy testing.
cjstehno
A: 

ReflectionTestUtils is the easiest to add the mock you want (we use JMock, but it does not really matter), drawback is that it is slightly brittle. If you rename the field, you must remember to change the test as well.

You can also use this: http://i-proving.ca/space/Technologies/Tapestry/Using+jMock+and+Inject-Object

It describes how to use a mocked object in a spring context.

festerwim