Mockito Verify Behaviour

0

Mockito is an open source mock unit testing framework for Java. In this article, we will create mock objects, stub the behavior and mostly verify the behavior. Our main focus is on verification, you will several different ways to verify the method calls, but you will also get a glimpse of how to stub the behavior.

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

Our system under test is about employee tracking system. Once an employee joins, EmployeeManager.join(employee) is called. This should probably create an employee record using which we track other details like the salary, leave etc.

Suppose the EmployeeManager is not yet been implemented and all we know is some operations that we are going to perform on employee object, in such case, it is important that the team can proceed further and not wait for the actual implementation. This is where we will use Mockito to mock out external dependencies, EmployeeManager in our case.

You can even use it to mocks out a Jdbc Connection, a socket connection etc. This allows one to proceed with their own component uni testing and encourages Test-Driven-development.

Mock, Stub Behavior and Verify Method Calls

Since EmployeeManager is not yet implemented let’s start with an interface which contains method getSalary(employee).

EmployeeManager:

package com.javarticles.mokcito;


public interface EmployeeManager {
    int getSalary(Employee emp);
}

Suppose we have a method called getBonus() in Employee class which calculates bonus based on the salary. If salary > than 10000, bonus would be 10% of the salary else for all other employees earning &lt= 10000, the bonus will be 50% of their salary. We can come up with some rough implementation as shown below. Employee class depends on EmployeeManager to get the employee’s salary. Note that the EmployeeManager is passed as a parameter. Instead of passing it as method argument, you may want to inject the bean either using a setter or a constructor method.

Employee:

package com.javarticles.mokcito;
 
public class Employee {
    public int getBonus(EmployeeManager empManager) {
        int salary = empManager.getSalary(this) ;
        if (salary > 10000) {
            return (int) ((double)salary * .10d);
        } else {
            return (int) ((double)salary * .5d);
        }
    }
}

Let’s look at out first test case.

We want to create a mock of EmployeeManager object as the implementation is not available.

EmployeeManager empManager = mock(EmployeeManager.class);

Our goal is to test the bonus logic so we will also create a couple of Employee objects.
Employee Sam earns more than 10000 and John earns less than 10000. We will stub the EmployeeManager.getSalary(employee) behavior so that if employee is Sam, 12000 is returned as the salary. If employee is John, 8000 is returned.

Employee sam = new Employee();
when(empManager.getSalary(sam)).thenReturn(12000);
Employee john = new Employee();
when(empManager.getSalary(john)).thenReturn(8000);

Mockito provides whenthen stubbing methods. when() is a static Mockito API method. We use it when you want the mock to return particular value when particular method is called. Once stubbed, the method will always return stubbed value regardless of how many times it is called.

Once the behavior is stubbed, we will call the methods that calculate the bonus and then assert their values.

Assert.assertEquals(1200, sam.getBonus(empManager));
Assert.assertEquals(4000, john.getBonus(empManager));

Finally, we will verify whether our mock object’s methods are called.
We know that if want to know an employee’s bonus, we must also know their salary which means getBonus() method would have also called EmployeeManager.getSalary(employee).

Let’s verify whether the method was called. In order to verify that EmployeeManager.getSalary() is called, we need to call the static method called verify() to verify an invvocation happened. If note we just verified a method that is also stubbed. This is a duplication, as the assert would work only if the stubbed behavior worked which means that the method call used in stub got invoked so we don’;t have to verify this again!

verify(empManager).getSalary(sam);
verify(empManager).getSalary(john);

VerifyEmployeeBehavior:

package com.javarticles.mockito;

import static org.mockito.Mockito.*;

import org.mockito.exceptions.verification.TooManyActualInvocations;
import org.mockito.exceptions.verification.WantedButNotInvoked;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import com.javarticles.mokcito.Employee;
import com.javarticles.mokcito.EmployeeManager;

public class VerifyEmployeeBehavior {

