Mockito Stub Examples

0

Using stubbing we train the mock objects about what values to return when its methods are invoked. Mockito provides whenthen stubbing pattern to stub a mock object’s method invocation.

The mock API invocation goes into when() which is a static Mockito API method and the value that we want the want the mock to return goes into the then() API.

Mockito is an open source mock unit testing framework for Java. In this article, we will look into some of the stubbing examples.

Below are my setup details:

pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.javarticles.mockito</groupId>
  <artifactId>mockitoVerifyBehavior</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
	<dependencies>
		<dependency>
			<groupId>org.testng</groupId>
			<artifactId>testng</artifactId>
			<version>6.8.8</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.mockito</groupId>
			<artifactId>mockito-core</artifactId>
			<version>2.0.5-beta</version>
		</dependency>
	</dependencies>
</project>

System Under Test

All our stubbing examples follow a simple model. Our model consists of interface Tree and class Seed. We know when we plant a seed, it eventually grows into a tree. We have included this in Tree interface.

Tree:

package com.javarticles.mockito;

public interface Tree {
    Tree grow(Seed seed);
}

Here is the Seed class.

Seed:

package com.javarticles.mockito;

public class Seed {
    private String name;
    
    public Seed(String name) {
        this.name = name;
    }
    
    public boolean equals(Object o) {
        if (o == null) {
            return false;
        }
        if (!(o instanceof Seed)) {
            return false;
        }
        Seed seed = (Seed) o;
        return name.equals(seed.getName());
    }

    public String getName() {
        return name;
    }
    
    public String toString() {
        return "Seed(" + name + ")";
    }
}

Stubbing Example

In our first example, test simpleStubbing(), we have used Mockito’s built-in matcher, isA() which checks if the passed object is an instance of the class type passed in the isA() argument.

when(tree.grow(isA(Seed.class))).thenReturn(tree);

StubbingTests:

package com.javarticles.mockito;

import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;

import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

public class StubbingTests {
    private Tree tree;
    private Seed seed = new Seed("Orange");
    private AppleTree appleTree;
    private AppleSeed appleSeed = new AppleSeed();
    
    @BeforeMethod
    public void createMock() {
        tree = mock(Tree.class);
    }
    
    @Test
    public void simpleStubbing() {
        when(tree.grow(isA(Seed.class))).thenReturn(tree);
        
        assertEquals(tree.grow(seed), tree);        
    }
}

Latest Sub is evaluated first

A mock object can be stubbed multiple times for the same method invocation. We need this as the method may need to return different values for different arguments.

For example,
A seed planted eventually grows into a tree. The below API models this scenario:

when(tree.grow(isA(Seed.class))).thenReturn(tree);

Now consider this scenario. Suppose we know about the seed then we don’t have to model it in a generic way.
For example,
If an apple seed is sown, it will grow into an apple tree.

To model this, we will introduce couple of new interfaces. AppleSeed extends Seed.

AppleSeed:

package com.javarticles.mockito;

public class AppleSeed extends Seed {

    public AppleSeed() {
        super("Apple");
    }

}

AppleTree extends Tree

AppleTree:

package com.javarticles.mockito;

public interface AppleTree extends Tree {
}

We will stub the mock method one more time for the specific types. If the argument is an appleSeed, the return Object would be appleTree object.

when(tree.grow(appleSeed)).thenReturn(appleTree);

If a mock object is stubbed multiple times for the same method invocation then the latest method invocation is given preference.
See evaluateLatestStubbingOrderReversed() where we have reversed the order of stubbing. Compare it to evaluateLatestStubbingProperOrder) and you will know.
Since we have swapped the stub statements, the below call throws AssertionError.

assertEquals(tree.grow(appleSeed), appleTree);

This is because the latest stub comes into play. Since apple seed is also of Seed type, it returns Tree object instead of AppleTree object.

when(tree.grow(isA(Seed.class))).thenReturn(tree);

StubbingTests:

package com.javarticles.mockito;

import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;

import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

public class StubbingTests {
    private Tree tree;
    private Seed seed = new Seed("Orange");
    private AppleTree appleTree;
    private AppleSeed appleSeed = new AppleSeed();
    
    @BeforeMethod
    public void createMock() {
        tree = mock(Tree.class);
        appleTree = mock(AppleTree.class);
    }
    
    @Test
    public void simpleStubbing() {
        when(tree.grow(isA(Seed.class))).thenReturn(tree);
        
        assertEquals(tree.grow(seed), tree);        
    }
    
