Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Enumerating list in mockito's thenReturn

Is there a way to enumerate the items in a list within mockito's thenReturn function so I return each item in a list. So far I've done this:

List<Foo> returns = new ArrayList<Foo>();
//populate returns list

Mockito.when( /* some function is called */ ).thenReturn(returns.get(0), returns.get(1), returns.get(2), returns.get(3));

This works exactly how I want it to. Each time the function is called, it returns a different object from the list, e.g get(1), get(2) etc.

But I want to simplify this and make it more dynamic to any size list in case I have a list with size say 100. I tried something like this:

Mockito.when( /* some function is called */ ).thenReturn(
    for(Foo foo : returns) {
        return foo;
    }
);

I've tried this as well:

Mockito.when(service.findFinancialInstrumentById(eq(1L))).thenReturn(
    for (int i=0; i<returns.size(); i++) {
        returns.get(i);
    }
);

But this doesn't work....so how do I enumerate this list within the thenReturn....I've come across other methods to like then or answerbut I'm not sure which one works best in this scenario.

like image 996
Richard Avatar asked Oct 23 '15 20:10

Richard


2 Answers

The thenReturn() method signature is

thenReturn(T value, T... values)

So it takes an instance of T, followed by a vararg T..., which is syntactic sugar for an array. So you can use

when(foo.bar()).thenReturn(list.get(0), 
                           list.subList(1, list.size()).toArray(new Foo[]{}));

But a cleaner solution would be to create an Answer implementation that takes a List as argument and answers the next element of the list every time it's used. And then use

when(foo.bar()).thenAnswer(new SequenceAnswer<>(list));

For example:

private static class SequenceAnswer<T> implements Answer<T> {

    private Iterator<T> resultIterator;

    // the last element is always returned once the iterator is exhausted, as with thenReturn()
    private T last;

    public SequenceAnswer(List<T> results) {
        this.resultIterator = results.iterator();
        this.last = results.get(results.size() - 1);
    }

    @Override
    public T answer(InvocationOnMock invocation) throws Throwable {
        if (resultIterator.hasNext()) {
            return resultIterator.next();
        }
        return last;
    }
}
like image 187
JB Nizet Avatar answered Nov 19 '22 03:11

JB Nizet


Another way of doing it (but personally, I prefer JB Nizet SequenceAnswer idea), would be something like this...

OngoingStubbing stubbing = Mockito.when(...);
for(Object obj : list) {
    stubbing = stubbing.thenReturn(obj);
}
like image 13
Florian Schaetz Avatar answered Nov 19 '22 02:11

Florian Schaetz