使用 Java 8 Lambdas 的单元测试代码

2022-09-02 00:58:57

我已经使用Java 8几个月了,并且我已经开始使用Lambda表达式,这在某些情况下非常方便。但是,我经常遇到一些问题来对使用 Lambda 的代码进行单元测试。

以下伪代码为例:

private Bar bar;

public void method(int foo){
    bar.useLambda(baz -> baz.setFoo(foo));
}

一种方法是只验证柱上的调用

verify(bar).useLambda(Matchers.<Consumer<Baz>>.any());

但是,通过这样做,我不会测试Lambda的代码。

另请注意,我无法将 Lambda 替换为方法和使用方法引用:

bar.useLambda(This::setFooOnBaz);

因为我不会有那个方法的foo。或者至少我是这么认为的。

你以前遇到过这个问题吗?如何测试或重构我的代码以正确测试它?


编辑

由于我正在编码的是单元测试,因此我不想实例化bar,我将使用模拟。因此,我将无法仅验证该呼叫。baz.setFoo


答案 1

您无法直接对 lambda 进行单元测试,因为它没有名称。除非您有对它的引用,否则无法调用它。

通常的替代方法是将 lambda 重构为命名方法,并使用产品代码中的方法引用,并从测试代码中按名称调用该方法。正如您所注意到的,这种情况不能以这种方式重构,因为它捕获 ,并且方法引用唯一可以捕获的是接收器。foo

但是yshavit的答案触及了一个重要的观点,即是否有必要对私有方法进行单元测试。lambda 当然可以被视为私有方法。

这里还有一个更大的问题。单元测试的一个原则是,你不需要对任何太简单而无法打破的东西进行单元测试。这与lambda的理想情况非常吻合,lambda是一个非常简单的表达式,显然是正确的。(至少,这是我认为理想的。请考虑以下示例:

    baz -> baz.setFoo(foo)

毫无疑问,当收到引用时,这个lambda表达式将调用其方法并将其作为参数传递?也许它是如此简单,以至于不需要进行单元测试。BazsetFoofoo

另一方面,这只是一个例子,也许您要测试的实际lambda要复杂得多。我见过使用大型,嵌套,多行lambda的代码。例如,请参阅此答案及其问题和其他答案。这样的 lambda 确实很难调试和测试。如果 lambda 中的代码足够复杂,需要进行测试,那么也许应该从 lambda 中重构该代码,以便可以使用常用技术对其进行测试。


答案 2

像对待私有方法一样对待 lambda;不要单独测试它,而是测试它的效果。在您的情况下,调用应该会导致发生 - 因此,请调用然后验证 。method(foo)bar.setFoomethod(foo)bar.getFoo()


推荐