我直到今天才开始了解Mockito。我写了一些简单的测试(使用JUnit,请参见下文),但是我不知道如何在Spring的托管bean中使用模拟对象。什么是使用Spring的最佳实践。我应该如何向我的bean注入模拟依赖项?
您可以跳过这一步,直到回到我的问题。
首先,我学到了什么。这是一篇很好的文章Mocks Are n't Stubs,它解释了基础知识(Mock的检查行为验证而不是状态验证)。然后在这里有一个很好的例子Mockito 和这里更容易用嘲笑嘲笑。我们必须解释是的Mockito的模拟对象都是模拟和存根。
这个测试
@Test
public void testReal(){
List<String> mockedList = mock(List.class);
//stubbing
//when(mockedList.get(0)).thenReturn("first");
mockedList.get(anyInt());
OngoingStubbing<String> stub= when(null);
stub.thenReturn("first");
//String res = mockedList.get(0);
//System.out.println(res);
//you can also verify using argument matcher
//verify(mockedList).get(anyInt());
verify(mockedList);
mockedList.get(anyInt());
}
效果很好。
回到我的问题。这里有人将Mockito模拟注入Spring Bean中,有人尝试使用Springs ReflectionTestUtils.setField()
,但是这里我们建议使用Spring Integration Tests,创建Mock对象来更改Spring的上下文。
我不太了解最后两个链接...有人可以向我解释Spring对Mockito有什么问题吗?这个解决方案怎么了?
@InjectMocks
private MyTestObject testObject
@Mock
private MyDependentObject mockedObject
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
https://stackoverflow.com/a/8742745/1137529
编辑:我不是很清楚。我将提供3个代码示例来说明我自己:假设,我们有带方法的bean HelloWorld和带方法的printHello()
bean HelloFacade,sayHello
它们将调用转发给HelloWorld的method printHello()
。
第一个示例是使用Spring的上下文且没有自定义运行器,将ReflectionTestUtils用于依赖项注入(DI):
public class Hello1Test {
private ApplicationContext ctx;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
this.ctx = new ClassPathXmlApplicationContext("META-INF/spring/ServicesImplContext.xml");
}
@Test
public void testHelloFacade() {
HelloFacade obj = (HelloFacade) ctx.getBean(HelloFacadeImpl.class);
HelloWorld mock = mock(HelloWorld.class);
doNothing().when(mock).printHello();
ReflectionTestUtils.setField(obj, "hello", mock);
obj.sayHello();
verify(mock, times(1)).printHello();
}
}
正如@Noam指出的那样,有一种方法无需显式调用即可运行它MockitoAnnotations.initMocks(this);
。我还将在此示例中使用Spring的上下文。
@RunWith(MockitoJUnitRunner.class)
public class Hello1aTest {
@InjectMocks
private HelloFacade obj = new HelloFacadeImpl();
@Mock
private HelloWorld mock;
@Test
public void testHelloFacade() {
doNothing().when(mock).printHello();
obj.sayHello();
}
}
另一种方法
public class Hello1aTest {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@InjectMocks
private HelloFacadeImpl obj;
@Mock
private HelloWorld mock;
@Test
public void testHelloFacade() {
doNothing().when(mock).printHello();
obj.sayHello();
}
}
没什么,在前面的示例中,我们必须手动实例化HelloFacadeImpl并将其分配给HelloFacade,因为HelloFacade是接口。在最后一个示例中,我们只需要声明HelloFacadeImpl即可,Mokito将为我们实例化它。这种方法的缺点是,现在,被测单元是impl类,而不是接口。
@InjectMocks
(相对较新,尽管IIRC在该博客文章之前),因此在某些情况下可能需要重新排序Bean定义。我不确定问题到底是什么。