    @Test
    public void evaluateLatestStubbingProperOrder() {
        when(tree.grow(isA(Seed.class))).thenReturn(tree);
        when(tree.grow(appleSeed)).thenReturn(appleTree);
        
        assertEquals(tree.grow(appleSeed), appleTree);
        assertEquals(tree.grow(seed), tree);        
    }
    
    @Test(expectedExceptions=AssertionError.class)
    public void evaluateLatestStubbingOrderReversed() {
        when(tree.grow(appleSeed)).thenReturn(appleTree);
        when(tree.grow(isA(Seed.class))).thenReturn(tree);   
        
        assertEquals(tree.grow(appleSeed), appleTree);
    }
}

It’s redundant to verify a stubbed invocation

In letsVerifyStubbedInvocation(), we stub the method call, we call the method, assert the returned value and then we verify the method is called.

Although it is possible to verify a stubbed invocation, usually it’s just redundant.

We stub the mock object to return treeseed.grow() is called. If the seed is rotten, tree.grow() will not be called. We add isRooten and tree members to Seed class.

Seed:

package com.javarticles.mockito;

public class Seed {
    private String name;
    private boolean isRotten;
    private Tree tree;
    
    public Seed(String name) {
        this.name = name;
    }
    
    public Tree grow() {
        if (!isRotten() && tree != null) {
            return tree.grow(this);
        }  
        return null;
    }
      
    public boolean equals(Object o) {
        if (o == null) {
            return false;
        }
        if (!(o instanceof Seed)) {
            return false;
        }
        Seed seed = (Seed) o;
        return name.equals(seed.getName());
    }

    public String getName() {
        return name;
    }
    
    public String toString() {
        return "Seed(" + name + ")";
    }

    public boolean isRotten() {
        return isRotten;
    }

    public void setRotten(boolean isRotten) {
        this.isRotten = isRotten;
    }

    public void setTree(Tree tree) {
        this.tree = tree;
    }        
    
}

Since we are already asserting the returned value from seed.grow() which indirectly calls tree.grow(seed), if the returned value is different from what we are expecting, assert will fail and it will never reach verify call. Since the returned value is based on the method call we have stubbed, it is obvious that the stubbed method would have got called else the assert will fail anyway.

Thus verifying a stubbed invocation is redundant.

StubbingTests:

package com.javarticles.mockito;

import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.*;
import static org.testng.Assert.assertEquals;

import org.mockito.exceptions.misusing.CannotVerifyStubOnlyMock;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

public class StubbingTests {
    private Tree tree;
    private Seed seed = new Seed("Orange");
    private AppleTree appleTree;
    private AppleSeed appleSeed = new AppleSeed();
    
    @BeforeMethod
    public void createMock() {
        tree = mock(Tree.class);
        seed.setTree(tree);
        appleTree = mock(AppleTree.class);
        appleSeed.setTree(appleTree);
    }
    
    @Test
    public void simpleStubbing() {
        when(tree.grow(isA(Seed.class))).thenReturn(tree);
        
        assertEquals(tree.grow(seed), tree);        
    }
    
    @Test
    public void evaluateLatestStubbingProperOrder() {
        when(tree.grow(isA(Seed.class))).thenReturn(tree);
        when(tree.grow(appleSeed)).thenReturn(appleTree);
        
        assertEquals(tree.grow(appleSeed), appleTree);
        assertEquals(tree.grow(seed), tree);        
    }
    
    @Test(expectedExceptions=AssertionError.class)
    public void evaluateLatestStubbingOrderReversed() {
        when(tree.grow(appleSeed)).thenReturn(appleTree);
        when(tree.grow(isA(Seed.class))).thenReturn(tree);   
        
        assertEquals(tree.grow(appleSeed), appleTree);
    }
    
    @Test
    public void letsVerifyStubbedInvocation() {
        seed.setRotten(false);
        when(tree.grow(isA(Seed.class))).thenReturn(tree);        
        assertEquals(seed.grow(), tree);        
        verify(tree).grow(seed);        
        verifyNoMoreInteractions(tree);
        
        seed.setRotten(true);
        Assert.assertNull(seed.grow());
    }
}

Stub toString

In test stubToString(), we stub tree.toString().

StubbingTests:

package com.javarticles.mockito;

import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.*;
import static org.testng.Assert.assertEquals;

import org.mockito.exceptions.misusing.CannotVerifyStubOnlyMock;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

