1. Overview

In this tutorial, we're going to look at defining multiple expectations on a mock. Generally, we configure a method on the mock object to return some controlled value. In this case, the mock object always returns the same value. However, we can also configure the mock to return a value on the first invocation and some other value on the second invocation.

2. Sample Application

Let's start with our sample application.

Firstly, we've PersonRepository which manages data access operations. Secondly, we've PersonService which declares PersonRepository as a dependency:

public class PersonService {
    private final PersonRepository personRepository;
    public PersonService(PersonRepository personRepository) {
        this.personRepository = personRepository;
    }
    public Person update(Person person) {
        return personRepository.update(person);
    }
}
public class PersonRepository {
    public Person update(Person person) {
        return person;
    }
}

3. Multiple Expectations On A Mock

Mockito enables us to create expectations in the form of when().thenReturn() statements. When we configure a mock method with only one behavior, all invocations of that method will return the same value. However, there are cases where we must return different values on different invocations. We'll achieve this by chaining the expectations:

@InjectMocks
private PersonService personService;

@Mock
private PersonRepository personRepository;

@Test
public void shouldDefineMultipleExpectations() {
    Person firstExpected = new Person("first");
    Person secondExpected = new Person("second");
    Mockito.when(personRepository.update(Mockito.any(Person.class))).thenReturn(firstExpected).thenReturn(secondExpected);

    Person firstPerson = personService.update(new Person("test"));

    Assertions.assertThat(firstPerson).isEqualTo(firstExpected);

    Person secondPerson = personService.update(new Person("test"));

    Assertions.assertThat(secondPerson).isEqualTo(secondExpected);
}

Here, we have two cascaded thenReturn statements - defining the behavior of update. As a result, when we first call the update method, it'll return firstExpected. When it's called again, it'll return secondExpected.

But be aware that rewriting the expectation with a different value doesn't give the same behavior:

@Test
public void shouldNotDefineMultipleExpectations() {
    Person firstExpected = new Person("first");
    Person secondExpected = new Person("second");
    Mockito.when(personRepository.update(Mockito.any(Person.class))).thenReturn(firstExpected);
    Mockito.when(personRepository.update(Mockito.any(Person.class))).thenReturn(secondExpected);

    Person firstPerson = personService.update(new Person("test"));
    // Will fail!
    Assertions.assertThat(firstPerson).isEqualTo(firstExpected);

    Person secondPerson = personService.update(new Person("test"));

    Assertions.assertThat(secondPerson).isEqualTo(secondExpected);
}

Here we aren't chaining the thenReturn calls, instead, we're overriding the expected return value.

4. Summary

In this tutorial, we've looked at how we can define multiple expectations and then return different values using Mockito.

As always, the source code for all examples in this tutorial is available on Github.