用Mockito监视Lambda

时间:2019-01-23 13:54:41

标签: java unit-testing lambda mockito

在编写涉及模拟lambda的单元测试时,我遇到了一个有趣的问题。

@Test
public void spyingLambda() {
    final Supplier<String> spy = Mockito.spy((Supplier) () -> "1");
    spy.get();
}

运行此测试失败,并显示以下错误:

  

Mockito无法模拟/间谍,因为:    -期末班

上述问题的一种解决方法是将lambda替换为匿名实现:

@Test
public void spyingAnonymousImplementation() {
    final Supplier<String> spy = Mockito.spy(new Supplier<String>() {
        @Override
        public String get() {
            return "1";
        }
    });
    spy.get();
}

尽管两个测试完全相同(IDE建议甚至将匿名实现替换为lambda),第二个测试也不会失败。

我想知道这是否是已知问题,可以通过模仿解决,还是有其他解决方法。

3 个答案:

答案 0 :(得分:3)

仅供参考,以改善@alex的答案,您也可以

public static <T> T spyLambda(final T lambda) {
    Class<?>[] interfaces = lambda.getClass().getInterfaces();
    MatcherAssert.assertThat(interfaces, IsArrayWithSize.arrayWithSize(1));
    return Mockito.mock((Class<T>) interfaces[0], delegatesTo(lambda));
}

,然后在不指定类型(例如Supplier.class)的情况下对其进行监视

Callable<Integer> callable = spyLambda(() -> {
    return 42;
});
Supplier<Integer> supplier = spyLambda(() -> 42);
Runnable runnable = spyLambda(() -> System.out.println("42"));

答案 1 :(得分:1)

解决此问题的另一种方法是:

/**
 * This method overcomes the issue with the original Mockito.spy when passing a lambda which fails with an error
 * saying that the passed class is final.
 */
public static <T> T spyLambda(final Class<T> lambdaType, final T lambda) {
    return mock(lambdaType, delegatesTo(lambda));
}

通过更改以下第一种方法可以监视lambda:

@Test
public void spyingLambda() {
    final Supplier<String> spy = spyLambda(Supplier.class, () -> "1");
    spy.get();
}

希望上述示例可以对遇到相同问题的其他人有所帮助。

答案 2 :(得分:0)

您可以允许最终课程模拟。创建文件src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker包含

mock-maker-inline

https://www.baeldung.com/mockito-final#configure-mocktio