Hot questions for Using Mockito in java stream

Question:

I have a problem mocking an Iterable class combined with a call of spliterator(). It all works fine when calling spliterator once, but the second call returns no values.

As the mock always returns the same Spliterator instance, I assume that the state is not reset. Is there a way to do this?

This is the smallest example I could give

The call mapStringToHash is a Lib in real life and can't be changed. MyIterable is also no object under my control.

package net.test;

import static org.hamcrest.CoreMatchers.is;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static java.util.stream.Collectors.toList;
import static org.hamcrest.MatcherAssert.assertThat;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Spliterator;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class SpliteratorTest {

    class MyIterable<T> implements Iterable<T> {

        private List<T> list;

        MyIterable(List<T> list) {
            this.list = new ArrayList<>(list);
        }

        @Override
        public Iterator<T> iterator() {
            return list.iterator();
        }

        @Override
        public Spliterator<T> spliterator() {
            return list.spliterator();
        }
    }

    // this a library method
    private Stream<Integer> mapStringToHash(final MyIterable<String> myIterable) {
        return StreamSupport.stream(myIterable.spliterator(), false).map(String::hashCode);
    }

    @Test
    public void testSeveralSpliteratorCalls() {
        MyIterable myIterable = givenMyIterableMock("a", "b", "c");

        Stream<Integer> myIterableHash1 = mapStringToHash(myIterable);
        assertThat(myIterableHash1.count(), is(3L));


        Stream<Integer> myIterableHash2 = mapStringToHash(myIterable);
        assertThat(myIterableHash2.count(), is(3L));
    }

    private MyIterable givenMyIterableMock(String... values) {
        MyIterable myIterable = mock(MyIterable.class);

        Spliterator myIterableSpliterator = Arrays.stream(values)
                .collect(toList())
                .spliterator();
        doReturn(myIterableSpliterator).when(myIterable).spliterator();
        return myIterable;
    }
}

Answer:

It turns out it's not as circumvent as I thought. It can be done using a custom Answer implementation, but since Answer is a functional interface, the following suffices:

Mockito.when(myIterable.spliterator()).then(invocation -> Arrays.spliterator(values));

Question:

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?


Answer:

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 Streams 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);
        }
    }
}

Question:

I'm trying to get my head around generics and wildcards in java 8. But I cannot understand why cannot mock this repository method. The code is pretty simple so should be easy to reproduce.

I've got this compiling error in "thenReturn" part of the "when"

