One of the interactions I want to test is that a class Foo
is supposed to pass a Stream<Changes>
to FooListener.someChangesHappened
. Is there a Mockito idiom to verify that a stream contained the expected objects?
Asked
Active
Viewed 1.2k times
5

Doradus
- 938
- 1
- 9
- 15
-
2you might want to rethink the way you write test methods. Tests are not only used to test the logic, but also to ensure that things work as expected when the implementation is changed. Let's say you write a test method which checks what's inside stream, later it's decided that you don't want to use streams, you'd have to change your test cases then to check if it does the same thing. – Rahul Sharma May 07 '16 at 18:02
-
@Rahul - I'm not sure I see your point. Obviously if an interface changes, the tests need to change too, streams or no streams. – Doradus May 07 '16 at 22:18
1 Answers
6
Assuming you are just verifying the argument to a mock implementation, and are not actually using it, here is a custom Hamcrest Matcher
that will get the job done. It gets hairy when you need to read from the Stream
more than once, because Stream
s are not built for that. You'll notice that this solution even needs to protect itself from JUnit calling matches
more than once.
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.not;
import static org.mockito.Matchers.argThat;
import static org.mockito.Mockito.verify;
@RunWith(MockitoJUnitRunner.class)
public class Foo {
@Mock
FooListener fooListener;
@Before
public void happen() {
fooListener.someChangesHappened(Stream.of(Changes.ONE, Changes.TWO, Changes.THREE));
}
@Test
public void contains() {
verify(fooListener).someChangesHappened(argThat(streamThat(hasItem(Changes.TWO))));
}
@Test
public void doesNotContain() {
verify(fooListener).someChangesHappened(argThat(streamThat(not(hasItem(Changes.FOUR)))));
}
private static <T> Matcher<Stream<T>> streamThat(Matcher<Iterable<? super T>> toMatch) {
return new IterableStream<>(toMatch);
}
private interface FooListener {
void someChangesHappened(Stream<Changes> stream);
}
private enum Changes {
ONE, TWO, THREE, FOUR
}
private static class IterableStream<T> extends TypeSafeMatcher<Stream<T>> {
Matcher<Iterable<? super T>> toMatch;
List<T> input = null;
public IterableStream(Matcher<Iterable<? super T>> toMatch) {
this.toMatch = toMatch;
}
@Override
protected synchronized boolean matchesSafely(Stream<T> item) {
// This is to protect against JUnit calling this more than once
input = input == null ? item.collect(Collectors.toList()) : input;
return toMatch.matches(input);
}
@Override
public void describeTo(Description description) {
description.appendText("stream that represents ");
toMatch.describeTo(description);
}
}
}

Yosef Weiner
- 5,432
- 1
- 24
- 37
-
1Cool! So the core idea is that, since the mock listener doesn't actually consume the stream, you can write a `Matcher` that converts it to a list and compares that against `toMatch`. Is that close? – Doradus May 08 '16 at 01:03