Contents

Mockito: Return value based on stub input arguments

Writen by: David Vlijmincx

Before I start the article, I want you to know that this is a controversial feature. It is still important that you know how it works, but I also want to show you alternative approaches that will let you do the same but doesn't hurt the readability of your tests.

Introduction

In this article, I show you how to change the return value of a stubbed method. If creating multiple test methods doesn't fit your use case, you can let a mock change the output based on the input arguments. I am going to show you three ways you could do this.

1
2
3
4
5
public class Dog {
    public String WantToPlayFetch(String name) {
        // Implementation...
    }
}

thenAnswer

The most powerful way of changing the return value of a stubbed method is to use the thenAnswer method. The method allows you to pass a lambda that will run when the method is called. In the following example, I am going to stub the WantToPlayFetch and base the reply on the input using thenAnswer. When the WantToPlayFetch gets called with “Max” it will return a different value than when the method is called with “Michel” as a parameter.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
 @Test
void thenAnswer() {
    Dog mockDog = mock(Dog.class);

    when(mockDog.WantToPlayFetch(anyString())).thenAnswer(invocation -> {
        String name = invocation.getArgument(0);

        if (name.equals("Max")) {
            return "Yes i want to play!";
        } else {
            return "That is not my name";
        }
    });


    Assertions.assertEquals("Yes i want to play!", mockDog.WantToPlayFetch("Max"));
    Assertions.assertEquals("That is not my name", mockDog.WantToPlayFetch("Michel"));
}

Returning the input parameters

With “thenAnswer” you can do one more trick and that is to return the input parameter of the stubbed method. In the following example the stubbed “WantToPlayFetch” method will return whatever the input parameter is.

1
2
3
4
5
6
7
8
9
@Test
void returningTheInput() {
    Dog mockDog = mock(Dog.class);

    when(mockDog.WantToPlayFetch(anyString())).thenAnswer(invocation -> invocation.getArgument(0));

    Assertions.assertEquals("Max", mockDog.WantToPlayFetch("Max"));
    Assertions.assertEquals("Michel", mockDog.WantToPlayFetch("Michel"));
}

Multiple thenReturn statements

Another way to have different kinds of output for your input parameters is to have multiple thenReturn statements. I would recommend creating multiple tests method instead of doing it this way. Just know that it is possible. In the following example I stubbed the WantToPlayFetch using two thenReturn statements.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
@Test
void WhenThen() {
    Dog mockDog = mock(Dog.class);

    when(mockDog.WantToPlayFetch("Max")).thenReturn("Yes!");
    when(mockDog.WantToPlayFetch("Michel")).thenReturn("Who is that?");

    Assertions.assertEquals("Yes!", mockDog.WantToPlayFetch("Max"));
    Assertions.assertEquals("Who is that?", mockDog.WantToPlayFetch("Michel"));
}

Specify return values for consecutive calls

There is also an overloaded thenReturn method that takes multiple arguments. You can use the overloaded thenReturn method to specify the return values for consecutive calls. In the following example, the WantToPlayFetch method is stubbed to return:

  • “Yes!” as the first value
  • “No!” as the second value
  • “Maybe?” as the last value.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
@Test
void consecutiveCalls() {
    Dog mockDog = mock(Dog.class);

    when(mockDog.WantToPlayFetch(anyString())).thenReturn("Yes!", "No!", "Maybe?");

    Assertions.assertEquals("Yes!", mockDog.WantToPlayFetch("Max"));
    Assertions.assertEquals("No!", mockDog.WantToPlayFetch("Max"));
    Assertions.assertEquals("Maybe?", mockDog.WantToPlayFetch("Max"));
}

Conclusion

In this article, we saw multiple ways how you could change the return value of a stubbed method based on the input.

Further reading

More about testing in Java:

 




Questions, comments, concerns?

Have a question or comment about the content? Feel free to reach out!