Reputation: 18633
What would be a good way to compare two Stream
instances in Java 8 and find out whether they have the same elements, specifically for purposes of unit testing?
What I've got now is:
@Test
void testSomething() {
Stream<Integer> expected;
Stream<Integer> thingUnderTest;
// (...)
Assert.assertArrayEquals(expected.toArray(), thingUnderTest.toArray());
}
or alternatively:
Assert.assertEquals(
expected.collect(Collectors.toList()),
thingUnderTest.collect(Collectors.toList()));
But that means I'm constructing two collections and discarding them. It's not a performance issue, given the size of my test streams, but I'm wondering whether there's a canonical way to compare two streams.
Upvotes: 51
Views: 44466
Reputation: 7279
Another way of doing the same thing:
static void assertStreamEquals(Stream<?> s1, Stream<?> s2) {
Iterator<?> it2 = s2.iterator();
assert s1.allMatch(o -> it2.hasNext() && Objects.equals(o, it2.next())) && !it2.hasNext();
}
Upvotes: 1
Reputation: 390
If order of elements doesn't matter, then comparison can be done for any number of streams using stream groupingBy() and then checking count for each element.
Example is for IntStream but you can get the idea behind this method:
IntStream stream1 = IntStream.range(1, 9);
IntStream stream2 = IntStream.range(1, 10);
boolean equal = IntStream.concat(stream1, stream2)
.boxed()
.collect(Collectors.groupingBy(Function.identity()))
.entrySet().stream().noneMatch(e -> e.getValue().size() != 2);
Upvotes: 2
Reputation: 435
public static boolean equalStreams(Stream<?> ... streams) {
List<Iterator<?>> is = Arrays.stream(streams)
.map(Stream::iterator)
.collect(Collectors.toList());
while (is.stream().allMatch(Iterator::hasNext))
if (is.stream().map(Iterator::next).distinct().limit(2).count() > 1)
return false;
return is.stream().noneMatch(Iterator::hasNext);
}
Upvotes: 2
Reputation: 19682
static void assertStreamEquals(Stream<?> s1, Stream<?> s2) {
Iterator<?> iter1 = s1.iterator(), iter2 = s2.iterator();
while(iter1.hasNext() && iter2.hasNext())
assertEquals(iter1.next(), iter2.next());
assert !iter1.hasNext() && !iter2.hasNext();
}
Upvotes: 43
Reputation: 3175
You can assert the stream's content without creating a Stream<> expected
.
AssertJ has fluent and readable solutions for this.
import static org.assertj.core.api.Assertions.assertThat;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
class MyTests {
@Test
void test() {
Stream<Integer> actual = Stream.of(0, 8, 15); // your thingUnderTest
assertThat(actual).containsExactly(0, 8, 15);
}
}
Upvotes: 2
Reputation: 5191
How to Compare Two Streams in java 8 and above: with the example of Comparing IntStream
package com.techsqually.java.language.generics.basics;
import java.util.Iterator;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class TwoStreamComparision {
public static void main(String[] args) {
String a = "Arpan";
String b = "Arpen";
IntStream s1 = a.chars();
IntStream s2 = b.chars();
Iterator<Integer> s1It = s1.iterator();
Iterator<Integer> s2It = s2.iterator();
//Code to check how many characters are not equal in both the string at their Respective Position
int count = 0;
while (s2It.hasNext()){
if (!s1It.next().equals(s2It.next())){
count++;
}
}
System.out.println(count);
}
}
Upvotes: -1
Reputation: 12112
Using the elementsEqual
method in the Guava library:
Iterators.elementsEqual(s1.iterator(), s2.iterator())
Upvotes: 4
Reputation: 269667
Collecting the stream under test (as you show) is a straightforward and effective way of performing the test. You may create the list of expected results in the easiest way available, which might not be collecting a stream.
Alternatively, with most libraries for creating mock collaborators, one could mock a Consumer
that "expects" a series of accept()
calls with particular elements. Consume the Stream
with it, and then "verify" that its configured expectations were met.
Upvotes: 4