public class StubbingTests {
    private Tree tree;
    private Seed seed = new Seed("Orange");
    private AppleTree appleTree;
    private AppleSeed appleSeed = new AppleSeed();
    
    @BeforeMethod
    public void createMock() {
        tree = mock(Tree.class);
        seed.setTree(tree);
        appleTree = mock(AppleTree.class);
        appleSeed.setTree(appleTree);
    }
    
    @Test
    public void simpleStubbing() {
        when(tree.grow(isA(Seed.class))).thenReturn(tree);
        
        assertEquals(tree.grow(seed), tree);        
    }
    
    @Test
    public void evaluateLatestStubbingProperOrder() {
        when(tree.grow(isA(Seed.class))).thenReturn(tree);
        when(tree.grow(appleSeed)).thenReturn(appleTree);
        
        assertEquals(tree.grow(appleSeed), appleTree);
        assertEquals(tree.grow(seed), tree);        
    }
    
    @Test(expectedExceptions=AssertionError.class)
    public void evaluateLatestStubbingOrderReversed() {
        when(tree.grow(appleSeed)).thenReturn(appleTree);
        when(tree.grow(isA(Seed.class))).thenReturn(tree);   
        
        assertEquals(tree.grow(appleSeed), appleTree);
    }
    
    @Test
    public void letsVerifyStubbedInvocation() {
        seed.setRotten(false);
        when(tree.grow(isA(Seed.class))).thenReturn(tree);        
        assertEquals(seed.grow(), tree);        
        verify(tree).grow(seed);        
        verifyNoMoreInteractions(tree);
        
        seed.setRotten(true);
        Assert.assertNull(seed.grow());
    }
    
    @Test
    public void stubToString() {
        final String orangeTree = "Orange Tree";
        when(tree.toString()).thenReturn(orangeTree);
        assertEquals(tree.toString(), orangeTree);
    }
}

Throwing Exceptions

We have seen how to stub mock objects to simulate a method invocation and return a value. In some scenarios, you may want your APIs to throw exceptions. This again can be trained using Mockito provided API thenThrow() to throw exceptions thrown during testing.

Suppose, one tries to plant a rotten seed, it may not grow into tree and we want our API to throw exception.

We will stub the tree object to throw an exception when a method is called using rotten seed.

when(tree.grow(rottenSeed)).thenThrow(new RuntimeException("Seed is rotten, can't grow into tree"));

The pattern to mock void object is different from methods that return values. Void methods don’t return values so we need a different pattern to train the mock object. Let’s see an example. We will introduce a new void method to Tree interface.

Tree:

package com.javarticles.mockito;

public interface Tree {
    Tree grow(Seed seed);
    
    void growSelf(Seed seed);
}

In order to throw exception from a void method use the following code snippet:

doThrow(new RuntimeException("Seed is rotten, can't grow into tree")).when(tree).growSelf(rottenSeed);

StubbingTests:

package com.javarticles.mockito;

import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.*;
import static org.testng.Assert.assertEquals;

import org.mockito.exceptions.misusing.CannotVerifyStubOnlyMock;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

public class StubbingTests {
    private Tree tree;
    private Seed seed = new Seed("Orange");
    private AppleTree appleTree;
    private AppleSeed appleSeed = new AppleSeed();
    
    @BeforeMethod
    public void createMock() {
        tree = mock(Tree.class);
        seed.setTree(tree);
        appleTree = mock(AppleTree.class);
        appleSeed.setTree(appleTree);
    }
    
    @Test
    public void simpleStubbing() {
        when(tree.grow(isA(Seed.class))).thenReturn(tree);
        
        assertEquals(tree.grow(seed), tree);        
    }
    
    @Test
    public void evaluateLatestStubbingProperOrder() {
        when(tree.grow(isA(Seed.class))).thenReturn(tree);
        when(tree.grow(appleSeed)).thenReturn(appleTree);
        
        assertEquals(tree.grow(appleSeed), appleTree);
        assertEquals(tree.grow(seed), tree);        
    }
    
    @Test(expectedExceptions=AssertionError.class)
    public void evaluateLatestStubbingOrderReversed() {
        when(tree.grow(appleSeed)).thenReturn(appleTree);
        when(tree.grow(isA(Seed.class))).thenReturn(tree);   
        
        assertEquals(tree.grow(appleSeed), appleTree);
    }
    
