1. Overview

In this tutorial, we’ll explore different ways of returning custom values from mocked methods. For this purpose, Mockito provides Answer interface. Throughout the article, we will cover different use cases and different Answer implementations.

2. Detailing Answer Interface

Let’s start with investigating the Answer interface.

The Answer interface enables us to define custom return values and has the following contract:

public interface Answer<T> {
    /**
     * @param invocation the invocation on the mock.
     *
     * @return the value to be returned
     *
     * @throws Throwable the throwable to be thrown
     */
    T answer(InvocationOnMock invocation) throws Throwable;
}

It has an answer() method with the invocation parameter which provides us runtime related information. Moreover, it returns a value parameterized as T.

Next, let’s see how we can use Answer implementations.

When defining return values we generally use when().thenReturn() statements. However, for Answer implementations, we should use when().then() statement:

Mockito.when(mockCall()).then(new customAnswer())

3. Accessing the Arguments during Mocking

Now, we’ll look at how we can access method arguments in an Answer implementation.

But before that, let’s see our sample classes. We have the PersonRepository and PersonService classes. Also, note that PersonService includes PersonRepository as a dependency.

public class PersonService {
    private final PersonRepository personRepository;
    public PersonService(PersonRepository personRepository) {
        this.personRepository = personRepository;
    }
...
    public Person select(Person first, Person second, Person third) {
        return personRepository.select(first, second, third);
    }
}
public class PersonRepository {
...
    public Person select(Person first, Person second, Person third) {
        return first;
    }
}

Our Answer implementation will return the first argument:

@InjectMocks
private PersonService personService;

@Mock
private PersonRepository personRepository;

@Test
public void shouldReturnFirstPerson() {
    Person firstPerson = new Person("first");
    Person secondPerson = new Person("second");
    Person thirdPerson = new Person("third");
    Mockito.when(personRepository.select(firstPerson, secondPerson, thirdPerson))
           .thenAnswer(new Answer<Person>() {
               @Override
               public Person answer(InvocationOnMock invocation) throws Throwable {
                   return invocation.getArgumentAt(0, Person.class);
               }
           });

    Person actual = personService.select(firstPerson, secondPerson, thirdPerson);

    Assertions.assertThat(actual).isEqualTo(firstPerson);
}

Here, we’re getting the first argument from invocation instance and expecting it to be the type of Person class. Then we are returning this Person instance.

4. Calling the Real Method during Mocking

Alternatively, we can also call the real method in an Answer implementation:

@Test
public void shouldCallRealMethod() {
    Person firstPerson = new Person("first");
    Person secondPerson = new Person("second");
    Person thirdPerson = new Person("third");
    Person other = new Person("other");
    Mockito.when(personRepository.select(firstPerson, secondPerson, thirdPerson))
           .thenAnswer(new Answer<Person>() {
               @Override
               public Person answer(InvocationOnMock invocation) throws Throwable {
                   return (Person) invocation.callRealMethod();
               }
           });

    Person actual = personService.select(firstPerson, secondPerson, thirdPerson);

    Assertions.assertThat(actual).isEqualTo(firstPerson);
}

Here, our Answer implementation calls the real method – PersonRepository.select() – and returns firstPerson.

5. Summary

In this tutorial, we investigated how we can return custom values on mocked methods using Answer interface.

As always, the source code is available on Github.

Leave a Reply

Close Menu