    @Test
    public void stubEmpBehavior() {
        EmployeeManager empManager = mock(EmployeeManager.class);
        Employee sam = new Employee();
        when(empManager.getSalary(sam)).thenReturn(12000);
        Employee john = new Employee();
        when(empManager.getSalary(john)).thenReturn(8000);
        Assert.assertEquals(1200, sam.getBonus(empManager));
        Assert.assertEquals(4000, john.getBonus(empManager));
        verify(empManager).getSalary(sam);
        verify(empManager).getSalary(john);
    }
}

Let’s do some more verification.

Verify Behavior

Let’s add join() method to our EmployeeManager. In below example, we verify that empManager.join(sam) is called.

EmployeeManager:

package com.javarticles.mokcito;

public interface EmployeeManager {
    void join(Employee emp);

    int getSalary(Employee emp);
}

VerifyEmployeeBehavior:

package com.javarticles.mockito;

import static org.mockito.Mockito.*;

import org.testng.annotations.Test;

import com.javarticles.mokcito.Employee;
import com.javarticles.mokcito.EmployeeManager;

public class VerifyEmployeeBehavior {
    @Test
    public void employeeJoins() {
        Employee sam = new Employee();
        EmployeeManager empManager = mock(EmployeeManager.class);
        empManager.join(sam);
        verify(empManager).join(sam);
    }

    @Test
    public void stubEmpBehavior() {
        EmployeeManager empManager = mock(EmployeeManager.class);
        Employee sam = new Employee();
        when(empManager.getSalary(sam)).thenReturn(12000);
        Employee john = new Employee();
        when(empManager.getSalary(john)).thenReturn(8000);
        Assert.assertEquals(1200, sam.getBonus(empManager));
        Assert.assertEquals(4000, john.getBonus(empManager));
        verify(empManager).getSalary(sam);
        verify(empManager).getSalary(john);
    }
}

Verify NoMoreInteractions

verify() on mock to verify whether certain method was invoked. After the verification, if you want to make sure that nothing else was invoked on your mocks, you need to call verifyNoMoreInteractions() on your mock object.

Let’s introduce another method to EmployeeManager. If employee requests for leave, we will call EmployeeManager.requestLeave(employee, noOfDays). In test noMoreInteractionsWithEmpManager(), we invoke EmployeeManager.join(employee) and then EmployeeManager.requestLeave().

We next verify that both the methods are called. After which we verify that nothing else was called on the mock object. Note that verifyNoMoreInteractions() should be used only when relevant when you want to indicate something explicit. We need to make sure it is not over used as it will have an impact on maintenance of the test code.

EmployeeManager:

package com.javarticles.mokcito;

public interface EmployeeManager {
    void join(Employee emp);

    void requestLeave(Employee emp, int noOfDays);

    int getSalary(Employee emp);
}

VerifyEmployeeBehavior:

package com.javarticles.mockito;

import static org.mockito.Mockito.*;

import org.testng.annotations.Test;

import com.javarticles.mokcito.Employee;
import com.javarticles.mokcito.EmployeeManager;

public class VerifyEmployeeBehavior {
    @Test
    public void employeeJoins() {
        Employee sam = new Employee();
        EmployeeManager empManager = mock(EmployeeManager.class);
        empManager.join(sam);
        verify(empManager).join(sam);
    }
    
    @Test
    public void noMoreInteractionsWithEmpManager() {
        Employee sam = new Employee();
        EmployeeManager empManager = mock(EmployeeManager.class);
        empManager.join(sam);
        empManager.requestLeave(sam, 4);
        verify(empManager).join(sam);
        verify(empManager).requestLeave(sam, 4);
        verifyNoMoreInteractions(empManager);
    }

   @Test
    public void stubEmpBehavior() {
        Employee sam = new Employee();
        when(empManager.getSalary(sam)).thenReturn(12000);
        Employee john = new Employee();
        when(empManager.getSalary(john)).thenReturn(8000);
        Assert.assertEquals(1200, sam.getBonus(empManager));
        Assert.assertEquals(4000, john.getBonus(empManager));
        verify(empManager).getSalary(sam);
        verify(empManager).getSalary(john);
    }
}

WantedButNotInvoked Exception

What happens if you try to verify a method interaction that never took place? Mockito will throw WantedButNotInvoked exception. See test case verifyCallNotInvoked where we will verify whether EmployeeManager.getTotalEmployees() was called.

EmployeeManager:

package com.javarticles.mokcito;

public interface EmployeeManager {
    void join(Employee emp);

    void requestLeave(Employee emp, int noOfDays);
    
    int getTotalEmployees();

    int getSalary(Employee emp);
}

VerifyEmployeeBehavior:

package com.javarticles.mockito;

import static org.mockito.Mockito.*;

import org.mockito.exceptions.verification.WantedButNotInvoked;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import com.javarticles.mokcito.Employee;
import com.javarticles.mokcito.EmployeeManager;

public class VerifyEmployeeBehavior {
    private EmployeeManager empManager;
    
    @BeforeMethod
    public void createMock() {
        empManager = mock(EmployeeManager.class);
    }
    
    @Test
    public void employeeJoins() {
        Employee sam = new Employee();
        empManager.join(sam);
        verify(empManager).join(sam);
        verifyNoMoreInteractions(empManager);
    }
    
    @Test
    public void noMoreInteractionsWithEmpManager() {
        Employee sam = new Employee();
        empManager.join(sam);
        empManager.requestLeave(sam, 4);
        verify(empManager).join(sam);
        verify(empManager).requestLeave(sam, 4);
        verifyNoMoreInteractions(empManager);
    }
    
    @Test(expectedExceptions=WantedButNotInvoked.class)
    public void verifyCallNotInvoked() throws Exception {
        verify(empManager).getTotalEmployees();
    }

   @Test
    public void stubEmpBehavior() {
        Employee sam = new Employee();
        when(empManager.getSalary(sam)).thenReturn(12000);
        Employee john = new Employee();
        when(empManager.getSalary(john)).thenReturn(8000);
        Assert.assertEquals(1200, sam.getBonus(empManager));
        Assert.assertEquals(4000, john.getBonus(empManager));
        verify(empManager).getSalary(sam);
        verify(empManager).getSalary(john);
    }
}

Verification on wrong method argument

What happens if method was invoked with different parameters than expected? In wrongMethodArguments test, john requests or 2 days of leave but we verify for 3 days and the test fails with AssertionError exception.

VerifyEmployeeBehavior:

package com.javarticles.mockito;

import static org.mockito.Mockito.*;

import org.mockito.exceptions.verification.TooManyActualInvocations;
import org.mockito.exceptions.verification.WantedButNotInvoked;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import com.javarticles.mokcito.Employee;
import com.javarticles.mokcito.EmployeeManager;

public class VerifyEmployeeBehavior {
    private EmployeeManager empManager;
    
    @BeforeMethod
    public void createMock() {
        empManager = mock(EmployeeManager.class);
    }
    
    @Test
    public void employeeJoins() {
        Employee sam = new Employee();
        empManager.join(sam);
        verify(empManager).join(sam);
        verifyNoMoreInteractions(empManager);
    }
    
    @Test
    public void noMoreInteractionsWithEmpManager() {
        Employee sam = new Employee();
        empManager.join(sam);
        empManager.requestLeave(sam, 4);
        verify(empManager).join(sam);
        verify(empManager).requestLeave(sam, 4);
        verifyNoMoreInteractions(empManager);
    }
    
    @Test(expectedExceptions=WantedButNotInvoked.class)
    public void verifyCallNotInvoked() throws Exception {
        verify(empManager).getTotalEmployees();
    }
    
    @Test(expectedExceptions=AssertionError.class)
    public void wrongMethodArguments() {
        Employee john = new Employee();
        empManager.requestLeave(john, 2);
        verify(empManager).requestLeave(john, 3);
    }

   @Test
    public void stubEmpBehavior() {
        Employee sam = new Employee();
        when(empManager.getSalary(sam)).thenReturn(12000);
        Employee john = new Employee();
        when(empManager.getSalary(john)).thenReturn(8000);
        Assert.assertEquals(1200, sam.getBonus(empManager));
        Assert.assertEquals(4000, john.getBonus(empManager));
        verify(empManager).getSalary(sam);
        verify(empManager).getSalary(john);
    }
}

Verify multiple interactions

Sometimes we may need to call a mock object’s method a certain number of times. In such cases we have to use the overloaded verify() method which takes times as an argument. The second parameter helps in verifying whether certain behavior happened at least once or exact number of times or never, it is a Mockito framework class of type org.mockito.verification.VerificationMode.

Both redundantVerificationShouldFailIfMultipleMethodCalls and singleVerificationShouldFailMultipleMethodCalls() fail with exception TooManyActualInvocations as the verification is done for a single method call and the number of times is not considered. We fix this in test atLeastOnceVerifyIfMultipleMethodCalls().

VerifyEmployeeBehavior:

package com.javarticles.mockito;

import static org.mockito.Mockito.*;

import org.mockito.exceptions.verification.TooManyActualInvocations;
import org.mockito.exceptions.verification.WantedButNotInvoked;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import com.javarticles.mokcito.Employee;
import com.javarticles.mokcito.EmployeeManager;

public class VerifyEmployeeBehavior {
    private EmployeeManager empManager;
    
    @BeforeMethod
    public void createMock() {
        empManager = mock(EmployeeManager.class);
    }
    
    @Test
    public void employeeJoins() {
        Employee sam = new Employee();
        empManager.join(sam);
        verify(empManager).join(sam);
        verifyNoMoreInteractions(empManager);
    }
    
    @Test
    public void noMoreInteractionsWithEmpManager() {
        Employee sam = new Employee();
        empManager.join(sam);
        empManager.requestLeave(sam, 4);
        verify(empManager).join(sam);
        verify(empManager).requestLeave(sam, 4);
        verifyNoMoreInteractions(empManager);
    }
    
    @Test(expectedExceptions=WantedButNotInvoked.class)
    public void verifyCallNotInvoked() throws Exception {
        verify(empManager).getTotalEmployees();
    }
    
    @Test(expectedExceptions=AssertionError.class)
    public void wrongMethodArguments() {
        Employee john = new Employee();
        empManager.requestLeave(john, 2);
        verify(empManager).requestLeave(john, 3);
    }
    
    @Test(expectedExceptions=TooManyActualInvocations.class)
    public void redundantVerificationShouldFailIfMultipleMethodCalls() {
        Employee john = new Employee();
        empManager.requestLeave(john, 3);
        empManager.requestLeave(john, 3);
        verify(empManager).requestLeave(john, 3);
        verify(empManager).requestLeave(john, 3);
    }
    
    @Test(expectedExceptions=TooManyActualInvocations.class)
    public void singleVerificationShouldFailMultipleMethodCalls() {
        Employee john = new Employee();
        empManager.requestLeave(john, 3);
        empManager.requestLeave(john, 3);
        verify(empManager).requestLeave(john, 3);
    }
    
    @Test
    public void atLeastOnceVerifyIfMultipleMethodCalls() {
        Employee john = new Employee();
        empManager.requestLeave(john, 3);
        empManager.requestLeave(john, 3);
        verify(empManager, atLeastOnce()).requestLeave(john, 3);
        
        empManager.requestLeave(john, 3);
        empManager.requestLeave(john, 3);
        verify(empManager, atMost(4)).requestLeave(john, 3);
        
        empManager.requestLeave(john, 3);
        empManager.requestLeave(john, 3);
        verify(empManager, atLeast(6)).requestLeave(john, 3);
    }

   @Test
    public void stubEmpBehavior() {
        Employee sam = new Employee();
        when(empManager.getSalary(sam)).thenReturn(12000);
        Employee john = new Employee();
        when(empManager.getSalary(john)).thenReturn(8000);
        Assert.assertEquals(1200, sam.getBonus(empManager));
        Assert.assertEquals(4000, john.getBonus(empManager));
        verify(empManager).getSalary(sam);
        verify(empManager).getSalary(john);
    }
}

Verify Overloaded Methods

In this example, we verify the overloaded methods on the mock object. In order to test this, we have introduced an overloaded method called join(employees) which takes a varargs array of employees.