    @Test
    public void letsVerifyStubbedInvocation() {
        seed.setRotten(false);
        when(tree.grow(isA(Seed.class))).thenReturn(tree);        
        assertEquals(seed.grow(), tree);        
        verify(tree).grow(seed);        
        verifyNoMoreInteractions(tree);
        
        seed.setRotten(true);
        Assert.assertNull(seed.grow());
    }
    
    @Test
    public void stubToString() {
        final String orangeTree = "Orange Tree";
        when(tree.toString()).thenReturn(orangeTree);
        assertEquals(tree.toString(), orangeTree);
    }
    
    @Test
    public void stubMethodToThrowException() {
        Seed rottenSeed = new Seed("Rotten");
        when(tree.grow(rottenSeed)).thenThrow(new RuntimeException("Seed is rotten, can't grow into tree"));
        doThrow(new RuntimeException("Seed is rotten, can't grow into tree")).when(tree).growSelf(rottenSeed);
        try {
            System.out.println("Call tree.grow(rottenSeed)");
            tree.grow(rottenSeed);
            Assert.fail();
        } catch(RuntimeException e) {
            System.out.println("Exception thrown " + e);
        }
        
        try {
            System.out.println("Call tree.growSelf(rottenSeed)");
            tree.growSelf(rottenSeed);
            Assert.fail();
        } catch(RuntimeException e) {
            System.out.println("Exception thrown " + e);
        }
    }    
}

Stubbing is not interaction

Stubbing is not considered as interaction. See test stubbingIsNotInteraction() where we just stub and don’t call any method on the stub. We verify this using verifyZeroInteractions(tree).

StubbingTests:

package com.javarticles.mockito;

import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.*;
import static org.testng.Assert.assertEquals;

import org.mockito.exceptions.misusing.CannotVerifyStubOnlyMock;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

public class StubbingTests {
    private Tree tree;
    private Seed seed = new Seed("Orange");
    private AppleTree appleTree;
    private AppleSeed appleSeed = new AppleSeed();
    
    @BeforeMethod
    public void createMock() {
        tree = mock(Tree.class);
        seed.setTree(tree);
        appleTree = mock(AppleTree.class);
        appleSeed.setTree(appleTree);
    }
    
    @Test
    public void simpleStubbing() {
        when(tree.grow(isA(Seed.class))).thenReturn(tree);
        
        assertEquals(tree.grow(seed), tree);        
    }
    
    @Test
    public void evaluateLatestStubbingProperOrder() {
        when(tree.grow(isA(Seed.class))).thenReturn(tree);
        when(tree.grow(appleSeed)).thenReturn(appleTree);
        
        assertEquals(tree.grow(appleSeed), appleTree);
        assertEquals(tree.grow(seed), tree);        
    }
    
    @Test(expectedExceptions=AssertionError.class)
    public void evaluateLatestStubbingOrderReversed() {
        when(tree.grow(appleSeed)).thenReturn(appleTree);
        when(tree.grow(isA(Seed.class))).thenReturn(tree);   
        
        assertEquals(tree.grow(appleSeed), appleTree);
    }
    
    @Test
    public void letsVerifyStubbedInvocation() {
        seed.setRotten(false);
        when(tree.grow(isA(Seed.class))).thenReturn(tree);        
        assertEquals(seed.grow(), tree);        
        verify(tree).grow(seed);        
        verifyNoMoreInteractions(tree);
        
        seed.setRotten(true);
        Assert.assertNull(seed.grow());
    }
    
    @Test
    public void stubToString() {
        final String orangeTree = "Orange Tree";
        when(tree.toString()).thenReturn(orangeTree);
        assertEquals(tree.toString(), orangeTree);
    }
    
    @Test
    public void stubMethodToThrowException() {
        Seed rottenSeed = new Seed("Rotten");
        when(tree.grow(rottenSeed)).thenThrow(new RuntimeException("Seed is rotten, can't grow into tree"));
        doThrow(new RuntimeException("Seed is rotten, can't grow into tree")).when(tree).growSelf(rottenSeed);
        try {
            System.out.println("Call tree.grow(rottenSeed)");
            tree.grow(rottenSeed);
            Assert.fail();
        } catch(RuntimeException e) {
            System.out.println("Exception thrown " + e);
        }
        
        try {
            System.out.println("Call tree.growSelf(rottenSeed)");
            tree.growSelf(rottenSeed);
            Assert.fail();
        } catch(RuntimeException e) {
            System.out.println("Exception thrown " + e);
        }
    }    
    
    @Test
    public void stubbingIsNotInteraction() {
        Seed rottenSeed = new Seed("Rotten");
        when(tree.grow(rottenSeed)).thenThrow(new RuntimeException("Seed is rotten, can't grow into tree"));
        doThrow(new RuntimeException("Seed is rotten, can't grow into tree")).when(tree).growSelf(rottenSeed);
        
        verifyZeroInteractions(tree);
    }
}

Stub-Only mock doesn’t record method invocations

A stub-only mock does not record method invocations. We can use this setting if we want to save memory. If we try verify the invocations on a stub-only mock, it will throw CannotVerifyStubOnlyMock exception.

See test stubOnlyDisallowVerifications.

StubbingTests:

package com.javarticles.mockito;

import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.*;
import static org.testng.Assert.assertEquals;

import org.mockito.exceptions.misusing.CannotVerifyStubOnlyMock;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

public class StubbingTests {
    private Tree tree;
    private Seed seed = new Seed("Orange");
    private AppleTree appleTree;
    private AppleSeed appleSeed = new AppleSeed();
    
    @BeforeMethod
    public void createMock() {
        tree = mock(Tree.class);
        seed.setTree(tree);
        appleTree = mock(AppleTree.class);
        appleSeed.setTree(appleTree);
    }
    
    @Test
    public void simpleStubbing() {
        when(tree.grow(isA(Seed.class))).thenReturn(tree);
        
        assertEquals(tree.grow(seed), tree);        
    }
    
    @Test
    public void evaluateLatestStubbingProperOrder() {
        when(tree.grow(isA(Seed.class))).thenReturn(tree);
        when(tree.grow(appleSeed)).thenReturn(appleTree);
        
        assertEquals(tree.grow(appleSeed), appleTree);
        assertEquals(tree.grow(seed), tree);        
    }
    
    @Test(expectedExceptions=AssertionError.class)
    public void evaluateLatestStubbingOrderReversed() {
        when(tree.grow(appleSeed)).thenReturn(appleTree);
        when(tree.grow(isA(Seed.class))).thenReturn(tree);   
        
        assertEquals(tree.grow(appleSeed), appleTree);
    }
    
    @Test
    public void letsVerifyStubbedInvocation() {
        seed.setRotten(false);
        when(tree.grow(isA(Seed.class))).thenReturn(tree);        
        assertEquals(seed.grow(), tree);        
        verify(tree).grow(seed);        
        verifyNoMoreInteractions(tree);
        
        seed.setRotten(true);
        Assert.assertNull(seed.grow());
    }
    
    @Test
    public void stubToString() {
        final String orangeTree = "Orange Tree";
        when(tree.toString()).thenReturn(orangeTree);
        assertEquals(tree.toString(), orangeTree);
    }
    
    @Test
    public void stubMethodToThrowException() {
        Seed rottenSeed = new Seed("Rotten");
        when(tree.grow(rottenSeed)).thenThrow(new RuntimeException("Seed is rotten, can't grow into tree"));
        doThrow(new RuntimeException("Seed is rotten, can't grow into tree")).when(tree).growSelf(rottenSeed);
        try {
            System.out.println("Call tree.grow(rottenSeed)");
            tree.grow(rottenSeed);
            Assert.fail();
        } catch(RuntimeException e) {
            System.out.println("Exception thrown " + e);
        }
        
        try {
            System.out.println("Call tree.growSelf(rottenSeed)");
            tree.growSelf(rottenSeed);
            Assert.fail();
        } catch(RuntimeException e) {
            System.out.println("Exception thrown " + e);
        }
    }    
    
    @Test
    public void stubbingIsNotInteraction() {
        Seed rottenSeed = new Seed("Rotten");
        when(tree.grow(rottenSeed)).thenThrow(new RuntimeException("Seed is rotten, can't grow into tree"));
        doThrow(new RuntimeException("Seed is rotten, can't grow into tree")).when(tree).growSelf(rottenSeed);
        
        verifyZeroInteractions(tree);
    }
    
    @Test(expectedExceptions=CannotVerifyStubOnlyMock.class)
    public void stubOnlyDisallowVerifications() {
        Tree stubOnlyTree = mock(Tree.class, withSettings().stubOnly());
        when(stubOnlyTree.grow(seed)).thenReturn(tree);
        assertEquals(tree, stubOnlyTree.grow(seed));
        verify(stubOnlyTree, atLeastOnce()).grow(seed);
    }
}

Download the source code

In this article, I showed you several examples on stubbing mock objects using Mockito.

You can download the source code here: mockitoStubbing.zip
Share.

Comments are closed.