Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mock a method that returns a Stream and is called more than one time

MyStreamClass mock = mock(MyStreamClass.class);

when(mock.streamMethod()).thenReturn(Stream.of("A", "B"));

System.out.println(""+mock.streamMethod().findFirst());
System.out.println(""+mock.streamMethod().findFirst());

the second call of findFirst will throw java.lang.IllegalStateException: stream has already been operated upon or closed

like image 542
telebog Avatar asked Feb 11 '19 15:02

telebog


People also ask

Which method returns a stream?

stream() is just such a method which returns a stream to the caller.

What is a mocked method?

Mocking is done when you invoke methods of a class that has external communication like database calls or rest calls. Through mocking you can explicitly define the return value of methods without actually executing the steps of the method.

What does a stream return?

Streams don't change the original data structure, they only provide the result as per the pipelined methods. Each intermediate operation is lazily executed and returns a stream as a result, hence various intermediate operations can be pipelined. Terminal operations mark the end of the stream and return the result.

How do you mock an interface in Java?

We can use org. mockito. Mockito class mock() method to create a mock object of a given class or interface. This is really the simplest way to mock an object.


2 Answers

Try the thenAnswer instead of thenReturn:

Answer<Stream> answer = new Answer<Stream>() {
    public Stream answer(InvocationOnMock invocation) throws Throwable {
        return Stream.of("A", "B");
    }
};


when(mock.streamMethod()).thenAnswer(answer);

Now a new Stream will be created for each call to streamMethod.

Further read:

Here is an article I wrote on Dynamic Answering in Mockito that might be complementary.

like image 161
Maciej Kowalski Avatar answered Sep 22 '22 19:09

Maciej Kowalski


You're not mocking a Stream, you're creating one - and only one, which will be consumed after the first terminating method having been called on it, which is what you experience.

Most of the time, it's best to stick with mocking as far as possible, in your case

MyStreamClass mock = mock(MyStreamClass.class);
Stream mockStream = mock(Stream.class);
when(mock.streamMethod()).thenReturn(mockStream);

That should be enough for testing all clients of MyStreamClass - there's no point in getting actual results from the stream.

If that does not fit your design, you can alternatively use an Answer:

when(mock.streamMethod()).then(i -> Stream.of("A", "B"));

this will result in the stream being created every time the method is called.

Or, you can mock several calls with thenReturn().

when(mock.streamMethod()).thenReturn(Stream.of("A", "B"), Stream.of("A", "B"));

which will last you 2 calls.

like image 43
daniu Avatar answered Sep 25 '22 19:09

daniu