EmployeeManager:

package com.javarticles.mokcito;


public interface EmployeeManager {
    void join(Employee emp);

    void requestLeave(Employee emp, int noOfDays);
    
    int getTotalEmployees();
    
    void join(Employee... emp);

    int getSalary(Employee emp);
}

In test detectOverloadedMethods(), we join multiple employees and then verify the method call.

VerifyEmployeeBehavior:

package com.javarticles.mockito;

import static org.mockito.Mockito.*;

import org.mockito.exceptions.verification.TooManyActualInvocations;
import org.mockito.exceptions.verification.WantedButNotInvoked;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import com.javarticles.mokcito.Employee;
import com.javarticles.mokcito.EmployeeManager;

public class VerifyEmployeeBehavior {
    private EmployeeManager empManager;
    
    @BeforeMethod
    public void createMock() {
        empManager = mock(EmployeeManager.class);
    }
    
    @Test
    public void employeeJoins() {
        Employee sam = new Employee();
        empManager.join(sam);
        verify(empManager).join(sam);
        verifyNoMoreInteractions(empManager);
    }
    
    @Test
    public void noMoreInteractionsWithEmpManager() {
        Employee sam = new Employee();
        empManager.join(sam);
        empManager.requestLeave(sam, 4);
        verify(empManager).join(sam);
        verify(empManager).requestLeave(sam, 4);
        verifyNoMoreInteractions(empManager);
    }
    
    @Test(expectedExceptions=WantedButNotInvoked.class)
    public void verifyCallNotInvoked() throws Exception {
        verify(empManager).getTotalEmployees();
    }
    
    @Test(expectedExceptions=AssertionError.class)
    public void wrongMethodArguments() {
        Employee john = new Employee();
        empManager.requestLeave(john, 2);
        verify(empManager).requestLeave(john, 3);
    }
    
    @Test(expectedExceptions=TooManyActualInvocations.class)
    public void redundantVerificationShouldFailIfMultipleMethodCalls() {
        Employee john = new Employee();
        empManager.requestLeave(john, 3);
        empManager.requestLeave(john, 3);
        verify(empManager).requestLeave(john, 3);
        verify(empManager).requestLeave(john, 3);
    }
    
    @Test(expectedExceptions=TooManyActualInvocations.class)
    public void singleVerificationShouldFailMultipleMethodCalls() {
        Employee john = new Employee();
        empManager.requestLeave(john, 3);
        empManager.requestLeave(john, 3);
        verify(empManager).requestLeave(john, 3);
    }
    
    @Test
    public void atLeastOnceVerifyIfMultipleMethodCalls() {
        Employee john = new Employee();
        empManager.requestLeave(john, 3);
        empManager.requestLeave(john, 3);
        verify(empManager, atLeastOnce()).requestLeave(john, 3);
        
        empManager.requestLeave(john, 3);
        empManager.requestLeave(john, 3);
        verify(empManager, atMost(4)).requestLeave(john, 3);
        
        empManager.requestLeave(john, 3);
        empManager.requestLeave(john, 3);
        verify(empManager, atLeast(6)).requestLeave(john, 3);
    }
    
    @Test
    public void detectOverloadedMethods() {
        Employee sam = new Employee();
        Employee john = new Employee();
        Employee roy = new Employee();
        empManager.join(sam);
        verify(empManager).join(sam);
        empManager.join(john, roy);
        verify(empManager).join(john, roy);
    }

   @Test
    public void stubEmpBehavior() {
        Employee sam = new Employee();
        when(empManager.getSalary(sam)).thenReturn(12000);
        Employee john = new Employee();
        when(empManager.getSalary(john)).thenReturn(8000);
        Assert.assertEquals(1200, sam.getBonus(empManager));
        Assert.assertEquals(4000, john.getBonus(empManager));
        verify(empManager).getSalary(sam);
        verify(empManager).getSalary(john);
    }
}

Download the source code

This was an example about how we verify behavior using Mockito.

You an download the source code here: mockitoVerifyBehaviour.zip
Share.

Comments are closed.