logo
Solutionunittest

Mockito stubbing

Views: 654 Created: 2019-04-29 Read time: 5 minutes
Post Preview
Tags:

1)     Preface

Mockito's stubbing functionality is literally the core and heart of this framework. It opens the door to all the rest of its excellent features. Once stubbed, the behaviour of the mock can be verified in all the shape and forms. Whether something happened, something never happened, some things happened in exact order etc. There are many flavours of stubbing adequate in certain situations. Let's go through them together.

 

2)     Mockito stubbing: concrete arguments

Let's start off with a basic example where we expect a mocked object to return a particular value, provided a given set of parameters.

This time we will be observing our hero gaining a buff!

 

SUT Code


public void gainBuff(Hero hero, BuffType buffType){
    if(hero.getActiveBuff() != null){
        return;
    }

    if(gameEngine.giveSuperBuff(hero.getLevel(), hero.getMoraleLevel())){
        hero.setActiveBuff(new SuperBuff("super duper buff", buffType));

        return;
    }

    hero.setActiveBuff(new Buff("normal duper buff", buffType));
}

In this SUT method, we are:

      (L3):  If Hero already has a Buff, leave the method.

      (L7):  Here based on the level and morale of the Hero, the GameEngine decides whether a SuperBuff should be granted to the hero instead of a regular one.

      (L13):  A regular Buff is given to the Hero.

Now we would like to test a scenario where an actual SuperBuff is given to the Hero. The gameEngine.giveSuperBuff method is a bit more complicated than it seems in reality, and we would not like to call it directly. Instead, we just want to make sure when a minimal hero level and morale is passed, there is a chance the super version will be given.

 

Test Code


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

@Test
public void shouldGiveHeroSuperBuff() throws Exception{
    // Arrange
    Integer heroLevel = 75;
    Integer heroMorale = 8;
    Hero hero = new Hero();
    hero.setLevel(heroLevel);
    hero.setMoraleLevel(heroMorale);

    when(gameEngineMock.giveSuperBuff(75, 8)).thenReturn(true);

    // Act
    gameControllerSUT.gainBuff(hero, BuffType.OFFENSIVE);

    // Assert
    assertThat(hero.getActiveBuff()).isInstanceOf(SuperBuff.class);
    assertThat(hero.getActiveBuff().getBuffType()).isEqualTo(BuffType.OFFENSIVE);
}

In this test method, we are:

      (L3):  We create a mock of GameEngine class, and we inject it into the gameControllerSUT.

      (L8-12):  Setting up our input values.

      (L14):  We tell the gameEngineMock that when its giveSuperBuff method is called with 75 and 8 params respectively, it should return true.

      (L20,21):  We verify that the Hero has actually been granted an Offensive SuperBuff.

 

Tip
Tip

 

3)     Mockito stubbing: wildcard argument matchers

Sometimes we do not care about the exact parameter values that are passed to our stub. We would like to make sure that some of them are, but the rest.. if the type is right, it goes. This time we will try to steal from our enemies castle!

 

SUT Code


public void breakIntoCastleAndSteal(Hero hero, Castle castle){
    boolean mainDoorOpened = false;

    for(Lockpick lockpick: hero.getLockpicks()){
        boolean opened = gameEngine.attemptToOpenDoor(lockpick
                , hero.getLockpickingLevel());

        if(opened){
            mainDoorOpened = true;
            break;
        }
    }

    if(!mainDoorOpened){
        return;
    }

    BigDecimal jeweleryWorth = gameEngine.stealFromJeweleryBox(castle, hero);
    hero.addMoney(jeweleryWorth);
}

In this SUT method, we are:

      (L5):  Trying to open the main door as many times as many Lockipcks we have.

      (L19):  If the door was opened at some attempt, we stealFromJeweleryBox and add the value of jewels to Heros purse.

Now we would like to test a happy path scenario that assumes we unlock the door on the first attempt and get what is ours!

 

Test Code


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

@Test
public void shouldBreakIntoCastleAndStealJewelery() throws Exception{
    // Arrange
    Castle castle = new Castle();
    Hero hero = new Hero();
    BigDecimal jeweleryWorth = BigDecimal.valueOf(100);
    hero.setLockpicks(Arrays.asList(new Lockpick[]{new Lockpick(1), new Lockpick(2)}));

    when(gameEngineMock.stealFromJeweleryBox(castle, hero)).thenReturn(jeweleryWorth);

    when(gameEngineMock.attemptToOpenDoor(any(Lockpick.class), eq(hero.getLockpickingLevel())))
            .thenReturn(true);

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

    // Act
    gameControllerSUT.breakIntoCastleAndSteal(hero, castle);

    // Assert
    verify(gameEngineMock, times(1)).attemptToOpenDoor(
            any(Lockpick.class), eq(hero.getLockpickingLevel()));
    assertThat(hero.getMoney()).isEqualTo(BigDecimal.valueOf(100).add(jeweleryWorth));
}

In this test method, we are:

      (L2,3):  Creating and inject the GameEngine mock.

      (L8-11):  Preparing the Hero and Castle objects.

      (L15):  When the gameEngineMock.attemptToOpenDoor is called with any kind of a Lockpick and with the specific hero level, the door should open.

      (L19):  Take note of that additional Guard Assert of hero purse before we invoke the SUT.

      (L25,26):  We verify that the door has been opened on the first attempt and that hero has increased his purse size considerably.

 

Tip
Tip

 

Note
Note

 

4)     Mockito spying on objects

