【问题标题】:How to unit test Java 8 streams?如何对 Java 8 流进行单元测试?
【发布时间】:2018-11-22 22:11:23
【问题描述】:

list.stream().forEach(e -> { dbCall.delete(e.Id());});

列表中的每个项目都会从数据库中删除。

假设列表中有3个项目,如何进行单元测试:

  1. Delete 被调用了 3 次。
  2. 删除被称为“按顺序/顺序”,即列表中元素的顺序?

【问题讨论】:

  • 由于您使用的是明确无序的forEach,因此测试调用是否按顺序完成是没有意义的。但无论如何,您要求的不是单元测试。您正在尝试验证实施细节。如果该语句做了正确的事情,并且正确的事情是删除指定的三个条目,这就是您应该验证的内容,谁在乎哪个方法以什么顺序被调用?测试代码是否删除了三个指定项的方法,不取决于你是使用循环,list.forEach,还是list.stream().forEach(…)
  • @Holger forEach 不是“明确无序”;对于顺序流,它保证是有序的,对于并行流是隐式无序的。此外,删除的顺序可能很重要,例如,如果列表是按数据库强制执行的项目之间的引用关系排序的。牵强,也许,不是最好的设计,也许,但可能。
  • @daniu 你是怎么得出这个结论的? documentation of forEach 明确表示:“此操作的行为是明确的不确定性”。 As said by one of the authors 关于并行流执行的声明不允许对顺序流得出相反的结论。但是对于单元测试,顺序仍然无关紧要。重要的是,这三个项目是否被正确删除。
  • @Holger 我得出这个结论是因为在这种情况下,流来自List,其行为与调用List#forEach 相同,在迭代顺序(如果指定了迭代顺序)”(docs.oracle.com/javase/8/docs/api/java/lang/…)。 Brian 的陈述是关于Stream#forEach 调用的一般情况,例如也适用于从无序Collection 创建的流。你是对的,“保证”是不正确的——但 JDK 从未改变过现有的行为。
  • @Holger 至于顺序在单元测试中无关紧要,那是不正确的。 “三项正确删除”是操作需求,单元测试(严格意义上)验证技术行为。另外,一般来说,调用顺序很好地在单元测试的范围内:如果这是三个不同的服务调用而不是数据库删除,我相信你会同意顺序可能是相关的,我们不会有这个讨论.

标签: java unit-testing testing java-stream


【解决方案1】:

只需验证应该调用dbCall.delete() 的预期时间。 这可能如下所示:

Mockito.verify(dbCall, times(3L)).delete(any(String.class));

流可以并行工作,因此您无法验证序列。您可以使用索引上的验证元素来执行此操作,但序列将被忽略。 Mockito 只会验证调用+值是否被使用。这对于单元测试来说已经足够了。

【讨论】:

    【解决方案2】:

    你可以使用JUnit的InOrder

    DbCall dbCall = mock(DbCall.class);
    List<Element> list = Arrays.asList(newElement(1), newElement(2), newElement(3));
    
    runDeleteMethod(list);
    
    InOrder inorder = inOrder(dbCall);
    inorder.verify(dbCall).delete(1);
    inorder.verify(dbCall).delete(2);
    inorder.verify(dbCall).delete(3);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-22
      • 1970-01-01
      • 1970-01-01
      • 2010-09-10
      • 1970-01-01
      相关资源
      最近更新 更多