Contents

Mockito using thenReturn and thenAnswer

Writen by: David Vlijmincx

Introduction

In this post, we are going to look at how to return a specific mock based on the input. Sometimes you want to return a specific mock when a certain input is given. I will show you two ways of achieving this by using thenReturn and thenAnswer.

When to use thenReturn or thenAnswer

Both methods let you decide what a mocked object returns. thenReturn() returns a fixed value while thenAnswer() lets you use the parameters to determine a return value.

To give you an idea of how to use these two methods, we are going to mock this class:

1
2
3
4
5
public class Person {
    public String talk(String input){
        return "Hello";
    }
}

Using thenReturn()

Here we use thenReturn() to return the fixed value “Good morning”. It will return this no matter what the input String is for the talk(String input) method.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

class PersonTest {

    @Test
    void testChangePersonResponse_ThenReturn(){
        // Create a mock of person
        Person person = mock(Person.class);
        // When the talk(String input) method is called with "any()" String we return Good morning.
        when(person.talk(any())).thenReturn("Good morning");
        // Check that the return value is Good morning when we call talk() with "any String"
        assertEquals("Good morning", person.talk("any String"));
    }
}

Implementing thenAnswer() functionality with thenReturn()

Replacing the any() method with a fixed string, we can imitate the thenAnswer() method to a certain degree. This has a few downsides:

  • We split the responsibility of returning a value over multiple thenReturn() methods
  • We only return a value when one of the predefined when() methods are called
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

class PersonTest {

    @Test
    void testChangePersonResponse_WithWhenAndThenReturn(){
        // Create a mock of person
        Person person = mock(Person.class);

        // When the talk(String input) method is called with "any()" String we return Good morning.
        when(person.talk("Good morning")).thenReturn("Good morning to you to");
        when(person.talk("Good afternoon")).thenReturn("Good afternoon to you");

        // Check that the return value is Good morning when we call talk() with "any String"
        assertEquals("Good morning to you to", person.talk("Good morning"));
        assertEquals("Good afternoon to you", person.talk("Good afternoon"));
    }
}

Using thenAnswer()

thenAwnser() uses a lambda to decide what the mocked talk(String input) call returns. When we call the mocked person object now with any String the Lambda grabs the value of the first parameter (in this case input) and passes it to our function. This has the following advantages:

  • We can define a return value for each combination of input parameters.
  • The responsibility of what value is returned is now located in one when() call.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

class PersonTest {

    @Test
    void testChangePersonResponse_ThenAnswer(){
        // Create a mock of person
        Person person = mock(Person.class);

        // Return a value based on the first parameter
        when(person.talk(any())).thenAnswer(input -> "Good afternoon".equals(input.getArgument(0))?
            "Good afternoon to you to" :
            "Something else"
        );

        // Written out example of the lambda above
        when(person.talk(any())).thenAnswer(input -> {
            // get the first argument passed to to person.talk(String input)
            // in this case we only have one parameter and it is on place 0
            var firstMethodArgument = input.getArgument(0);

            // Decide what to return
            if ("Good afternoon".equals(firstMethodArgument)){
                return "Good afternoon to you to";
            } else {
                return "Something else";
            }
        });

        assertEquals("Good afternoon to you to", person.talk("Good afternoon"));
        assertEquals("Something else", person.talk("Good evening"));
    }
}

Conclusion

Both methods can be used to return a value based on the parameters. thenReturn() helps return fixed value but can be limiting when you want to return a more specific value. This is where thenAnwsers() really shines; it gives you full control over the return value and access to passed parameters.

Further reading

More about testing in Java: