Mockito Stubbing Consecutive Answers

0

One may want to return different values when a same method call multiple times. For example, a custom reader, stubbed to return different values as its read() method is called.
One may also want to stub with a Throwable simulating the case when the reader should have reached the EOF.

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

Below are my setup details:

Dependencies

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>

Stub with Consecutive Answers

Let’s first have our own custom reader interface. As you can see it has separate read() methods for each data type. We will mock this to return different values for each readString() call.

MyReader:

package com.javarticles.mokcito;

public interface MyReader {
    int readInt();
    String readString();
    boolean readBoolean();
    long readLong();
}

Assume the reader is holding the data to build the Employee object. Method readFrom(reader) will call the read() methods based on the understood data format structure and populate the employee object with its state.

Employee:

package com.javarticles.mokcito;


public class Employee {
    private int age;
    private String firstName;
    private String lastName;
    private String designation;

    public void readFrom(MyReader reader) {
        age = (int) reader.readInt();
        firstName = (String) reader.readString();
        lastName = (String) reader.readString();
        designation = (String) reader.readString();
    }
    
    public String toString() {
        return "Employee: (" + firstName + ", " + lastName + ", " + age + ", " + designation + ")"; 
    }
}

To build the employee object from its reader, we first read the age, and then first name, last name and the designation. Last three reads can be stubbed in consecutive form to return different values.
We create the mock object in createStub().

myReader = mock(MyReader.class);

In stubMultipleConsecutiveAnswers, we stub the reader to return the age when myReader.readInt() is called.

when(myReader.readInt()).thenReturn(32);

Next, three reads are stubbed using short version of consecutive stubbing and the usual consecutive stubbing. In the shorter version, one can pass the return values as varargs.

when(myReader.readString())
    .thenReturn("John", "S")
    .thenReturn("Programmer");

StubbingWithConsecutiveAnswers:

package com.javarticles.mockito;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

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

import com.javarticles.mokcito.Employee;
import com.javarticles.mokcito.MyReader;

public class StubbingWithConsecutiveAnswers {
    public MyReader myReader;

    @BeforeMethod
    public void createStub() {
        myReader = mock(MyReader.class);
    }

    @Test
    public void stubMultipleConsecutiveAnswers() {
        when(myReader.readInt()).thenReturn(32);
        when(myReader.readString()).thenReturn("John", "S").thenReturn(
                "Programmer");
        Employee emp = new Employee();
        emp.readFrom(myReader);
        System.out.println(emp);
    }
}

Output:

[TestNG] Running:
  C:\Users\mokkara\AppData\Local\Temp\testng-eclipse-1367252570\testng-customsuite.xml

Employee: (John, S, 32, Programmer)
PASSED: stubMultipleConsecutiveAnswers

===============================================
    Default test
    Tests run: 1, Failures: 0, Skips: 0
===============================================

Last Stubbed Call Remains Intact

The last stubbing is always given importance. The consecutive stubbing results into different return values. But once the method calls are done with, any further call on the stubbed method, will return the last stubbed return value.
After the employee object is retrieved, any further call on myReader.readString() will return ‘Programmer’.

StubbingWithConsecutiveAnswers:

package com.javarticles.mockito;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

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

import com.javarticles.mokcito.Employee;
import com.javarticles.mokcito.MyReader;

public class StubbingWithConsecutiveAnswers {
    public MyReader myReader;

    @BeforeMethod
    public void createStub() {
        myReader = mock(MyReader.class);
    }

    @Test
    public void stubMultipleConsecutiveAnswers() {
        when(myReader.readInt()).thenReturn(32);
        when(myReader.readString()).thenReturn("John", "S").thenReturn(
                "Programmer");
        Employee emp = new Employee();
        emp.readFrom(myReader);
        System.out.println(emp);
    }
    
    @Test
    public void lastStubbedCall() {
        when(myReader.readInt()).thenReturn(32);
        when(myReader.readString()).thenReturn("John", "S").thenReturn(
                "Programmer");
        Employee emp = new Employee();
        emp.readFrom(myReader);
        System.out.println(emp);
        
        System.out.println("Reader string: " + myReader.readString());
        System.out.println("Reader string: " + myReader.readString());
        System.out.println("Reader int: " + myReader.readInt());
    }
}

Output:

[TestNG] Running:
  C:\Users\mokkara\AppData\Local\Temp\testng-eclipse-1054171469\testng-customsuite.xml

Employee: (John, S, 32, Programmer)
Reader string: Programmer
Reader string: Programmer
Reader int: 32
Employee: (John, S, 32, Programmer)
PASSED: lastStubbedCall
PASSED: stubMultipleConsecutiveAnswers

===============================================
    Default test
    Tests run: 2, Failures: 0, Skips: 0
===============================================

Stub with a Throwable After Consecutive Stubbing

You may want to restrict further reading from the MyReader once employee object is retrieved. We can achieve this by stubbing it with a Throwable.

when(myReader.readString())
              .thenReturn("John", "S")
              .thenReturn("Programmer")
              .thenThrow(new RuntimeException("No more to read"));

StubbingWithConsecutiveAnswers:

package com.javarticles.mockito;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

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

import com.javarticles.mokcito.Employee;
import com.javarticles.mokcito.MyReader;

public class StubbingWithConsecutiveAnswers {
    public MyReader myReader;

    @BeforeMethod
    public void createStub() {
        myReader = mock(MyReader.class);
    }

    @Test
    public void stubMultipleConsecutiveAnswers() {
        when(myReader.readInt()).thenReturn(32);
        when(myReader.readString()).thenReturn("John", "S").thenReturn(
                "Programmer");
        Employee emp = new Employee();
        emp.readFrom(myReader);
        System.out.println(emp);
    }
    
    @Test
    public void lastStubbedCall() {
        when(myReader.readInt()).thenReturn(32);
        when(myReader.readString()).thenReturn("John", "S").thenReturn(
                "Programmer");
        Employee emp = new Employee();
        emp.readFrom(myReader);
        System.out.println(emp);
        
        System.out.println("Reader string: " + myReader.readString());
        System.out.println("Reader string: " + myReader.readString());
        System.out.println("Reader int: " + myReader.readInt());
    }
    
    @Test(expectedExceptions=RuntimeException.class)
    public void stubExceptionAfterConsecutiveCalls() {
        when(myReader.readInt()).thenReturn(32);
        when(myReader.readString())
              .thenReturn("John", "S")
              .thenReturn("Programmer")
              .thenThrow(new RuntimeException("No more to read"));
        Employee emp = new Employee();
        emp.readFrom(myReader);
        System.out.println(emp);
        System.out.println("Won't reach here..." + myReader.readString());
    }    
}

Output:

[TestNG] Running:
  C:\Users\mokkara\AppData\Local\Temp\testng-eclipse-434829197\testng-customsuite.xml

Employee: (John, S, 32, Programmer)
Reader string: Programmer
Reader string: Programmer
Reader int: 32
Employee: (John, S, 32, Programmer)
Employee: (John, S, 32, Programmer)
PASSED: lastStubbedCall
PASSED: stubExceptionAfterConsecutiveCalls
PASSED: stubMultipleConsecutiveAnswers

===============================================
    Default test
    Tests run: 3, Failures: 0, Skips: 0
===============================================

Download the source code

This was an example about Mockito Stubbing with Consecutive Answers.

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

Comments are closed.