【问题标题】:Should i mock List for stream operations?我应该模拟列表以进行流操作吗?
【发布时间】:2018-10-29 12:25:01
【问题描述】:

我在函数中有一行代码将流操作应用于ArrayList

List<Entity> list = xyz(); 

long result = list.stream().map(n -> n.getData()).filter(n -> n == 1).count();

现在,当我为此方法编写测试时,我应该这样做:

@Mock
private List<Entity> list;

//inside the test method
when(list.stream().map(any()).filter(any()).count()).thenReturn(someValue);

我想到的是,当我们在代码中调用流操作时,我们基本上是走出我们的类来调用这些函数。由于它是单元测试,我们应该留在我们的模块中。请澄清我是否有一些误解。如果我们不需要模拟List,那为什么呢?

【问题讨论】:

  • 没有。你应该模拟 xyz()
  • 是的,已经完成了。我真的只关心流操作。如果我们不需要模拟 List 那为什么?基本上我们要走出我们的模块。
  • 嗯...不是吗?列表的流式传输都在该方法中。只是超出范围的 xyz() 调用
  • 令我困惑的是 stream() 是ArrayList 的方法,而不是我们自己的类。这就是为什么我突然想到我们要下课了。
  • 在这种情况下,String 也是另一个类,你会去模拟“test”.equals(value) 吗?如果您无法获得价值,您只需要模拟任何东西。你有列表的值,因为它是由 xyz() 返回的,所以不需要模拟任何东西。

标签: java unit-testing mockito junit4


【解决方案1】:

可以模拟列表,但这可能比它的价值更麻烦。列表和流接口非常大,如果不模拟每个方法(不,谢谢)或只模拟您使用的方法,就很难模拟它们,这意味着您将依赖于了解您所使用方法的内部实现细节重新测试。后者导致脆弱的测试。最好写一个不关心实现细节的测试,只关心输入和输出。

当创建对象的正确版本非常困难时,或者当您想为测试提供隔离时,应该使用模拟。创建列表并不难,而且它们经过了很好的测试,因此模拟它们并没有真正为增加隔离提供任何价值。

正常创建列表即可。

list = Arrays.asList(new Entity(1), new Entity(2), new Entity(1));

在这种情况下,您可以断言方法的结果为 2。

您可能会从模拟实体中获得一些好处,但是例如

Mockito.when(Entity.getData()).thenReturn(1);

【讨论】:

    【解决方案2】:

    看来你并不真正关心流操作的内部工作,你只关心它的结果。

    在我看来,您应该将该逻辑提取到其他一些专门的类中,该类将有一个接受列表并返回计数的公共方法。

    然后您可以将该类用作依赖项并模拟其计数方法:

    // the impl
    
    private DataCounter dataCounter;
    
    ...
    
    List<Entity> list = xyz(); 
    
    long result = dataCounter.count(list);
    
    // test class
    
    @Mock
    private DataCounter dataCounter;
    
    //inside the test method
    when(dataCounter.count(Mockito.any(List.class)).thenReturn(Mockito.eq(someValue));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-25
      • 1970-01-01
      • 2017-09-18
      • 2011-04-12
      • 2020-09-15
      • 2016-11-12
      • 2020-12-05
      • 1970-01-01
      相关资源
      最近更新 更多