Mockito

Java Unit Testing with Mockito Example

In this post, we feature a comprehensive article about Java Unit Testing with Mockito Example.

1. Introduction

Java unit testing is a software testing which focuses on testing methods in a class. When a class depends on other classes and/or interfaces, we can test it by using Mockito to create and configure mock objects.

In this example, first, I will create a class which depends on an interface and other class. Second, I will test it using Mockito with Junit framework. I will demonstrate the following actions:

  1. Define a mocked object with @Mock.
  2. Define a test class which depends on mocked objects with @InjectMocks.
  3. Configure a mocked object’s behavior.
  4. Verify a mocked object’s behavior.

2. Technologies Used

The example code in this article was built and run using:

  • Java 11
  • Maven 3.3.9
  • Eclipse Oxygen
  • Junit 4.12 and 5.5.2

3. Maven Project

In this step, I will demonstrate how to use Mockito in both JUnit 4 and JUnit 5 in a three-module Maven project:

  • common – includes four classes – SomeClass, OtherService, SomeInterface, and SomeException. SomeClass depends on OtherService and SomeInterface.
  • JUnit4-demo– tests SomeClass with Mockito in JUnit 4.
  • JUnit5-demo – tests SomeClass with Mockito in JUnit 5.

3.1 Dependencies

Parent pom.xml includes three modules.

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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>jcg.zheng.demo</groupId>
	<artifactId>junit-demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>pom</packaging>

	<name>junit-demo</name>
	<url>http://maven.apache.org</url>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>


	<description>parent project for junit demo</description>
	<modules>
		<module>common</module>
		<module>junit4-demo</module>
		<module>junit5-demo</module>
	</modules>

	<build>
		<plugins>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.8.0</version>
				<configuration>
					<release>11</release>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-surefire-plugin</artifactId>
				<version>3.0.0-M4</version>
			</plugin>
			 <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-site-plugin</artifactId>
                <version>3.8.2</version>
            </plugin>
		</plugins>
	</build>

	<reporting>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-surefire-report-plugin</artifactId>
				<version>3.0.0-M4</version>
			</plugin>
		</plugins>
	</reporting>
</project>

4. Common Module

In this step, I will create a common module which contains four classes:

  • OtherService – a class which has three public methods.
  • SomeInterface – an interface which defines two public methods.
  • SomeException – a run time exception
  • SomeClass – has four methods and depends on both OtherService and SomeInterface.

4.1 POM

The common module’s pom.xml is defined as the following:

pom.xml

<?xml version="1.0"?>
<project
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
	xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>jcg.zheng.demo</groupId>
		<artifactId>junit-demo</artifactId>
		<version>0.0.1-SNAPSHOT</version>
	</parent>

	<artifactId>common</artifactId>

	<name>comon</name>
	<url>http://maven.apache.org</url>

</project>

4.2 SomeInterface

In this step, I will create SomeInterface which has the following methods:

  • doSomething – it does not return anything.
  • getSomeList – it returns a list of string values.

SomeInterface.java

package jcg.zheng.demo;

import java.util.List;

public interface SomeInterface {
	
	void doSomething(String input);
	
	List<String> getSomeList(String input);

}

4.3 OtherService

In this step, I will create OtherService.

OtherService.java

package jcg.zheng.demo;

public class OtherService {

	public int calculateByDoubleIt(int num) {
		return num * 2;
	}
	
	public void doSomething(String input) {
		if ("Ok".equalsIgnoreCase(input)) {
			System.out.println("do something.");
		} else {
			throw new RuntimeException("Remote service failed");
		}

	}
	
	public boolean returnABoolean(String inputData) {
		if ("Save".equalsIgnoreCase(inputData)) {
			return true;
		} else {
			return false;
		}
	}
}

4.4 SomeException

In this step, I will create a SomeException class which extends from RuntimeExcpetion.

SomeException.java

package jcg.zheng.demo;

public class SomeException extends RuntimeException {

	private static final long serialVersionUID = 347808963459470775L;
	
	public SomeException(String msg) {
		super(msg);
	}

}

4.5 SomeClass

