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

Fdi*_*eal 14 java lambda unit-testing java-8

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

以下面的伪代码为例:

private Bar bar;

public void method(int foo){
    bar.useLambda(baz -> baz.setFoo(foo));
}
Run Code Online (Sandbox Code Playgroud)

一种方法是仅仅验证条形码上的呼叫

verify(bar).useLambda(Matchers.<Consumer<Baz>>.any());
Run Code Online (Sandbox Code Playgroud)

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

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

bar.useLambda(This::setFooOnBaz);
Run Code Online (Sandbox Code Playgroud)

因为我不会在那个方法上有foo.或者至少这是我的想法.

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


编辑

因为我编码的是单元测试,我不想实例化bar,而我将使用mock.所以我将无法验证baz.setFoo通话.

Stu*_*rks 15

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

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

但是yshavit答案触及了关于是否有必要对私有方法进行单元测试的重要观点.lambda当然可以被认为是一种私有方法.

这里还有一个更大的观点.单元测试的原则之一是您不需要对任何太简单而无法破坏的东西进行单元测试.这与lambda的理想情况很好地吻合,这是一个非常简单的表达式,显然是正确的.(至少,这是我认为理想的.)考虑一下这个例子:

    baz -> baz.setFoo(foo)
Run Code Online (Sandbox Code Playgroud)

是否有任何疑问,这个lambda表达式,当提交Baz引用时,将调用其setFoo方法并将其foo作为参数传递?也许这很简单,不需要进行单元测试.

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


ysh*_*vit 11

像对待私人方法一样对待lambdas; 不要单独测试,而是测试它的效果.在您的情况下,调用method(foo)应该导致bar.setFoo- 所以,调用method(foo),然后验证bar.getFoo().

  • @Fdiazreal:当你的代码委托给'Bar`时,没有实例化bar就没有必要测试这个动作.当然,你也可以自己测试`baz.setFoo(foo)`.由于`setFoo`是一种普通的方法,你应该没有问题测试它 - 只需忘记lambda. (3认同)
  • 同意,不要对 lambda 进行单元测试;单元测试结果。 (2认同)