如何为 Java Stream 编写 Junit

Sti*_*ing 6 java unit-testing java-8 java-stream

我最近开始使用 java 流并编写一个用户服务,它返回一个用户流。使用该用户流,我处理其他逻辑。

以下是我正在处理流的一段代码,它工作正常

try (Stream<User> users = userService.getStream()) {
    users.forEach(user -> {
    });
Run Code Online (Sandbox Code Playgroud)

但是当我开始编写 Junit 时,它失败并显示以下错误消息。

java.lang.IllegalStateException: stream has already been operated upon or closed
    at java.util.stream.AbstractPipeline.sourceStageSpliterator(AbstractPipeline.java:279)
    at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:647) 
    at com.test.UserService.sendBulkNotification(UserService.java:47)
    at com.test.UserServiceTest.sendNotificationTest(UserServiceTest.java:64) 
Run Code Online (Sandbox Code Playgroud)

这是我的单元测试代码:

List<User> users = new ArrayList<>();
for(long i = 1; i <= 5; i++) {
    User user = new User();
    user.setId(i);
    users.add(user);
}

when(userService.getStream()).thenReturn(users.stream());
userService.sendNotification("user", 1, "test.com");
Run Code Online (Sandbox Code Playgroud)

你能帮我用流编写测试用例/帮我解决这个问题吗?

And*_*eas 7

当您使用 时thenReturn(users.stream()),您调用users.stream()一次并将该Stream对象移交给 Mockito 运行时,然后每次when(...)触发时都会返回相同的实例。

由于 aStream只能消耗一次,因此任何次要触发器都将失败。

你需要给 Mockito 一个工厂/供应商对象,它可以在Stream每次触发器触发时产生一个新的。Mockito 将其称为 an Answer,因此请thenAnswer(Answer<?> answer)改为调用。

when(userService.getStream()).thenAnswer(invo -> users.stream());
Run Code Online (Sandbox Code Playgroud)

您必须在 lambda 表达式中命名参数,但由于您不使用它,因此您可以随意调用它。我使用invoinvocation,为函数接口中的answer方法声明的参数的名称的缩写Answer