测试依赖项调用的lambda表达式

abk*_*srv 6 java lambda junit unit-testing java-8

我试图测试lambda表达式中的一些代码,这是从另一个类的回调.

class EmailSender {
    private EmailBuilder emailBuilder;

    public void send() {
        String testEmail = emailBuilder.buildEmail("Test Email", bodyContentAppender());
        //send testEmail
    }

    private Consumer<Email> bodyContentAppender() {
        //how to test this through JUnit?
        return email -> email.appendBody("Body Content");
    }
}

interface EmailBuilder {

    String buildEmail(String templateName, Consumer<Email> contentAppender);
}
Run Code Online (Sandbox Code Playgroud)

getBodyContent调用方法中的lambda表达式是EmailBuilderJUnit测试中的模拟依赖项EmailSender.由于我在嘲笑行为EmailBuilder,因此getBodyContent不会从测试中调用内部代码.如何测试这样的作品?

编辑: 通过Argument Captors捕获lambda表达式在这种情况下不是解决方案,因为模拟行为EmailBuilder并且不调用实际方法.其次,email.appendBody对一个由外部API传递而不是直接创建的对象进行一些转换.

Hul*_*ulk 2

您在这里尝试做的本质上是验证工厂方法实际上确实返回了正确的对象。有一个相关的问题,其中的共识是除了验证工厂方法是否确实返回正确类型的对象之外,不要测试它的结果。该对象的行为应该在该类型的单元测试中进行测试。

在回答有关单元测试 lambda 的相关问题时,Stuart Marks 认为

如果 lambda 中的代码足够复杂以至于需要测试,那么也许应该从 lambda 中重构该代码,以便可以使用常用技术对其进行测试。

现在,真正的问题是:如果这不是 lambda,而是MyBodyContentAppender实现函数式接口的具体类Consumer<Email>,您将如何对其进行单元测试?你会为这门课写什么样的测试?

您可能会编写测试来验证,给定一个Email, 调用accept()确实appendBody()使用适当的参数进行调用,也许使用null参数调用它会抛出 aNullPointerException等。您可能不会验证它是否email.appendBody()按预期工作,因为这已被以下测试覆盖EmailEmail如果很难创建,您可能必须模拟这些测试。

那么,所有这些测试也可以针对 lambda 进行。您的问题是工厂和创建的对象的类型都是私有的,因此从测试的角度来看,访问该对象的唯一方法是通过传递给 (mocked) 的参数emailBuilder.buildEmail()

如果您使用 Mockito 来模拟emailBuilder,您可以通过 s 捕获此方法的参数ArgumentCaptor(请参阅15. 捕获进一步断言的参数(自 1.8.0 起)),我确信其他模拟库提供类似的功能。