Variable output of Mockito mocks
I have a class WidgetProcessor
that has a dependency on another class FizzChecker
,:
public class FizzChecker {
public boolean hasMoreBuzz() {
// Sometimes returns true, sometimes returns false.
}
}
This method hasMoreBuzz()
is called internally WidgetProcessor
as follows:
public class WidgetProcessor {
public int process() {
while(fizzChecker.hasMoreBuzz()) {
// ... process stuff in here
}
}
}
I want to write test cases when:
-
fizzChecker.hasMoreBuzz()
returns false the first time it is called (hence the loop is never executed) -
fizzChecker.hasMoreBuzz()
returns false the 5th time it is called
I am trying to figure out how to do this with Mockito. So far, my best (terrible) attempt is:
WidgetProcessor fixture = new WidgetProcessor();
FizzChecker mockFizzChecker = Mockito.mock(FizzChecker.class);
// This works great for the first test case, but what about the 2nd
// where I need it to return: true, true, true, true, false?
Mockito.when(mockFizzChecker).hasMoreBuzz().thenReturn(false);
fixture.setFizzChecker(mockFizzCheck);
fixture.process();
// Assert omitted for brevity
Thanks in advance.
You can pass multiple values to thenReturn
or store the chain . Consecutive calls to the truncated method return actions in sequence, repeating the final action for all calls. Examples:
// will return true four times, and then false for all calls afterwards
when(mockFizzChecker.hasMoreBuzz()).thenReturn(true, true, true, true, false);
when(mockFizzChecker.hasMoreBuzz())
.thenReturn(true)
.thenReturn(true)
.thenReturn(true)
.thenReturn(true)
.thenReturn(false);
// you can also switch actions like this:
when(someOtherMock.someMethodCall())
.thenReturn(1, 2)
.thenThrow(new RuntimeException());
You probably want to install them separately:
public class WidgetProcessorTest {
private WidgetProcessor processor;
private FizzChecker mockFizzChecker;
@Before public void setUp() {
processor = new WidgetProcessor();
mockFizzChecker = Mockito.mock(FizzChecker.class);
processor.setFizzChecker(mockFizzChecker);
}
@Test public void neverHasBuzz() {
when(mockFizzChecker.hasMoreBuzz()).thenReturn(false);
processor.process();
// asserts
}
@Test public void hasFiveBuzzes() {
when(mockFizzChecker.hasMoreBuzz())
.thenReturn(true, true, true, true, false);
processor.process();
// asserts
}
}
One final note: you may actually need to negotiate multiple calls (e.g. hasMoreBuzz
and getNextBuzz
). If it starts to get complicated and you plan on writing this in many tests, try skipping Mockito and just implementFakeFizzChecker
it instead .
source to share
Try using Answers . This will allow you to execute the code when you call the hasMoreBuzz () method.
Check out the example in the link above. If you create an Answer object and implement the answer () method to store a counter, you can take an action based on the value of that counter.
Edit: I wrote a quick test program to test this. Here he is:
package com.ejk;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.mock;
public class SO {
@Test
public void testIt() {
IFoo mock = mock(IFoo.class);
MyAnswer myAnswer = new MyAnswer();
when(mock.doFoo()).then(myAnswer);
for (int i=1; i<10; i++) {
System.out.println(i+ ") " + mock.doFoo());
}
}
class MyAnswer implements Answer<Boolean> {
int counter = 1;
@Override
public Boolean answer(InvocationOnMock invocation) throws Throwable {
return (counter++ == 5) ? Boolean.FALSE : Boolean.TRUE;
}
}
interface IFoo {
boolean doFoo();
}
}
source to share