JUnit can you use verify() and doReturn() at the same time?

Viewed 27

I have some async calls using CompletableFutures and my unit tests are failing. Most of the time they are not failing, but once in a while they may fail… I'm getting the error message that:

org.mockito.exceptions.misusing.PotentialStubbingProblem: 
Strict stubbing argument mismatch. Please check:
 - this invocation of 'queryForList' method:
    namedParameterJdbcTemplate.queryForList(
    null,
    MapSqlParameterSource {id=0},
    class java.lang.String
);
...
Typically, stubbing argument mismatch indicates user mistake when writing tests.
Mockito fails early so that you can debug potential problem easily.
However, there are legit scenarios when this exception generates false negative signal:
  - stubbing the same method multiple times using 'given().will()' or 'when().then()' API
    Please use 'will().given()' or 'doReturn().when()' API for stubbing.
  - stubbed method is intentionally invoked with different arguments by code under test
    Please use default or 'silent' JUnit Rule (equivalent of Strictness.LENIENT).

I've tried using doReturn().when() but it still gave the same error. Using Mockito.lenient() fixed it, but I feel using the Mockito.verify() method is the correct approach for this stubbing/async problem.

After adding the verification and the mock to return:

        Mockito.verify(namedParameterJdbcTemplate, Mockito.timeout(100).times(1)).queryForList(Mockito.anyString(), Mockito.any(MapSqlParameterSource.class), Mockito.eq(String.class));
        Mockito.verify(namedParameterJdbcTemplate, Mockito.timeout(100).times(1)).query(Mockito.anyString(), Mockito.any(MapSqlParameterSource.class), Mockito.any(BasicMapper.class));

        Mockito.when(namedParameterJdbcTemplate.queryForList(Mockito.anyString(), Mockito.any(MapSqlParameterSource.class), Mockito.eq(String.class))).thenReturn(null);
        Mockito.when(namedParameterJdbcTemplate.query(Mockito.anyString(), Mockito.any(MapSqlParameterSource.class), Mockito.any(BasicMapper.class))).thenReturn(offerEvents);

I got this error

Wanted but not invoked:
namedParameterJdbcTemplate.queryForList
...
Actually, there were zero interactions with this mock.

Whats the best way I can resolve this issue?

1 Answers

You don't show the full test code, but you probably put the verify before the code you're testing. Move it so it is after the code you're testing.

when is used to setup the mock, so it must be called before code that calls the mock to get the data.

verify checks if a method was called on the mock as expected, so it must be called after the code that calls the mock, otherwise nothing has happened yet, and the verification will fail.

As an aside, if your code also verifies a result which depends on the data provided by the mock, it is not really necessary to also perform verification on the mock: the fact you get the expected data based on the setup done with when should be sufficient confirmation that the mock was called.

Related