java Mockito 验证特定的 lambda 已作为模拟方法中的参数传递

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/41462913/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 05:54:07  来源:igfitidea点击:

Mockito verify that a specific lambda has been passed as an argument in mock's method

javalambdamockito

提问by JavaSloth

I want to test the following method:

我想测试以下方法:

    public void dispatchMessage(MessageHandler handler, String argument1, String argument2, Long argument3) {

    handler.registerMessage(() -> {
        dispatcher.dispatch(argument1,
                argument2,
                argument3);
    });

}

Where MessageHandleris a helper class which will accept a Functional Interface implementation in the form a lambda, and store it for later execution.

哪里MessageHandler是一个辅助类,它将接受 lambda 形式的功能接口实现,并将其存储以供以后执行。

Is there a way to verify with mockito that the dispatchMessagemethod of the mocked MessageHandlerhas been called with the specific lambda expression:

有没有办法用 mockito 验证模拟的dispatchMessage方法MessageHandler是否已使用特定的 lambda 表达式调用:

Meaning, can I write such a test:

意思是,我可以写这样一个测试:

        @Test
public void testDispatchMessage_Success() throws Exception {

    myMessageDispatcher.dispatchMessage(handler, "activityId", "ctxId", 1l, );

    verify(handler, times(1)).dispatchMessage(() -> {
        dispatcher
            .dispatch("activityId", "ctxId", 1l,);
    });

}

}

This test will result in assertion error: Argument(s) are different! Wanted:

此测试将导致断言错误:Argument(s) is different!通缉:

......Tests$$Lambda/379645464@48f278eb

Actual invocation has different arguments:

实际调用有不同的参数:

..........Lambda/482052083@2f217633

which makes sense since mockito tries to compare two different implementations of the functional interface, which have a different hash code.

这是有道理的,因为 mockito 试图比较函数接口的两种不同实现,它们具有不同的哈希码。

So is there some other way to verify that the method dispatchMessage()has been called with a lambda that returns void and has a body method of dispatcher.dispatch("activityId", "ctxId", 1l,);?

那么是否有其他方法可以验证该方法dispatchMessage()是否已使用返回 void 且主体方法为 的 lambda 调用 dispatcher.dispatch("activityId", "ctxId", 1l,);

回答by hotzst

Yes, you can. The trick here is that you have to get to the instance of the lambda that is passed to the registerMessageand then execute that expression and then you can verify the result.

是的你可以。这里的技巧是您必须获得传递给 的 lambda 实例,registerMessage然后执行该表达式,然后您才能验证结果。

For the purpose of a meaningful example I created this Handlerclass that contains the dispatchMessagethat you want to test:

为了一个有意义的例子,我创建了这个Handler包含dispatchMessage你想要测试的类:

public class Handler {

    private Dispatcher dispatcher = new Dispatcher();

    public void dispatchMessage(MessageHandler handler, String argument1, String argument2, Long argument3) {

        handler.registerMessage(() -> {
            dispatcher.dispatch(argument1,
                    argument2,
                    argument3);
        });

    }

    interface MessageHandler {
        void registerMessage(Runnable run);
    }

    static class Dispatcher {
        void dispatch(String a, String b, long c){
            // Do dispatch
        }
    }
}

What you have to remember is that a lambda expression is just a short hand form to pass a function to a method. In this example the function is the runmethod of a Runnable. Therefore the method registerMessageof the interface for MessageHandlertakes a Runnableas it's argument. I also included an implementation for the Dispatcher, which is called from within registerMessage. The test for this looks like this:

您必须记住的是,lambda 表达式只是将函数传递给方法的简写形式。在这个例子中,函数是 a 的run方法Runnable。因此,registerMessage接口的方法MessageHandler将 aRunnable作为参数。我还包括了 的实现Dispatcher,它是从 内部调用的registerMessage。对此的测试如下所示:

@RunWith(MockitoJUnitRunner.class)
public class HandlerTest {
    @Mock
    private Dispatcher dispatcher;
    @InjectMocks
    private Handler classUnderTest;
    @Captor
    private ArgumentCaptor<Runnable> registerMessageLambdaCaptor;

    @Test
    public void shouldCallDispatchMethod() {
        final String a = "foo";
        final String b = "bar";
        final long c = 42L;

        MessageHandler handler = mock(MessageHandler.class);

        classUnderTest.dispatchMessage(handler, a, b, c);

        verify(handler).registerMessage(registerMessageLambdaCaptor.capture());

        Runnable lambda = registerMessageLambdaCaptor.getValue();

        lambda.run();

        verify(dispatcher).dispatch(a, b, c);
    }
}

There is an ArgumentCaptorfor the lambda expression which we use in the first verification of the registerMessage. After that verification we can retrieve the lambda expression from the captor. The type of the lambda expression is Runnable, as defined in the MessageHandlerinterface. Hence we can call the runmethod on it and then verify that the dispatchmethod on the Dispatcherwas called with all the appropriate arguments.

有一个ArgumentCaptor用于我们在的第一验证使用λ表达式registerMessage。在验证之后,我们可以从捕获器中检索 lambda 表达式。lambda 表达式的类型是Runnable,如MessageHandler接口中所定义。因此,我们可以调用其run上的方法,然后验证是否使用所有适当的参数调用了上的dispatch方法Dispatcher

回答by Blundell

Outside of the specific lambda, you can verify that your method was called with anylambda expression was called like this:

在特定的 lambda 之外,您可以验证您的方法是否使用任何lambda 表达式被调用,如下所示:

    verify(handler).registerMessage(any())

    private fun <T> any(): T {
        Mockito.any<T>()
        return null as T
    }