Stubbing void methods so that they return custom answers

In this recipe, we will stub a void method that doesn't return a value, so it returns a custom answer.

Getting ready

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;
        }
    }

}

How to do it...

If you want your void method to throw an exception upon calling, you need to perform the following steps:

  1. Explicitly tell Mockito that the void method does nothing. For the BDD approach, call BDDMockito.willAnswer(answer).given(mock).methodToStub(), or in the standard way, call Mockito.doAnswer(answer).when(mock).methodToStub().
  2. Regardless of the chosen approach in the 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).
  3. Remember that the last passed value during the stubbing will be returned for each stubbed method call. In other words, say that you stub the mock as follows:
    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();
    }
  
}

How it works...

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.

See also

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.14.134.17