Creating chained returns in a loop

1,901 views
Skip to first unread message

Clint C

unread,
Apr 11, 2011, 1:13:50 PM4/11/11
to mockito
I'm trying to dynamically add some thenReturns() calls. This way i can
programatically build my Mock object

I have a method that returns 50 entries at a time, and the app will
keep reading it until it gets 0. So to mock it out currently I write

when(myService.getEntries())
.thenReturn(sampleElements(50))
.thenReturn(sampleElements(50))
.thenReturn(sampleElements(24)) //the remainder
.thenReturn(sampleElements(0));


Here is how I'd tried writing it:

OngoingStubbing<List<SimpleDoc>> dbService =
whhen(service.get50DocsByUserNameOrIdFromDate(anyString(), eq("JUnit
Test User 1"), eq("Z1234"), anyString()));

while(user1SampleDocs > 50){
dbService.thenReturn(sampleDocuments(50));
user1SampleDocs = user1SampleDocs - 50;
}
dbService.thenReturn(sampleDocuments(user1SampleDocs));
dbService.thenReturn(sampleDocuments(0));


But I end up getting a IndexOutOfBounds since Mockito tried to
'removeLastInvocation'

Brice Dutheil

unread,
Apr 12, 2011, 6:07:53 AM4/12/11
to moc...@googlegroups.com, Clint C
Hi,

Throwing IndexOutOfBoundsException looks like a bug. We'll fix it.

However you have two workarounds, 

First, you have to actually, change the reference of the dbServiceOngoingStubbing :
 
OngoingStubbing<List<SimpleDoc>> dbServiceOngoingStubbing =
when(service.get50DocsByUserNameOrIdFromDate(anyString(), eq("JUnitTest User 1"), eq("Z1234"), anyString()));

while(user1SampleDocs > 50){
    
dbServiceOngoingStubbing = dbServiceOngoingStubbing.thenReturn(sampleDocuments(50));
    user1SampleDocs -= 50;
}
dbService
OngoingStubbing.thenReturn(sampleDocuments(user1SampleDocs));
dbServiceOngoingStubbing.thenReturn(sampleDocuments(0));

Currently, what is important is to store the reference to the first stub.



The second way is to prepare the first answer, the other consecutive answers, then call thenReturn:
Something like (modulo some compiler warnings / error) : 

user1SampleDocs -= 50; // start one page further
List<List<SimpleDoc>> otherPages = newArrayList();
while(user1SampleDocs > 50){
    
otherPages.add(sampleDocuments(50));
    user1SampleDocs -= 50;
}

when(service.get50DocsByUserNameOrIdFromDate(anyString(), eq("JUnitTest User 1"), eq("Z1234"), anyString()))
.thenReturn(sampleDocument(50), otherPages.toArray())
.thenReturn(sampleDocuments(user1SampleDocs))
.thenReturn(sampleDocuments(0));



Hope that helps :)




-- 
Bryce



--
You received this message because you are subscribed to the Google Groups "mockito" group.
To post to this group, send email to moc...@googlegroups.com.
To unsubscribe from this group, send email to mockito+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/mockito?hl=en.


Clint Checketts

unread,
Apr 12, 2011, 8:19:17 AM4/12/11
to Brice Dutheil, moc...@googlegroups.com
Excellent workaround Brice! I see how keeping each new ongoing stub is returning a new ongoing stub, effectively chaining them. That makes for much better looking code. Also I have to get the reference for each ongoing stub, not just the first one.

I'd actually resorted to your second suggestion on my own, but the resulting code was very ugly, and would have scared off any of this test's maintainers.

Thanks for the quick reply, is there a Jira or issue tracker you'd like me to log the bug in?

Also for others reading this list here is the end workaround. I added a comment to point out the required addition since I had to read it a couple of times to see it:

//Store our initial stubbing, note we haven't done any htenReturns calls yet

OngoingStubbing<List<SimpleDoc>> dbServiceOngoingStubbing =
when(service.get50DocsByUserNameOrIdFromDate(anyString(), eq("JUnitTest User 1"), eq("Z1234"), anyString()));

while(user1SampleDocs > 50){
    //Each time we do a thenReturn, we store the newly returned ongoingStubbing, like a manual chaining
    
dbServiceOngoingStubbing = dbServiceOngoingStubbing.thenReturn(sampleDocuments(50));
    user1SampleDocs -= 50;
}
dbServiceOngoingStubbing = dbServiceOngoingStubbing.thenReturn(sampleDocuments(user1SampleDocs));
//Our last thenReturn call. since we aren't assigning it back to our variable it tells us we are finished with this stub
dbServiceOngoingStubbing.thenReturn(sampleDocuments(0));


-Clint

Brice Dutheil

unread,
Apr 12, 2011, 8:38:12 AM4/12/11
to Clint Checketts, moc...@googlegroups.com
Yup that's the idea.

Though I must say I would prefer to not expose to the "reader" the OngoingStubbing object reference. It might be a bit better for readability, which is super important. Also exposing OngoingStubbing in your test might give bad ideas to your coworkers or future one, especially if those are newbies (which all of us were at some point).

Options to do that will differ on a case by case basis. For example, you could naively just concatenate all following results instead of what I proposed to you earlier, ie only one call to "thenReturn("result1", otherMeaningfulResultsArray)", where otherResultArray is prepared elsewhere, maybe in another method. Or you can do something up to you imagination :)


And about the bug I logged it there : http://code.google.com/p/mockito/issues/detail?id=256


Thanks for reporting the bug anyway :)


Regards,


-- 
Bryce
Reply all
Reply to author
Forward
0 new messages