Stub multiple calls

One of the basics concepts in Mocking is the stubbing.

Wikipedia gives us this definition of stubbing:

“A method stub or simply stub in software development is a piece of code used to stand in for some other programming functionality. ”

In ApexMocks we can stub a method to return a value, or to throw an exception. We can even specify a custom answer when we need more flexibility and power.

Historically the stubbing with ApexMocks can handle only one value at the time.

What if you need to stub a method to return different values or different exceptions each time is called. Well, you could write an Answer and shape what you need, or…

Mockito, from which ApexMock get inspiration, have a specific syntax for that so why ApexMock shouldn’t have as well?

Now you can.

Every one of us has a friend that is not reliable time wise. They great, but they almost cannot make in time at a meeting. Everyone turned up, but not Franck. Then if you call them asking for an estimate of the time they would be there you get each time different time values… and potentially different excuses but for now, let’s keep it simple and concentrate on the times.

MY_MOCKS.when( everyoneTurnedUp.callFrankToFiguredOutWhenHisGonnaArrive()).
    thenReturn(new Time(15 minutes)).
    thenReturn(new Time(20 minutes)).
    thenReturn(new Time(10 minutes)).
    thenThrow(newBeInTimeException('we are all here, hurry up!')). //you are fed up of waiting and shout at Franck to be quicker
    thenReturn(new Time(0 minute)); //he finally arrived

When then you call the callFrankToFiguredOutWhenHisGonnaArrive() this would return 15 the first time, 20 the second, 10 the third, then would throw an exception for the fourth invocation, and for all the other subsequences calls would return zero.

This is possible because those methods can be chained together and define precisely what you need.

To be fair you could write that stubbing in a more compact way using the thenReturnMulti() stubbing method:

MY_MOCKS.when( everyoneTurnedUp.callFrankToFiguredOutWhenHisGonnaArrive()).
    thenReturnMulti(new List<Time>{minutes15, minutes20, minutes10}).
    thenThrow(new BeInTimeException('we are all here, hurry up!')).
    thenReturn(new Time(0 minute));

Similarly, there is the possibility to specify a sequence of Exception that you want to throw sequentially, with the thenThrowMulti() and a list of exceptions as the parameter.

thenReturnMulti() and thenThrowMulti() are not perfectly compliant with Mockito. Mockito uses the same name for the single argument version and the multiple argument version, using an iterable as the parameter of the multi. In Apex we are more limited. The thenReturnMulti() needs to take as a parameter  a list of objects,  and the thenReturn() needs an object. A list of objects is still an object, isn’t it?

If we stubbed N times a method and then the method is called more times than N, after N the value returned would be the one in the last stub. In our case after the fifth time, it would return constantly zero.

One last detail, if you stub the same method multiple times the last stub override the others, for example:

MY_MOCKS.when( everyoneTurnedUp.callFrankToFiguredOutWhenHisGonnaArrive()).
    thenReturn(new Time(5 minutes));

MY_MOCKS.when( everyoneTurnedUp.callFrankToFiguredOutWhenHisGonnaArrive()).
    thenReturn(new Time(10 minutes));

MY_MOCKS.when( everyoneTurnedUp.callFrankToFiguredOutWhenHisGonnaArrive()).
    thenReturn(new Time(11 minutes));

the last stub would override the two previous of 5 and 10 minutes.

The stubbing for sequential calls gives you the flexibility to cover those cases that a simple return is not enough, but with out need to write a custom answer.

Happy Mocking.




Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s