我今天才开始了解 Mockito。我写了一些简单的测试(使用 JUnit,见下文),但我不知道如何在 Spring 的托管 bean 中使用模拟对象。使用 Spring的最佳实践是什么。我应该如何向我的 bean 注入模拟依赖项?
你可以跳过这个直到回到我的问题。
首先,我学到了什么。这是一篇很好的文章Mocks Aren't Stubs解释了基础知识(Mock 的检查行为验证而不是状态验证)。然后这里有一个很好的例子Mockito 和这里Easier mocking with mockito。我们解释说 Mockito 的模拟对象既是mock又是stub。
这里Mockito和这里Matchers,你可以找到更多的例子。
本次测试
@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());
}
工作得很好。
回到我的问题。在这里Injecting Mockito mocks into a Spring bean有人尝试使用 Springs ReflectionTestUtils.setField()
,但是在这里Spring Integration Tests, Creating Mock Objects我们建议更改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和带有将调用转发到 HelloWorld 方法的方法的printHello()
bean HelloFacade 。sayHello
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-class 而不是接口。