Stubbing void methods so that they call real methods

In this recipe, we will stub a method that is a void method. It doesn't return a value, so it calls a real method. This way, we will construct a partial mock (to read more about partial mocking, please refer to Chapter 2, Creating Mocks).

Getting ready

For this recipe, our system under test will be the same class as 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, for simplicity, does only one thing: 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;
        }
    }

}

Contrary to the previous recipe, PersonSaver is a class and not an interface. This verifies whether the person's origin is defined. If that is not the case, then FailedToSavedPersonDataException will be thrown.

How to do it...

If you want your void method to call real methods upon calling the void method, you need to perform the following steps:

  1. Explicitly tell Mockito that the void method should call the real implementation. For the BDD approach, call BDDMockito.willCallRealMethod().given(mock).methodToStub(), or in the standard way, call Mockito.doCallRealMethod().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 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:
    willCallRealMethod().willNothing().given(personSaver).savePerson(smith);

    This example shows you how to make your void method call the real method only once, and then do nothing, by default. Regardless of the number of personSaver.savePerson(...) method executions, first the real implementation will be called, and then you will always have no further execution (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
        willCallRealMethod().given(personSaver).savePerson(any(Person.class));

        // when
        boolean updateSuccessful = systemUnderTest.updatePersonData(new Person());

        // then
        then(updateSuccessful).isFalse();
    }
  
}

Note

Remember that if you need to create a partial mock, and if you really don't have some strong arguments to back that decision up, then you should rethink the architecture of your program or your tests since it most likely is not the best quality. Please refer to Chapter 3, Creating Spies and Partial Mocks, for more details.

How it works...

Please refer to the Stubbing void methods recipe for more information on the Mockito internals related to stubbing void methods.

What's worth mentioning is that the answer-taking part in the Mockito internal delegation process is the CallsRealMethod answer.

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.144.9.124