In this recipe, we will stub a void method that doesn't return a value, so it returns a custom answer.
For this recipe, our system under test will be the same class as the one in the previous recipe, but let's take another look at it so that you don't need to scroll around to see the source code. The PersonProcessor
class does only one thing for simplicity: it delegates the process of saving person
to the PersonSaver
class. As shown in the following code, in case of success, true is returned; otherwise, false is returned:
public class PersonProcessor { private final PersonSaver personSaver; public PersonProcessor(PersonSaver personSaver) { this.personSaver = personSaver; } public boolean process(Person person) { try { personSaver.savePerson(person); return true; } catch (FailedToSavedPersonDataException e) { System.err.printf("Exception occurred while trying save person data [%s]%n", e); return false; } } }
If you want your void method to throw an exception upon calling, you need to perform the following steps:
BDDMockito.willAnswer(answer).given(mock).methodToStub()
, or in the standard way, call Mockito.doAnswer(answer).when(mock).methodToStub()
.given(...)
or when(...)
method, you have to provide the mock object (and not the method call like in the case of methods that return values).willAnswer(answer1).willAnswer(answer2).given(personSaver).savePerson(smith);
Then, regardless of the number of personSaver.savePerson(...)
method executions, first answer1
logic will be executed, and then you will always have the answer2
logic executed (until it is stubbed again).
Let's check the JUnit test. See Chapter 1, Getting Started with Mockito, for the TestNG configuration (remember that I'm using BDDMockito.given(...)
and AssertJ's BDDAssertions.then(...)
static methods. Check out Chapter 7, Verifying Behavior with Object Matchers, for more details on how to work with AssertJ or how to do the same with Hamcrest's assertThat(...)
):
@RunWith(MockitoJUnitRunner.class) public class PersonProcessorTest { @Mock PersonSaver personSaver; @InjectMocks PersonProcessor systemUnderTest; @Test public void should_fail_to_save_person_data_due_to_having_undefined_country() { // given willAnswer(new Answer() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { if (invocation.getArguments().length > 0) { Person person = (Person) invocation.getArguments()[0]; if (!person.isCountryDefined()) { throw new FailedToSavedPersonDataException("Undefined country"); } } return null; } }).given(personSaver).savePerson(any(Person.class)); // when boolean updateSuccessful = systemUnderTest.process(new Person()); // then then(updateSuccessful).isFalse(); } }
Please refer to the Stubbing void methods recipe for more information on the Mockito internals related to stubbing void methods.
As you can see, the Answer
interface has the following method:
public Object answer(InvocationOnMock invocation) throws Throwable
Note that since we have a void method to stub, we don't care about the answer's returned value. That is why we return null in the answer's body.
doReturn()
|doThrow()
|doAnswer()
|doNothing()
|doCallRealMethod()
family of methods at http://docs.mockito.googlecode.com/hg/1.9.5/org/mockito/Mockito.html#123.14.134.17