3

我正在使用 Mockito 来测试我的课程。我正在尝试使用深度存根,因为我没有办法将 Mock 注入 Mockito 中的另一个模拟对象中。

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() 方法时,它在这种情况下调用真正的方法。

when(somehelper.invokeMeth(isA(RequestObject.class)))
    .thenCallRealMethod();

在这种情况下,我期望 webServiceTemplate 不为空。

但是,当代码尝试执行该行时,我得到一个 Nullpointer 异常

webServiceTemplate.marshalSendAndReceive(t);

任何线索我如何可以访问一个深度模拟对象(即模拟中的模拟 - 在这种情况下是 somehelper 模拟中的 webserviceTemplete 模拟)然后应用一个 when 条件来抛出一个 WebserviceIOException ?我想要这个,以便我可以测试 MyService.create() 以检查当 WebServiceIOException 被抛出代码时它的行为是否正确。

4

1 回答 1

4

是的,当然,您正在混合真实对象和模拟。加上thenCallRealMethod像部分模拟一样使用lloks,这里感觉不对,难怪这个方法的javadoc也谈到了这一点。

我肯定应该强调你,而不是设计明智的,有一个返回模拟的模拟通常是一种气味。更准确地说,您违反了得墨忒耳定律,或者没有遵循“告诉,不问”的原则。

任何看你的代码我都不知道为什么代码需要 mock 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));
}

那些寻找你真正用例的人怎么样?

希望有帮助

于 2012-11-21T19:07:41.147 回答