Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling Mockito.when multiple times on same object?

When trying to use Mockito with Spring, by creating the Mock object via a bean declaration...

<bean id="accountMapper" class="org.mockito.Mockito" factory-method="mock"> 
    <constructor-arg value="org.example.persistence.mybatis.mappers.AccountMapper" /> 
</bean>     

...I found some strange behavior when calling Mockito.when multiple times without reseting the Mock object, for example:

Mockito.when(this.accountMapper.createBadGrammarException()).thenThrow(new BadSqlGrammarException("Bla", null, new SQLException()));

As soon as this code (the "Mockito.when") is called multiple time during the test (on the same mock), the tests fails with an error (BadSqlGrammerException even if this exception was what was actually expected - I do get a failure if I don't throw the exception, and throwing it manually works fine). Is this expected behavior? Mockito seems to suggest creating a new mock every time, which would mean creating the DAO for each method...?

What exactly happens when I call the Mockito.when method two times? How should the mock react? Replace the behavior? Ignore it? Unfortunately most searches only yield results for how to return different results for multiple calls to the method itself, but not what is to be expected for multiple calls to Mockito.when...

I'm simply trying to understand Mockito and best practices here, because going with something just because it SEEMS to works seems to be a bad idea...

like image 213
Florian Schaetz Avatar asked Jul 20 '15 08:07

Florian Schaetz


1 Answers

One of the problems with Mockito.when is that the argument you pass to it is the expression that you're trying to stub. So when you use Mockito.when twice for the same method call, the second time you use it, you'll actually get the behaviour that you stubbed the first time.

I actually recommend NOT using Mockito.when. There are many traps that you can fall into when you use it - quite a few cases when you need some other syntax instead. The "safer" alternative syntax is the "do" family of Mockito methods.

doReturn(value).when(mock).method(arguments ...);
doThrow(exception).when(mock).method(arguments ...);
doAnswer(answer).when(mock).method(arguments ...);

So in your case, you want

doThrow(new BadSqlGrammarException(??, ??, ??)).when(accountMapper).createBadGrammarException();

If you are starting out with Mockito, then I recommend that you learn to use the "do" family. They're the only way to mock void methods, and the Mockito documentation specifically mentions that. But they can be used whenever Mockito.when can be used. So if you use the "do" family, you'll end up with more consistency in your tests, and less of a learning curve.

For more information about the cases when you must use the "do" family, see my answer on Forming Mockito "grammars"

like image 171
Dawood ibn Kareem Avatar answered Sep 19 '22 09:09

Dawood ibn Kareem