使用Mockito,如何验证我的lambda表达式被调用?

use*_*471 6 java mockito java-8

我正在尝试测试一个带Consumer函数的方法,我想用Mockito验证我的lambda表达式只被调用一次.我现在使用的是在最终的单元素数组上使用标志的那种笨重方式:

final boolean[] handlerExecuted = {false};
instance.conditionalRun(item -> {
  handlerExecuted[0] = true;
  item.foo();
});

Assert.assertTrue(
    "Handler should be executed.",
    handlerExecuted[0]);
Run Code Online (Sandbox Code Playgroud)

看起来应该有更好的方法(或许是Mockito间谍)来验证这个lambda表达式只被调用一次.

use*_*471 6

其他一些答案提供了完全按照我的要求做出选择的替代方法,但这可以通过Consumer窥探类本身并让间谍调用你真正想要执行的方法来实现.包裹lambda以创建间谍的辅助方法有助于:

/** Get a spied version of the given Consumer. */
private Consumer<Item> itemHandlerSpy(Consumer<Item> itemHandler) {
  // Create a spy of the Consumer functional interface itself.
  @SuppressWarnings("unchecked")
  Consumer<Item> spy = (Consumer<Item>) Mockito.spy(Consumer.class);
  // Tell the spy to run the given consumer when the Consumer is given something to consume. 
  Mockito.doAnswer(it -> {
    // Get the first (and only) argument passed to the Consumer.
    Item item = (Item) it.getArguments()[0];
    // Pass it to the real consumer so it gets processed.
    itemHandler.accept(item);
    return null;
  }).when(spy).accept(Mockito.any(Item.class));
  return spy;
}
Run Code Online (Sandbox Code Playgroud)

然后测试方法变得非常简单:

Consumer<Item> itemHandler = itemHandlerSpy(Item::foo);
instance.conditionalRun(itemHandler);
// This verifies conditionalRun called the Consumer exactly once.
Mockito.verify(itemHandler).accept(Mockito.any(Item.class));
Run Code Online (Sandbox Code Playgroud)