Mockito验证了特定的lambda已经作为mock方法中的参数传递

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mockito验证了特定的lambda已经作为mock方法中的参数传递相关的知识,希望对你有一定的参考价值。

我想测试以下方法:

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

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

}

其中MessageHandler是一个辅助类,它将接受一个lambda形式的Functional Interface实现,并将其存储起来供以后执行。

有没有办法验证mockito已经使用特定的lambda表达式调用了模拟dispatchMessageMessageHandler方法:

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

        @Test
public void testDispatchMessage_Success() throws Exception {

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

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

}

}

此测试将导致断言错误:参数不同!通缉:

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

实际调用有不同的参数:

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

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

那么有没有其他方法来验证方法dispatchMessage()已被一个lambda调用返回void并具有dispatcher.dispatch("activityId", "ctxId", 1l,);的body方法?

答案

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

为了一个有意义的例子,我创建了这个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
        }
    }
}

你必须要记住的是,lambda表达式只是将函数传递给方法的简单形式。在这个例子中,函数是runRunnable方法。因此,registerMessage接口的MessageHandler方法以Runnable为参数。我还包括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);
    }
}

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

以上是关于Mockito验证了特定的lambda已经作为mock方法中的参数传递的主要内容,如果未能解决你的问题,请参考以下文章

是否可以以紧凑的方式使用 Mockito 验证任意交互?

Mockito - 验证集合中的对象是否称为方法

使用 Mockito 为 Firebase 用户身份验证设置单元测试

使用 Mockito 从模拟中抛出已检查的异常

Mockito验证只调用了一个预期的方法

mockito 验证未使用参数调用的方法