Reputation: 2043
I am recently started using java stream and write a one User service, which returns a stream of users. Using that user stream, I process other logic.
Following is the piece of code that I am dealing with stream and it works fine
try (Stream<User> users = userService.getStream()) {
users.forEach(user -> {
});
But when I start writing Junit then it fails with following error message.
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)
Here is my unit test code:
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");
Could you please help me to write test case with stream/help me to fix this issue?
Upvotes: 7
Views: 6049
Reputation: 159086
When you use thenReturn(users.stream())
, you call the users.stream()
once and hand that Stream
object over to the Mockito runtime, which will then return that same instance every time the when(...)
is triggered.
Since a Stream
can only be consumed once, any secondary triggers will fail.
You need to give Mockito a factory/supplier object that can produce a new Stream
every time the trigger fires. Mockito calls that an Answer
, so call thenAnswer(Answer<?> answer)
instead.
when(userService.getStream()).thenAnswer(invo -> users.stream());
You have to name the parameter in the lambda expression, but since you don't use it, you can call it anything. I used invo
as short for invocation
, the name of the parameter declared for the answer
method in the Answer
functional interface.
Upvotes: 8