我应该为流操作模拟列表吗?

Should i mock List for stream operations?

我在函数中有一行代码,它在 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);

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

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

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

正常创建列表即可。

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

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

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

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

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

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

然后您可以使用 class 作为依赖项并模拟其计数方法:

// 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));