【问题标题】:Error: a *different* void method cannot be stubbed with a return value错误:*不同* void 方法不能用返回值存根
【发布时间】:2016-02-12 23:20:06
【问题描述】:

当存根ClassOne.methodOne 时,我收到以下关于用返回值存根无效方法的错误消息,即使ClassOne.methodOne 不是无效的。该错误似乎与ClassTwo.methodTwo 相关,即使我正在存根ClassOne.methodOne。

org.mockito.exceptions.base.MockitoException: 
`'methodTwo'` is a *void method* and it *cannot* be stubbed with a *return value*!
Voids are usually stubbed with Throwables:
    doThrow(exception).when(mock).someVoidMethod();
***

If you're unsure why you're getting above error read on.
Due to the nature of the syntax above problem might occur because:
1. The method you are trying to stub is *overloaded*. Make sure you are calling
   the right overloaded version.
2. Somewhere in your test you are stubbing *final methods*. Sorry, Mockito does not
   verify/stub final methods.
3. A spy is stubbed using `when(spy.foo()).then()` syntax. It is safer to stub
   spies with `doReturn|Throw()` family of methods. More in javadocs for
   Mockito.spy() method.

我的代码:

public class ClassOne {
  private ClassTwo classTwo;

  public boolean methodOne() {
    classTwo.methodTwo();
    return true;
  }
}

我的测试:

when(classOne.methodOne("some string")).thenReturn(true);

为什么会发生这种情况,我该如何解决?

【问题讨论】:

    标签: java mockito


    【解决方案1】:

    当您尝试存根 Mockito 无法覆盖的方法时,可能会发生这种情况。when 的语法工作方式是,Mockito 识别它可以检测到的最新调用 作为对存根的方法调用。如果 Mockito 无法检测到您正在存根的方法调用,但可以检测到在存根方法的实际实现中发生的模拟调用,那么它可能会将该调用误认为是存根调用。因此,它认为您正在使用返回值对 void 方法 ClassTwo.methodTwo 进行存根,并抛出异常。

    /* 1 */  when(classOne.methodOne("some string")).thenReturn(true);
    /* 2 */  when(              false              ).thenReturn(true);
    /* 3 */  (    internal mockito stub object     ).thenReturn(true);
    

    通常,Mockito 调用classOne.methodOne,这是一个模拟上的未存根方法。 Mockito 的默认实现检测到调用,将调用记录为最后收到的调用,并返回 false。然后,在上面的第 2 步中,Mockito 看到对when 的调用,将最后一次调用标记为存根,并准备对第 3 步中的thenVerb 的调用。但是,在这种情况下,在第一步中,Mockito 没有覆盖methodOne,因此它无法检测到调用或记录调用。它实际上调用了classOne.methodOne,如果与模拟有任何交互,则将它们记录下来,就像它们在when 调用上方的测试中一样。步骤 2 像以前一样继续,除了 Mockito 标记了对存根的错误调用,因此步骤 3 看到对 void 方法的 thenReturn 调用。

    如果您使用 Matchers,这可能会更加麻烦,因为如果 internal matcher stack 上的 Matchers 数量错误,那么您可能会收到 InvalidUseOfMatchersException,即使测试中的存根调用似乎正确使用了匹配器。


    当 Mockito 无法覆盖您正在存根的方法时,就会出现此问题。您需要检查以下是否全部正确:

    • 类应该是非final,并且不应该有non-public parents。
    • 方法应该是非static和非final。
    • 实例应该是一个 Mockito 模拟。请注意,如果它是用@InjectMocks 创建的,它是一个真正的实现,而不是一个模拟; read more here。
    • 如异常中所述,当存根间谍时,use doReturn/doAnswer/doThrow syntax,否则您将在对 when 的调用中调用间谍的实际方法。

    【讨论】:

    • 为什么 Mockito 不能覆盖 methodOne?问题中的问题是由@InjectMocks引起的吗?查看您的清单,ClassOne 是非最终的并且没有父级(Object 除外),methodOne 是非静态且非最终的。所以剩下的唯一两个可以解释这个问题的项目是@InjectMocks 和 stubbing 间谍。这个问题似乎没有说明模拟是如何创建的。
    • @aro_tech:这个问题是对another recent Mockito question 的概括,其目标是将规范的问题/答案对作为欺骗目标。根据问题中列出的确切代码,InjectMocks 可能是原始链接问题中的原因,但误导性错误可能来自答案中列出的任何原因。
    • 这帮助我解决了间歇性模拟失败的问题。被测类调用了SwingUtilities.invokeLater,其runnable 调用了另一个失败的模拟方法。
    猜你喜欢
    • 2015-10-03
    • 1970-01-01
    • 2015-04-30
    • 1970-01-01
    • 2012-10-28
    • 1970-01-01
    • 2015-11-25
    • 2021-09-15
    • 2020-09-30
    相关资源
    最近更新 更多