Mockito验证特定的lambda已作为模拟方法中的参数传递 [英] Mockito verify that a specific lambda has been passed as an argument in mock's method

查看:76
本文介绍了Mockito验证特定的lambda已作为模拟方法中的参数传递的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想测试以下方法:

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

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

}

MessageHandler是一个帮助程序类,它将接受lambda形式的Functional Interface实现,并将其存储以供以后执行.

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

是否有一种方法可以通过嘲笑来验证是否已使用特定的lambda表达式调用了被模仿的MessageHandlerdispatchMessage方法:

Is there a way to verify with mockito that the dispatchMessage method of the mocked MessageHandler has been called with the specific lambda expression:

意思是,我可以编写这样的测试吗?

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:

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

实际调用具有不同的参数:

Actual invocation has different arguments:

..........Lambda$27/482052083@2f217633

这很有意义,因为模拟程序试图比较具有不同哈希码的功能接口的两种不同实现.

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

因此,还有其他方法可以验证方法dispatchMessage()是否已通过返回空值并具有body方法的lambda调用. dispatcher.dispatch("activityId", "ctxId", 1l,);?

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,); ?

推荐答案

是的,可以.这里的窍门是,您必须先获取传递给registerMessage的lambda实例,然后执行该表达式,然后才能验证结果.

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

出于一个有意义的示例的目的,我创建了这个Handler类,其中包含要测试的dispatchMessage:

For the purpose of a meaningful example I created this Handler class that contains the dispatchMessage that you want to test:

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
        }
    }
}

您要记住的是,lambda表达式只是将函数传递给方法的简写形式.在此示例中,函数是Runnablerun方法.因此,MessageHandler接口的方法registerMessageRunnable作为其参数. 我还包括了Dispatcher的实现,该实现在registerMessage内部调用. 测试如下:

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 run method of a Runnable. Therefore the method registerMessage of the interface for MessageHandler takes a Runnable as it's argument. I also included an implementation for the Dispatcher, which is called from within registerMessage. The test for this looks like this:

@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);
    }
}

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

There is an ArgumentCaptor for 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 MessageHandler interface. Hence we can call the run method on it and then verify that the dispatch method on the Dispatcher was called with all the appropriate arguments.

这篇关于Mockito验证特定的lambda已作为模拟方法中的参数传递的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