The method thenReturn(Stream<capture#1-of ? extends Something>) in the type
OngoingStubbing<Stream<capture#1-of ? extends Something>> is not applicable
for the arguments (Stream<capture#3-of ? extends Something>)

the test:

@Test
public void ItShourReturnStreamFromRepository() {
    List<Something> list = new ArrayList<Something>();
    list.add(new Something());
    Stream<? extends Something> stream = list.stream();
    when(someRepository.getStream()).thenReturn(stream);     
}

the class:

public class Something {}

the repository:

public interface SomeRepository{
    Stream<? extends Something> getStream();
}

Can someone help with this? Thanks!


Answer:

This is a general issue with wildcard types. To demonstrate it with a simplified, Mockito-independent example:

Enum<?> e = Thread.State.BLOCKED;

// produces "incompatible types: Enum<CAP#1> cannot be converted to Enum<CAP#2>"
Arrays.asList(e).set(0, e);

// works since Java 8
List<Enum<?>> list=Arrays.asList(e);
list.add(e);

// works even in older versions
Arrays.<Enum<?>>asList(e).set(0, e);

This points you to possible solutions that should work with the Mockito API as well. However, for designing an API like the SomeRepository you should following the general “Guidelines for Wildcard Use”:

Using a wildcard as a return type should be avoided because it forces programmers using the code to deal with wildcards.

The ? extends in the Stream’s element type produces a complication without any benefit. You can always create a Stream<Something> even from a source that has a more specific type, e.g.

SubTypeOfSomething subTyped = …

// from specific values
Stream<Something> s1 = Stream.of(subTyped);

// from existing collection
Set<SubTypeOfSomething> set = Collections.singleton(subTyped);
// note: this creates the stream directly from the source set
Stream<Something> s2 = Collections.<Something>unmodifiableSet(set).stream();

// if you really unavoidably have a more specifically typed Stream
Stream<SubTypeOfSomething> s3 = set.stream();
Stream<Something> s4 = s3.map(Function.identity());

The Stream<? extends Something> doesn’t offer anything the Stream<Something> doesn’t offer too.

It would be a different thing if the interface was typed instead, like following RC’s suggestion:

interface SomeRepository<T extends Something> {
    Stream<T> getStream();
}

Then, you don’t have a wildcard anymore and a more specifically typed stream might offer a benefit.

Question:

Say I've got this code:

public void doSomething(Collection<Item> batch)  { 
   batch.stream()      
   .filter(item -> item.group_id == 1)      
   .forEach(this::processItem);
}

processItem() is private method.

In real life the filter is more complex. I want to construct a unit test to verify a Collection items that all should fail the filter check, will result in forEach() never being invoked.

2 caveats:

  • Cannot modify doSomething() method signature
  • Prefer to keep processItem() private void method

Answer:

You could make the consumer invoked by forEach() a settable field:

private Consumer<Item> processingAction = this::processItem;

public void setProcessingAction(Consumer<Item> action) {
   this.processingAction = action;
}

public void doSomething(Collection<Item> batch)  { 
   batch.stream()      
   .filter(item -> item.group_id == 1)      
   .forEach(processingAction);
}

Now your test can be:

objUnderTest.setProcessingAction( item -> assertThat(item.groupId, is(1)));
objUnderTest.doSomething(listContainingItemsFromOtherGroups);

No need for Mockito here - your test-double is a lambda. You can, of course, mock a Consumer<Item> if you prefer.

It's a bit of a smell having a method just for testing (setProcessingAction()) - but that's because of the hard-coding and tight-coupling you've chosen to do. Why not take the opportunity to make injection (possibly constructor-injection) the primary way of setting the action?

If you're unwilling to make the action injectable, then you're stuck with processItem() always being called, and the effects of processItem() will be the only way to know what items were filtered.

Question:

I am writing a test where i have a set which will be put in to a method. I will then mock the method so it always returns return true.

I want to be able do this with help of a stream, so i can have a large Set. I am using JUnit4 for testing and Mockito for mocking.

Example:

setWithValues.stream().map(value-> when(method.returnTrueOrFalse(value)).thenReturn(true));

Answer:

While I can only speculate what the problem is with the code, my guess is the mocking is never executed for the absence of a terminal operation, it feels just wrong. The thing is it introduces new stubbing for every value in your set. Consider following alternative:

when(method.returnTrueOrFalse(Mockito.argThat(org.hamcrest.collection.IsIn.isIn(setWithValues)))).thenReturn(true);
// Or with static imports
when(method.returnTrueOrFalse(argThat(isIn(setWithValues)))).thenReturn(true);

It will aid debugability and will scale better with your set growing larger.

Question:

So I am using java 8 and trying to write some tests with PowerMock and Mockito. I am getting a MethodNotFoundException with the message:

No methods matching the name(s) stream were found in the class hierarchy of class java.util.Arrays$ArrayList.

I double checked the ArrayList documentation and it definitely looks like it inherits stream from Collections. Is this a problem with PowerMockito or am I missing something?

Line in question

PowerMockito.when(thing.call("services", "things")).thenReturn(Arrays.asList("testService")); // Doesn't matter if it's new ArrayList<String>()));

Then has something like this called on it

services.stream().filter( x -> //filter).collect(Collectors.toList())

EDIT: After further research this appears to be a PowerMock Problem. Would love a solution.


Answer:

This appeared to be a bug in PowerMock 1.5.5 and has been solved in 1.5.6

Reference: https://github.com/jayway/powermock/issues/536