In this step, I will create a SomeClass which depends on both SomeInterface and OtherService. It has the following methods:

  • doubleANumber – returns an integer after invoking someService.calculateByDoubleIt.
  • processData – returns void. It depends on someInterface.getSomeList and someService.doSomething
  • returnABoolean – returns a Boolean value after calling someService.returnABoolean
  • voidFoo – returns void. It depends on someInterface.doSomething and someService.doSomething.

SomeClass.java

package jcg.zheng.demo;

import java.util.List;

public class SomeClass {

	private SomeInterface someInterface;

	private OtherService someService;

	public int doubleANumber(int num) {
		try {
			return someService.calculateByDoubleIt(num);
		} catch (Exception e) {
			throw new SomeException("External Service-calculateByDoubleIt failed " + e.getMessage());
		}
	}

	public void processData(String input) {
		List<String> rawList = someInterface.getSomeList(input);
		if (rawList != null) {
			for (String item : rawList) {
				someService.doSomething(item);
			}
		}

	}

	public boolean returnABoolean(String inputData) {
		try {
			return someService.returnABoolean(inputData);
		} catch (Exception e) {
			throw new SomeException("External Service-returnABoolean failed " + e.getMessage());
		}
	}

	public void voidFoo(String inputData) {
		try {
			if ("Interface".equalsIgnoreCase(inputData)) {
				someInterface.doSomething(inputData);
			}
			someService.doSomething(inputData);
		} catch (Exception e) {
			throw new SomeException("External Service-doSomething failed " + e.getMessage());
		}
	}
}

5. JUnit 4 Test

In this step, I will create a JUnit 4 test class to test SomeClass with mocked SomeInterface and OtherService.

5.1 POM

The JUnit4-demo module’s pom.xml and depends on mockito-core and the common module.

pom.xml

<?xml version="1.0"?>
<project
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
	xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>jcg.zheng.demo</groupId>
		<artifactId>junit-demo</artifactId>
		<version>0.0.1-SNAPSHOT</version>
	</parent>

	<artifactId>junit4-demo</artifactId>

	<name>junit4-demo</name>
	<url>http://maven.apache.org</url>
	<properties>
		<junit.version>4.12</junit.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>jcg.zheng.demo</groupId>
			<artifactId>common</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>

		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>${junit.version}</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.mockito</groupId>
			<artifactId>mockito-core</artifactId>
			<version>3.2.4</version>
			<scope>test</scope>
		</dependency>
	</dependencies>

</project>

5.2 SomeClassTest

In this step, I will create a SomeClassTest class in JUnit 4. It will use the following Mockito annotation and libraries:

SomeClassTest.java

package jcg.zheng.demo.junit4;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.util.Arrays;
import java.util.List;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

import jcg.zheng.demo.SomeException;
import jcg.zheng.demo.SomeClass;
import jcg.zheng.demo.OtherService;
import jcg.zheng.demo.SomeInterface;

@RunWith(MockitoJUnitRunner.class)
public class SomeClassTest {

	@InjectMocks
	private SomeClass classUnderTest;
	
	@Mock
	private SomeInterface mockedInterface;

	@Mock
	private OtherService mockedService;

	@Test
	public void test_doubleANumber() {
		when(mockedService.calculateByDoubleIt(3)).thenReturn(6);

		assertEquals(6, classUnderTest.doubleANumber(3));
		verify(mockedService, times(1)).calculateByDoubleIt(3);
	}

	@Test(expected = SomeException.class)
	public void test_doubleANumber_exception() {
		when(mockedService.calculateByDoubleIt(3)).thenThrow(NullPointerException.class);
		classUnderTest.doubleANumber(3);

		verify(mockedService, times(1)).calculateByDoubleIt(3);
	}

	@Test
	public void test_processData() {
		when(mockedInterface.getSomeList(anyString())).thenReturn(null);
		classUnderTest.processData("NA");
		
		verify(mockedInterface, times(1)).getSomeList(anyString());
		verify(mockedService, times(0)).doSomething(anyString());
	}

	@Test
	public void test_processData_2() {
		List<String> twoItemsList = Arrays.asList("Mary", "Zheng");
		when(mockedInterface.getSomeList(anyString())).thenReturn(twoItemsList);
		classUnderTest.processData("NA");
		
		verify(mockedInterface, times(1)).getSomeList(anyString());
		verify(mockedService, times(2)).doSomething(anyString());
	}

