我正在使用Mockito来测试我的 class 。我尝试使用Deep存根,因为我没有办法在Mockito的另一个模拟对象内注入Mock。
class MyService{
@Resource
SomeHelper somehelper;
public void create()
{
//....
somehelper.invokeMeth(t);
}
}
class SomeHelper{
@Resource
private WebServiceTemplate webServiceTemplate;
public void invokeMeth(T t)
{
try{
//...
webServiceTemplate.marshalSendAndReceive(t);
}catch (final WebServiceIOException e) {
throw new MyAppException("Service not running");
}
}
}
现在,我试图对MyService类的create()方法进行单元测试。
我为SomeHelper注入了一个模拟,如下所示
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
SomeHelper somehelper;
我现在想要的是在模拟的somehelper对象上调用invokeMeth()方法时,在这种情况下它将调用real方法。
when(somehelper.invokeMeth(isA(RequestObject.class)))
.thenCallRealMethod();
在这种情况下,我期望webServiceTemplate不为null。
但是,当代码尝试执行该行时,我得到了一个Nullpointer异常
webServiceTemplate.marshalSendAndReceive(t);
有什么线索可以访问深层模拟对象(即模拟中的模拟-在这种情况下为somehelper模拟中的webserviceTemplete模拟),然后应用when条件抛出WebserviceIOException吗?
我想要这样做,以便可以测试MyService.create()来检查当WebServiceIOException抛出代码时它的行为是否正确。
最佳答案
是的,当然,您正在混合真实对象和模拟对象。加上像部分模拟一样使用thenCallRealMethod
lloks,在这里感觉很不对劲,也就怪怪javadoc of this method也谈到了这一点。
与设计明智地相比,我的最终确定应该给您带来压力,拥有返回模拟的模拟通常是一种气味。更准确地说,您违反了 Demeter律,或者不遵循告诉,不要问原则。
任何查看您的代码的人都不会理解为什么该代码需要模拟WebServiceTemplate
。您想对MyService
进行单元测试,但我看不到WebServiceTemplate
的关系。相反,您应该只专注于与助手的交互。然后分别对SomeHelper
进行单元测试,在这里您可以检查SomeHelper
和WebServiceTemplate
之间的交互。
这是我如何看待事物的一个小例子:
public void ensure_helper_is_used_to_invoke_a_RequestObject() {
// given a service that has an helper collaborator
... other fixture if necessary
// when
myService.behaviorToTest();
// then
verify(someHelperMock).invokeMeth(isA(RequestObject.class));
}
那些如何寻找您的实际用例?
希望有帮助