Sha*_*awn 5 unit-testing mocking mockito
我最近看到一些像这样工作的Mockito 1.9.5代码:
MyObject myObject = new MyObject();
...
Mockito.when(myObject.someMethod()).thenReturn("bogus");
Run Code Online (Sandbox Code Playgroud)
由于myObject 不是一个模拟对象,而是一个非模拟类的实例,我很惊讶这个编译并运行而不会失败单元测试.我预计我会失败说"你让我对非模拟对象设置期望,我希望只对模拟对象设置期望."
为什么这段代码不会导致测试失败?
更新:添加更多代码来实际复制我发现令人困惑的行为.这些例子充分说明了我的问题.以下代码的行为与我预期的一样 - 当我运行此测试时,测试失败并显示一条消息
when()需要一个必须是'对mock进行方法调用'的参数.
public class AnotherObject{
public String doSomething(){
return "did something";
};
}
public class MyObject{
private AnotherObject anotherObject = new AnotherObject();
public void setAnotherObject(AnotherObject anotherObject) {
this.anotherObject = anotherObject;
}
public String someMethod(){
return anotherObject.doSomething();
}
}
@Test
public void WhyDoesWhenWorkOnNonMock() throws Exception {
MyObject myObject = new MyObject();
Mockito.when(myObject.someMethod()).thenReturn("bogus");
}
Run Code Online (Sandbox Code Playgroud)
现在,如果我为这个人为的测试添加一些特定的行,那么即使我期望与以前相同的失败和相同的消息,测试也不会失败:
public class AnotherObject{
public String doSomething(){
return "did something";
};
}
public class MyObject{
private AnotherObject anotherObject = new AnotherObject();
public void setAnotherObject(AnotherObject anotherObject) {
this.anotherObject = anotherObject;
}
public String someMethod(){
return anotherObject.doSomething();
}
}
@Test
public void WhyDoesWhenWorkOnNonMock() throws Exception {
MyObject myObject = new MyObject();
AnotherObject mockAnotherObject = Mockito.mock(AnotherObject.class);
myObject.setAnotherObject(mockAnotherObject);
Mockito.when(myObject.someMethod()).thenReturn("bogus");
}
Run Code Online (Sandbox Code Playgroud)
Jef*_*ica 13
通过令人难以置信和脆弱的巧合,可能,除非myObject实际上被设定为间谍.
Mockito允许创建一个真实对象的"间谍":
MyObject myObject = spy(new MyObject());
Mockito.when(myObject.someMethod()).thenReturn("something");
// myObject is actually a duplicate of myObject, where all the fields are copied
// and the methods overridden. By default, Mockito silently records interactions.
myObject.foo(1);
verify(myObject).foo(anyInt());
// You can stub in a similar way, though doReturn is preferred over thenReturn
// to avoid calling the actual method in question.
doReturn(42).when(myObject).bar();
assertEquals(42, myObject.bar());
Run Code Online (Sandbox Code Playgroud)
除此之外,这段代码可能不像它应该的那样工作.when的参数是没有意义的,并且糖意味着隐藏模拟的交互是对模拟的最新方法调用.例如:
SomeObject thisIsAMock = mock(SomeObject.class);
OtherObject notAMock = new OtherObject();
thisIsAMock.methodOne();
Mockito.when(notAMock.someOtherMethod()).thenReturn("bar");
// Because notAMock isn't a mock, Mockito can't see it, so the stubbed interaction
// is the call to methodOne above. Now methodOne will try to return "bar",
// even if it isn't supposed to return a String at all!
Run Code Online (Sandbox Code Playgroud)
像这样的不匹配可能是ClassCastException,InvalidUseOfMatchersException和其他奇怪错误的简单来源.您的真实MyObject类也可能将mock作为参数,并且最后一次交互是与与之交互的模拟someMethod.
你的编辑证实了我的怀疑.就Java而言,它需要when在它可以调用之前评估参数when,因此您的测试调用someMethod(实际).Mockito看不到它 - 它只能在你与其中一个模拟器进行交互时采取行动 - 所以在你的第一个例子中,它看到与模拟的零交互,因此它失败了.在你的第二个例子中,你的someMethod调用doSomething是Mockito 可以看到的,所以它返回默认值(null)并将其标记为最近的方法调用.然后调用when(null)发生,Mockito忽略参数(null)并引用最近调用的方法(doSomething),以及从那一点返回"bogus"的存根.
您可以通过将此断言添加到测试中来查看,即使您从未明确地将其断言:
assertEquals("bogus", mockAnotherObject.doSomething());
Run Code Online (Sandbox Code Playgroud)
为了进一步参考,我在Mockito匹配器上写了一个单独的SO答案,其实现细节可能很有用.有关类似问题的扩展视图,请参阅步骤5和6.
| 归档时间: |
|
| 查看次数: |
5642 次 |
| 最近记录: |