	@Test(expected = SomeException.class)
	public void test_returnBooleanFoo_exception() {
		when(mockedService.returnABoolean("NA")).thenThrow(NullPointerException.class);
		classUnderTest.returnABoolean("NA");

		verify(mockedService, times(1)).returnABoolean("NA");
	}

	@Test
	public void test_returnBooleanFoo_false() {
		when(mockedService.returnABoolean("NA")).thenReturn(false);

		boolean shouldReturnFalse = classUnderTest.returnABoolean("NA");
		assertFalse(shouldReturnFalse);
	}

	@Test
	public void test_returnBooleanFoo_true() {
		when(mockedService.returnABoolean("Save")).thenReturn(true);

		boolean shouldReturnTrue = classUnderTest.returnABoolean("Save");
		assertTrue(shouldReturnTrue);
		verify(mockedService, times(1)).returnABoolean("Save");
	}

	@Test
	public void test_voidFoo() throws IllegalAccessException {
		try {
			classUnderTest.voidFoo("Ok");
			verify(mockedService, times(1)).doSomething("Ok");
			verify(mockedInterface, times(0)).doSomething(anyString());
		} catch (Exception e) {
			fail("Should not throw exception");
		}
	}

	
	@Test(expected = SomeException.class)
	public void test_voidFoo_exception() {
		doThrow(IllegalStateException.class).when(mockedService).doSomething("NA");
		classUnderTest.voidFoo("NA");
	}
	
	@Test
	public void test_voidFoo_interface() throws IllegalAccessException {
		try {
			classUnderTest.voidFoo("Interface");
			verify(mockedService, times(1)).doSomething("Interface");
			verify(mockedInterface, times(1)).doSomething("Interface");
		} catch (Exception e) {
			fail("Should not throw exception");
		}
	}
}

Output

[INFO] Running jcg.zheng.demo.junit4.SomeClassTest
[INFO] Tests run: 7, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.43 s - in jcg.zheng.demo.junit4.SomeClassTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 7, Failures: 0, Errors: 0, Skipped: 0

6. JUnit 5 Module

In this step, I will create a JUnit 5 test class to test SomeClass with mocked objects.

6.1 POM

The JUnit5-demo module’s pom.xml depends on JUnit 5 and common modules. Please note that it includes: junit-jupiter-engine ,junit-jupiter-api, mockito-core, and mockito-junit-jupiter.

pom.xml

<?xml version="1.0"?>
<project
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
	xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>jcg.zheng.demo</groupId>
		<artifactId>junit-demo</artifactId>
		<version>0.0.1-SNAPSHOT</version>
	</parent>

	<artifactId>junit5-demo</artifactId>

	<name>junit5-demo</name>
	<url>http://maven.apache.org</url>
	<properties>
		<junit-jupiter.version>5.5.2</junit-jupiter.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>jcg.zheng.demo</groupId>
			<artifactId>common</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>

		<dependency>
			<groupId>org.junit.jupiter</groupId>
			<artifactId>junit-jupiter-engine</artifactId>
			<version>${junit-jupiter.version}</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.junit.jupiter</groupId>
			<artifactId>junit-jupiter-api</artifactId>
			<version>${junit-jupiter.version}</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.junit.platform</groupId>
			<artifactId>junit-platform-runner</artifactId>
			<version>1.5.2</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.mockito</groupId>
			<artifactId>mockito-core</artifactId>
			<version>3.2.4</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.mockito</groupId>
			<artifactId>mockito-junit-jupiter</artifactId>
			<version>2.23.0</version>
			<scope>test</scope>
		</dependency>

	</dependencies>


</project>

6.2 SomeClassTest

In this step, I will create a SomeClassTest class in JUnit 5. It has the same annotations as Junit 4, the only difference is Junit 5 uses @ExtendWith(MockitoExtension.class).

SomeClassTest.java

package jcg.zheng.demo.junit5;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.util.Arrays;
import java.util.List;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import jcg.zheng.demo.SomeException;
import jcg.zheng.demo.SomeClass;
import jcg.zheng.demo.OtherService;
import jcg.zheng.demo.SomeInterface;

