首页 > 解决方案 > 使用 Mockito.inOrder 验证模拟方法是否按确切顺序调用

问题描述

我正在尝试测试是否按预期顺序调用模拟对象的方法。下面是简化的例子:

@Test
public void test() {
    List<String> mockedList = Mockito.mock(List.class);

    for (int i = 0; i < 5; i++) {
        mockedList.add("a");
        mockedList.add("b");
        mockedList.add("c");
    }

    // I want only this to pass.
    InOrder inOrder1 = Mockito.inOrder(mockedList);
    inOrder1.verify(mockedList).add("a");
    inOrder1.verify(mockedList).add("b");
    inOrder1.verify(mockedList).add("c");

    // I want this to fail.
    InOrder inOrder2 = Mockito.inOrder(mockedList);
    inOrder2.verify(mockedList).add("c");
    inOrder2.verify(mockedList).add("b");
    inOrder2.verify(mockedList).add("a");
}

尽管验证顺序 ( c -> b -> a) 与调用顺序 ( a -> b -> c) 不同,但此测试通过。这是因为 Mockito 验证方法 2 是否在方法 1 之后的任何地方调用,但不是立即调用(即,两者之间没有调用其他方法)。由于我多次添加元素,这很有可能。这意味着,Mockito InOrder 通过b -> a -> c -> a -> c -> b -> c -> b -> a ...

但我希望这失败,并确保订单始终a -> b -> c -> a -> b -> c -> a -> b -> c ...

更新:验证的正确方法是验证相同数量的迭代顺序(接受答案的摘要)

for (int i = 0; i < 5; i++) {
    inOrder1.verify(mockedList).add("a");
    inOrder1.verify(mockedList).add("b");
    inOrder1.verify(mockedList).add("c");
}

// fail the test if we missed to verify any other invocations
inOrder1.verifyNoMoreInteractions();

标签: javaunit-testingmockingmockito

解决方案


问题是你需要添加

inOrder.verifyNoMoreInteractions();

使用您的循环,您可以生成类似的调用

  • 添加(一)
  • 添加(b)
  • 添加(c)
  • 添加(一)
  • 添加(b)
  • 添加(c)

当你然后检查

inOrder.verify(mockedList).add("b");
inOrder.verify(mockedList).add("c");
inOrder.verify(mockedList).add("a");

它匹配调用 (add(b), add(c), add(a))。不检查其他呼叫。

  • 添加(一)
  • 添加(b)
  • 添加(c)
  • 添加(一)
  • 添加(b)
  • 添加(c)

所以我认为你必须选择:1)验证所有调用 a、b、c、a、b、c 2)验证你的模拟没有更多的交互发生

顺便说一句,如果您将验证更改为

inOrder.verify(mockedList).add("c");
inOrder.verify(mockedList).add("b");
inOrder.verify(mockedList).add("a");

它将失败,因为它与调用不匹配:-)


推荐阅读