How does Mockito handle overlapping matchers with multiple arguments in the thenReturn block

java, mockito

Solution

I had this problem today. It is caused by calls to the mock to set up stubbing actually consuming the stubbing already in place.

In this example, change the first line to

when(mock.call(anyString())).thenReturn("","",string1,string2)

This will give you two blank responses when you set up your other mock returns, leaving string1 as the first useful return value.

Try also the doReturn alternative which I think may not have these issues:

doReturn(string1,string2).when(mock).call(anyString());

This uses the stub differently during setup.

So I did some more research on this. Here's the function I was playing with, based on the OP's question:

    Function<String, String> function = mock(Function.class);
    when(function.apply(anyString())).thenReturn("A","B","C");
    when(function.apply("Jim")).thenReturn("Jim");
    when(function.apply("Bob")).thenReturn("Bob");

    assertThat(function.apply("Jim")).isEqualTo("Jim");
    assertThat(function.apply("Bob")).isEqualTo("Bob");
    assertThat(function.apply("")).isEqualTo("A");
    assertThat(function.apply("")).isEqualTo("B");
    assertThat(function.apply("")).isEqualTo("C");
    assertThat(function.apply("")).isEqualTo("C");

The above fails at `isEqualTo("A")` because the two calls to set up the mocks for `Jim` and `Bob` consume return values from the list provided to `anyString()`.

You might be tempted to reorder the `when` clauses, but that fails, because the `anyString()` supersedes the special cases, so that fails too.

The following version of the above DOES work as expected:

    when(function.apply(anyString())).thenReturn("A","B","C");

    doReturn("Jim")
        .when(function)
        .apply("Jim");
    doReturn("Bob")
        .when(function)
        .apply("Bob");

    assertThat(function.apply("Jim")).isEqualTo("Jim");
    assertThat(function.apply("Bob")).isEqualTo("Bob");
    assertThat(function.apply("")).isEqualTo("A");
    assertThat(function.apply("")).isEqualTo("B");
    assertThat(function.apply("")).isEqualTo("C");
    assertThat(function.apply("")).isEqualTo("C");

This is because the `doReturn` technique, which is intended for modifying pre-existing mocks in flight, doesn't actually involve calling the method on the mock to set up the mocking.

You could use `doReturn` for all setup, rather than mixing between `when`...`thenReturn` and `doReturn`..`when`..`function()`. As it happens, that's a bit uglier:

    doReturn("A").doReturn("B").doReturn("C")
        .when(function)
        .apply(anyString());

There's no convenient `varargs` function to let you specify multiple returns in sequence. The above has been tested and does work, though.

Problem

I've got a block of test code that is attempting to, in the generic case return two values on subsequent calls, but in specific cases only return the value associated with that case. The code looks something like: ``` when(mockObject.method(anyString())).thenReturn(string1, string2); when(mockObject.method(eq("expectedInput1"))).thenReturn(string1); when(mockObject.method(eq("expectedInput2"))).thenReturn(string2); ``` The expected behavior is that when calling `mockObject.method("foo")` and `mockObject.method("bar")`, `string1` and `string2` should be returned respectively, but the test is actually seeing two responses of `string2`. Is this a bug in `Mockito`? Or am I misunderstanding `Mockito` pattern matching. My assumption was that the last pattern to match is what is returned, but when going through that process does `Mockito` treat each argument in the first `thenReturn` block separately? Is there any way to get around this behavior? When I comment out the second two when calls, the mocks behave as expected, so I'm assuming there is something specific about the overlapping matcher behavior. Edit: This is in `Mockito` version `1.9.5`

Original source