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 object开发者_JAVA百科2;
}
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
The ReflectionTestUtils class in Spring might be helpful.
It seems to do what you are looking for...at least the injection part :-)
Mockito has a really powerful way of handling mocks and DI:
@RunWith(MockitoJUnitRunner.class)
public class Class1Test {
@Mock
private Interface2 inteface2mock;
@InjectMocks
private Class1 class1;
@Test
public void someTest() {
when(interface2mock.doSomething("arg")).thenReturn("result");
String actual = class1.doSomeThatDelegatesToInterface2();
assertEquals("result", actual);
}
}
Read more about @InjectMocks in the Mockito javadoc or in a blog post that I wrote about the topic some time ago.
Available as of Mockito 1.8.3, enhanced in 1.9.0.
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.com/2006/11/09/using-jmock-and-inject-object/
It describes how to use a mocked object in a spring context.
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 inappContext-test.xml
- A mock bean in
appContext-test.xml
must have the same ID as the corresponding bean inappContext-main.xml
- When the app runs only
appContext-main.xml
is loaded - When the tests run both
appContext-main.xml
andappContext-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.
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);
}
}
There is a JUnit Rule that gives EasyMock similar annotation-driven injection capabilities, in the manner of Mockito. See EasyMockRule
精彩评论