@ExtendWith(MockitoExtension.class)
public class SomeClassTest {

	@InjectMocks
	private SomeClass classUnderTest;

	@Mock
	private SomeInterface mockedInterface;

	@Mock
	private OtherService mockedService;

	@Test
	@DisplayName("It should double a number")
	public void test_doubleANumber() {
		when(mockedService.calculateByDoubleIt(3)).thenReturn(6);

		assertEquals(6, classUnderTest.doubleANumber(3));
		verify(mockedService, times(1)).calculateByDoubleIt(3);
	}

	@Test
	public void test_doubleANumber_exception() {
		when(mockedService.calculateByDoubleIt(3)).thenThrow(NullPointerException.class);

		assertThrows(SomeException.class, () -> {
			classUnderTest.doubleANumber(3);
		});

		verify(mockedService, times(1)).calculateByDoubleIt(3);
	}

	@Test
	public void test_processData() {
		when(mockedInterface.getSomeList(anyString())).thenReturn(null);
		classUnderTest.processData("NA");

		verify(mockedInterface, times(1)).getSomeList(anyString());
		verify(mockedService, times(0)).doSomething(anyString());
	}

	@Test
	public void test_processData_2() {
		List<String> twoItemsList = Arrays.asList("Mary", "Zheng");
		when(mockedInterface.getSomeList(anyString())).thenReturn(twoItemsList);
		classUnderTest.processData("NA");

		verify(mockedInterface, times(1)).getSomeList(anyString());
		verify(mockedService, times(2)).doSomething(anyString());
	}

	@Test
	public void test_returnBooleanFoo_exception() {
		when(mockedService.returnABoolean("NA")).thenThrow(NullPointerException.class);
		assertThrows(SomeException.class, () -> {
			classUnderTest.returnABoolean("NA");
		});

		verify(mockedService, times(1)).returnABoolean("NA");
	}

	@Test
	public void test_returnBooleanFoo_false() {
		when(mockedService.returnABoolean("NA")).thenReturn(false);

		boolean shouldReturnFalse = classUnderTest.returnABoolean("NA");
		assertFalse(shouldReturnFalse);
	}

	@Test
	public void test_returnBooleanFoo_true() {
		when(mockedService.returnABoolean("Save")).thenReturn(true);

		boolean shouldReturnTrue = classUnderTest.returnABoolean("Save");
		assertTrue(shouldReturnTrue);
		verify(mockedService, times(1)).returnABoolean("Save");
	}

	@Test
	public void test_voidFoo() throws IllegalAccessException {

		classUnderTest.voidFoo("OK");
		verify(mockedService, times(1)).doSomething("OK");

	}

	@Test
	public void test_voidFoo_exception() {
		doThrow(IllegalStateException.class).when(mockedService).doSomething("NA");
		assertThrows(SomeException.class, () -> {
			classUnderTest.voidFoo("NA");
		});

	}

	@Test
	public void test_voidFoo_interface() throws IllegalAccessException {

		classUnderTest.voidFoo("Interface");
		verify(mockedService, times(1)).doSomething("Interface");
		verify(mockedInterface, times(1)).doSomething("Interface");

	}

}

Output

[INFO] Running jcg.zheng.demo.junit5.SomeClassTest
[INFO] Tests run: 10, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.042 s - in jcg.zheng.demo.junit5.SomeClassTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 10, Failures: 0, Errors: 0, Skipped: 0

7. Summary

In this example, I demonstrated how to use Mockito to

  • Create mocked objects with @Mock.
  • Inject the mocked objects for the testing class marked with @InjectMocks.
  • Use Mockito static method to mock the object’s behavior.
  • Verify the mocked object’s method is invoked.

8. Download the Source Code

Download
You can download the full source code of this example here: Java Unit Testing With Mokito Example

Mary Zheng

Mary has graduated from Mechanical Engineering department at ShangHai JiaoTong University. She also holds a Master degree in Computer Science from Webster University. During her studies she has been involved with a large number of projects ranging from programming and software engineering. She works as a senior Software Engineer in the telecommunications sector where she acts as a leader and works with others to design, implement, and monitor the software solution.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button