Mockito UnfinishedStubbingException

2022-09-01 15:39:40

我是Mockito的新手,我尝试过研究这个例外,但我还没有找到具体的答案。当我同时使用两个模拟时,它发生在我的代码中,这意味着我通过一个模拟的构造函数,另一个模拟来给出。这样:

...
OperationNode child = getNode(Operation.ADD);
child.insertNode(getConstantNode(getIntegerValue(2));
...

 private ConstantNode getConstantNode(NumericalValue value){
    ConstantNode node = Mockito.mock(ConstantNode.class);
    Mockito.when(node.evaluate()).thenReturn(value);
    Mockito.when(node.toString()).thenReturn(value.toString());
    return node;
}

private IntegerValue getIntegerValue(int number) {
   IntegerValue integerValue = Mockito.mock(IntegerValue.class);
   Mockito.when(integerValue.getValue()).thenReturn(number);
   Mockito.when(integerValue.toString()).thenReturn(Integer.toString(number));
   return integerValue;
}

在其中一个论坛中,我读到关于不通过另一个模拟的构造函数发送模拟,因为Mockito可能会与模拟调用混淆,所以我尝试了以下方法:

NumericalValue value = getIntegerValue(2);
child.insertNode(getConstantNode(value));

但无济于事。我确保只调用方法 和,因为这些是该类具有的唯一方法。我不明白发生了什么。toString()getValue()

我还尝试单独使用模拟,看看我是否做错了什么:

child.insertNode(new ConstantNode(getIntegerValue(2)));

这很完美。

child.insertNode(getConstantNode(new IntegerValue(2)));

这也很好。


答案 1

从我在 mockito (https://code.google.com/p/mockito/issues/detail?id=53) 的 “Issue 53” 上读到的内容来看,由于 Mockito 中涉及的验证框架,我的代码遇到了问题。正是以下代码导致了异常本身。

private ConstantNode getConstantNode(NumericalValue value){
    ConstantNode node = Mockito.mock(ConstantNode.class);
    Mockito.when(node.evaluate()).thenReturn(value);
    Mockito.when(node.toString()).thenReturn(value.toString());
    return node;
}

如果你还记得我的代码,参数值也是一个MOCK,所以当被调用时,我相信(如果我错了,有人请纠正我)验证框架被触发,并确保每个“当”都有它的调用/验证/等。因此,如果发生这种情况,则不会验证,因为它尚未从 返回,从而启动了整个“验证所有内容”链。value.toString()thenReturn()thenReturn()Mockito.when(node.toString()).thenReturn(value.toString()valute.toString()

我如何修复它:

private ConstantNode getConstantNode(NumericalValue value){
    ConstantNode node = Mockito.mock(ConstantNode.class);
    Mockito.when(node.evaluate()).thenReturn(value);

    String numberToString = value.toString();

    Mockito.when(node.toString()).thenReturn(numberToString);
    return node;
}

这样,就可以对其进行验证。我发现这是一个完整的代码气味,因为我将不得不留下一个注释,解释为什么我在代码中使用一个看似无用的中间变量。

感谢您的帮助。


答案 2

这个问题中已经发布了一些很好的修复程序,但是对于仍然无法理解它的人来说,请考虑Java调用所有这些方法的顺序。根据 Java 语言规范,Java 在调用方法之前从左到右计算该方法的每个参数

  1. integerValue.getValue(),这是莫基托记录的
  2. when,其中 Mockito 接听最后一个呼叫 (to ) 并开始设置存根integer.getValue
  3. value.toString,这是Mockito记录的一个被嘲笑的电话
  4. thenReturn在残骸上

Mockito 抱怨的正是因为对 mock 的调用,步骤 3,发生在步骤 2 () 之后,但在步骤 4 () 之前,导致验证框架抱怨存根。喜悦,你的答案将麻烦的步骤3移到步骤1之前,这很好;Sajan将其从语句中完全删除,这也很好。whenthenReturn


推荐