When you start to work with spies, think about classic stubbing but in a reversed order. The difference between a Mock and a Spy is simple.. invocation on mocks by default just return a default value, spies by default have their real implementation invoked. Having that said, we need to be more careful how we perform the actual stubbing. By using the standard when().then() syntax we most probably get into trouble:

 

Test Code


Castle castleSpy = spy(new Castle());

when(castleSpy.startDefense(invaders)).thenReturn(true);

Here the castleSpy.startDefense(invaders) real implementation will get called before Mockito will have a chance to put that spy under its wing and wrap it with a nice proxy. This is not what we want. The invasion needs to happen before we start defending anything!

 

SUT Code


public boolean defendCastle(Hero hero, Castle castle){
    castle.startDefense(hero);

    List<Hero> heroesArmy = hero.getAllies();
    hero.castOffensiveSpell(heroesArmy);
    hero.getArmyIntoPosition();

    if(!castle.defenseStarted()){
        return false;
    }

    while(hero.isAlive() || !castle.taken()){
        castle.shootAtHeroAndHisArmy(hero);
        gameEngine.attackTheCastle(hero,castle);
    }

    if(hero.isAlive()){return false;}

    return true;
}

In this SUT method, we are:

      (L3):  As long as one of the castle scouts notices the hero and his army, the defence starts.

      (L5-7):  Heroes prepares his army for battle.

      (L9):  When castles defence is not ready until this point, the Hero easily takes the Castle without any resistance.

      (L13-16):  The fight begins. It continues either until the Castle is taken or Hero has been defeated.

Let's write a test where the Castle will defend itself and defeat the Hero. Now, we:

      Do not care what goes on inside the castle.startDefense method.

      Want to stub the castle.defenseStarted() to return true.

      Want the real implementation of castle.shootAtHeroAndHisArmy(hero) to drain his life every time a shooter shoots. It is a simple method, so calling a real implementation is fine here.

 

Test Code


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

@Test
public void shouldDefendTheCastle() throws Exception{
    // Arrange
    Hero hero = new Hero();
    Castle castleSpy = spy(new Castle());

    doNothing().when(castleSpy).startDefense(hero);
    doReturn(true).when(castleSpy).defenseStarted();

    // Act
    boolean castleDefended = gameControllerSUT.defendCastle(hero, castleSpy);

    // Assert
    assertThat(castleDefended).isTrue();
}

In this test method, we are:

      (L9):  Spying on the Castle instance.

      (L11):  We do not want to do anything here.

      (L12):  We make sure the defence has prepared itself before the battle.

 

Tip
Tip

 

Reference
Reference
unittest
Spying with Mockito

 

5)     Mockito thenThrow: expecting exceptions

That's fine you may think. We expect something to be returned when given actions are triggered. What about cases where we want to test scenarios where the dependent object throws an exception. We want to make sure our SUT acts as expected in those situations. Let's take a look at this example. Here the enemy is supposed to kill our hero, but something unexpected happens:

 

SUT Code


public void heroDies(Hero hero, Enemy enemy) throws HeroOvercomesDeathAndCrushesHisEnemy {
    Hit hit = enemy.hit(hero);

    while(!hit.isCritical()){
        hit = enemy.hit(hero);
    }

    enemy.performDeadlyFinalBlow();
}

In this SUT method, the enemy is trying to hit the hero until a critical hit is done. Then it is only a matter of finishing him off. But in rare cases, the hero might not be ready yet for being sent away.

 

Test Code


@Test
public void heroShouldNotDieJustLikeThat() throws Exception{
    // Arrange
    Hero hero = new Hero();
    Enemy enemyStub = mock(Enemy.class);
    Hit hit = new Hit();
    hit.setCritical(true);

    when(gameEngineMock.hit(enemyStub, hero)).thenReturn(hit);

    doThrow(new HeroOvercomesDeathAndCrushesHisEnemy())
            .when(enemyStub).performDeadlyFinalBlow();

    // Act
    Exception expectedException = null;

    try {
        gameControllerSUT.heroDies(hero, enemyStub);
    } catch (HeroOvercomesDeathAndCrushesHisEnemy e){
        expectedException = e;
    }

    // Assert
    assertThat(expectedException).isInstanceOf(HeroOvercomesDeathAndCrushesHisEnemy.class);
    assertThat(hero.isAlive()).isTrue();
}

In this test method, we are:

      (L12):  Preparing the performDeadlyFinalBlow method to throw an unexpected exception.

      (L25):  Making sure that the right exception has been thrown.

      (L26):  Making sure that our hero is still alive.

 

6)     Mockito thenAnswer: dynamic answering

If we need the result to be resolved more dynamically, for example, based on the input to the stubbed method, then Mockito provides the Answer feature. Go to the post below for an in-depth look at that potent tool:

 

Reference
Reference
unittest
Mockito dynamic answering

 

7)     Conclusion

 

Summary

 

We have seen examples of, what really is the spine of Mockito. Stubbing is the starting point of really introducing that SUT isolation to our test suite. Thanks to that, we do not have to care how adjacent objects exactly work. We just set-up the behaviour as provided by their interface and the way we go. Just make sure you do the right imitation!

Need more insight?
Repository
Repository
Glossary
Glossary
Tags:
Reference
You may also like:
mockito-most-common-exceptions
Mockito most common exceptions
spying-with-mockito
Spying with Mockito
unit-testing-common-mistakes
Unit testing common mistakes
Comments
Be the first to comment.
Leave a comment