25

我是 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)));

这也很好。

4

4 回答 4

31

根据我在 mockito ( https://code.google.com/p/mockito/issues/detail?id=53 ) 的“问题 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;
}

这样,它可以被验证。我发现这是一种完整的代码异味,因为我将不得不留下一条注释来解释为什么我在代码中使用了一个看似无用的中间变量。

谢谢您的帮助。

于 2013-03-21T23:37:42.033 回答
9

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

  1. integerValue.getValue(), Mockito 记录的
  2. when, Mockito 接受最后一次调用 (to integer.getValue) 并开始设置存根
  3. value.toString,这是 Mockito 记录的模拟调用
  4. thenReturn在树桩上

Mockito 抱怨正是因为对模拟的调用,步骤 3,发生步骤 2 ( when) 之后但步骤 4 ( thenReturn) 之前,导致验证框架抱怨存根。乔伊,您的回答将麻烦的步骤 3 移到步骤 1 之前,这很好;Sajan 将其从语句中完全删除,这也很好。

于 2013-03-22T02:22:21.437 回答
2

我认为问题在于线路

Mockito.when(node.toString()).thenReturn(value.toString());在方法中getConstantNode

尝试删除该行并检查它是否有效。也许你可以做类似的事情

int num = 2;
child.insertNode(getConstantNode(getIntegerValue(num), num);
...

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

private IntegerValue getIntegerValue(int number) {
   IntegerValue integerValue = Mockito.mock(IntegerValue.class);
   Mockito.when(integerValue.getValue()).thenReturn(number);
   return integerValue;
}
于 2013-03-21T18:02:40.640 回答
0

我认为这是调用顺序和 Mockito 框架验证的问题。试试这个,看看它是否有帮助:

...
OperationNode child = getNode(Operation.ADD);
IntegerValue value = getIntegerValue(2);
ConstantNode node =  Mockito.mock(ConstantNode.class);
Mockito.when(node.evaluate()).thenReturn(value);
Mockito.when(node.toString()).thenReturn(value.toString());
child.insertNode(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;
}

来源:https ://code.google.com/p/mockito/issues/detail?id=53

于 2013-03-21T17:39:07.153 回答