logo
Solutionunittest

Mockito most common exceptions

Views: 546 Created: 2019-03-09 Read time: 3 minutes
Post Preview
Tags:

1)     Preface

In this solution, we will be looking at the three most common exception that can be thrown by Mockito engine during the runtime of a test. If you have been working with Mockito for a while, I am sure you have stumbled upon each and everyone here. If you are new to Mockito, guess what, you are going to stumble upon these a 100% I can tell you that.

 

2)     InvalidUseOfMatchersException

This is probably one of the most common ones. Take a look at the test method and try to spot the problem:

 

SUT Code


public void openLootChest(Hero hero, Chest chest){
    for(Lockpick lockpick: hero.getLockpicks()){
        boolean opened = gameEngine.attemptToOpen(lockpick
                , hero.getLockpickingLevel(), chest.getPercentageChanceToSpawnGuardian());

        hero.increaseLockpicking();
        chest.increaseChanceToSpawnGuardian();

        if(opened){
            hero.addMoney(chest.getMoney());
            return;
        }
    }
}

In this SUT method, we are:

      (L3):  The Hero tries to open the loot chest until he runs out of Lockpicks.

      (L10):  If he succeeds, whatever is in the chest, is added to his pocket. Now he can go to town and have some fun.

Let's try to run a test where we would like to make sure that he succeeds on the first try:

 

Test Code


@InjectMocks private GameController gameControllerSUT;
@Mock private GameEngine gameEngineMock;

@Test
public void shouldOpenLootOnFirstAttempt() throws Exception{
    // Arrange
    Hero hero = new Hero();
    Lockpick theLockpick = new Lockpick(1);
    hero.setLockpicks(Arrays.asList(
            new Lockpick[]{theLockpick, new Lockpick(2), new Lockpick(3)}));

    Chest chest = new Chest();

    when(gameEngineMock.attemptToOpen(theLockpick, anyInt(), anyInt()))
            .thenReturn(true);

    // Guard Assert
    assertThat(hero.getMoney()).isEqualByComparingTo(BigDecimal.valueOf(100));

    // Act
    gameControllerSUT.openLootChest(hero,chest);

    // Assert
    assertThat(hero.getMoney()).isEqualByComparingTo(BigDecimal.valueOf(100).add(chest.getMoney()));
}

In this test method, we are:

      (L15):  Making sure that with the use of the first theLockpick hero will open the chest. Regardless of what the outcome of getLockpickingLevel() and chest.getPercentageChanceToSpawnGuardian() are.

      (L25):  Validating the purse of the hero and whether it has been increased by what was in the chest.

When we run this test, we get:

 


org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
3 matchers expected, 2 recorded:
-> at com.sourceartists.rpg.controller.GameControllerTest.shouldOpenLootOnFirstAttempt

In order to fix that we need to wrap the concrete theLockpick input param with Mockito.eq():

 

Test Code


when(gameEngineMock.attemptToOpen(eq(theLockpick), anyInt(), anyInt()))
            .thenReturn(true);

 

 

3)     MissingMethodInvocationException

A lot of times, we will be dealing with methods that have some kind of restricted. Let us go back to the previous example. This time it has been decided by your team that this method should be final:

 

SUT Code


public final boolean attemptToOpen(Lockpick lockpick, Integer hero, Integer chest);

Ok, fine you say, but the next time you run your test suite you get something of following:

 


org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
For example:
    when(mock.getArticles()).thenReturn(articles);

You start thinking to yourself, damn why is this not working anymore, no logic has been changed. What happened? Well, once you look a bit lower the answer is presented to you:

 


Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
   Those methods *cannot* be stubbed/verified.
   Mocking methods declared on non-public parent classes is not supported.
2. inside when() you don't call method on mock but on some other object.

Mockito has its limitations, but in general, they are valid design-wise. You should not be interested in private methods at all in your tests. They are an implementation detail and are really an extension of one or many of the public methods. If you have too many of them, it is most likely time to refactor and clean up your class design. The equals and hashCode should simply not be messed up with mocking-wise. Test them explicitly but do not stub these. Let them run around the hills freely.

When it finally comes to the final methods, your SUT should be looking, somehow, for a way to become independent of them. For example, by wrapping the call with a package or protected level method. Then that SUT method may get stubbed easily.

 

Note
Note

  

4)     UnfinishedStubbingException

This one is pretty straightforward if we are dealing with situations like:

 

Test Code


when(gameEngineMock.giveSuperBuff(hero, superOffensiveBuff));

doNothing().when(heroSpy);

We get the exception and the solution all at the same time:

 


org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here:

    E.g. thenReturn() may be missing.
    Examples of correct stubbing:
        when(mock.isOk()).thenReturn(true);
        when(mock.isOk()).thenThrow(exception);
        doThrow(exception).when(mock).someVoidMethod();
    Hints:
     1. missing thenReturn()
     2. you are trying to stub a final method, you naughty developer!

This is obvious, but let us look at this example:

 

Test Code


when(gameEngineMock.giveSuperBuff(hero.getLevel(), hero.getMorale()))
	.thenReturn(prepareBuff());


private Buff prepareBuff(){
   Buff buffMock = mock(Buff.class);

   when(buffMock.isSuper()).thenReturn(true);

   return buffMock;
}

It seems that have the correct when().then() structure here. But when we run the test, we get the exact same exception as above.

Why is that? What is happening here is as follows:

      gameEngineMock.giveSuperBuff method is called.

      Static when method is called

      Private method prepareBuff() gets called.

      mock(Buff.class) is created and another stubbing starts at this point.

Now, to Mockito, this would look like:

 


when(gameEngineMock.giveSuperBuff(hero.getLevel(), hero.getMorale()))

when(buffMock.isSuper()).thenReturn(true);

So, in the end, we are facing the exact basic scenario where Mockito stumbles upon a when() without then().

 

5)     Conclusion

 

Summary

 

We have gone through Mockito's three most common exceptions. You should know the solutions to these by heart, if you were to be treated as a Java automation artist.

Need more insight?
Repository
Repository
Glossary
Glossary
Tags:
Reference
You may also like:
mockito-wildcards
Mockito wildcards
unit-testing-common-mistakes
Unit testing common mistakes
bdd-mockito
BDD Mockito
Comments
Be the first to comment.
Leave a comment