top

Search

Software Key Tutorial

.

UpGrad

Software Key Tutorial

Mockito tutorial

Introduction

Unit testing is a software testing method where individual units or components of an application are tested in isolation. The purpose is to validate that each unit functions as intended. Unit testing has numerous benefits, like it improves code quality, catches bugs early in development, allows safe refactoring of code and provides documentation of code. However, some units may have dependencies on other objects and components. This makes unit testing more difficult. This is where mocking comes in. This Mockito tutorial covers it in detail. 

Mockito is one of the most popular mocking frameworks for Java. In this Mockito tutorial, we'll learn the basics of Mockito, its useful features and best practices. We will make the learning process easy with Mockito examples.

By the end of this Mockito tutorial, you'll understand how to use Mockito to unit test your Java code effectively.

Overview of Mockito

Mockito is an open-source mocking framework for Java, commonly referred to as the Mockito framework. It was originally created by Szczepan Faber and Philipp Haselwandter as a fork of EasyMock. Mockito simulates the behavior of real objects in automated unit tests.

This comprehensive Mockito JUnit tutorial details how Mockito helps to effectively test a code, especially when integrating with tools like Mockito Maven and Mockito Spring Boot.

In summary, Mockito provides a simple yet powerful API for configuring mock objects and leveraging them in unit tests.

Unit Testing with JUnit

Before jumping into Mockito, let's briefly discuss unit testing. JUnit is the most common Java unit testing framework.  Mockito vs. JUnit is often a topic of discussion. Here is a simple unit test written with JUnit:

import static org.junit.Assert.assertEquals;
import org.junit.Test;

public class CalculatorTest {

  @Test
  public void testAdd() {
    Calculator calculator = new Calculator();
    int sum = calculator.add(2, 3);
    assertEquals(5, sum);
  }

}

This test validates the add() method of a Calculator class by:

  1. Creating an instance of a Calculator

  2. Calling add() with 2 and 3

  3. Asserting the result equals 5

JUnit provides the annotations and assertions to write and run unit tests quickly. However, if the Calculator class had dependencies, they would need to be handled for true unit testing. This is where Mockito comes in.

The Need for Mocking in Unit Tests

Mocking involves creating fake implementations of dependencies and injecting them into the code under test. In a real application, classes often depend on other classes and interfaces. For example, consider a UserService class that depends on a UserRepository interface:

public class UserService {

  private UserRepository userRepository;

  public UserService(UserRepository userRepository) {
    this.userRepository = userRepository;
  }

  public void register(String email, String password) {
    User user = userRepository.findByEmail(email);
    if (user != null) {
      throw new RuntimeException("Email already exists");
    }
    // Save user
  }

}

The UserService depends on the UserRepository to check if a user email already exists when registering a new account.

To properly unit test the register() method in isolation, we need to provide a mock UserRepository somehow. This allows us to simulate test scenarios like:

  • Return a user for a given email to test if the email already exists 

  • Return null to simulate the user not existing in the repository

Without mocking, unit testing the UserService would require integration with a real UserRepository implementation like a database. That leads to slower and more brittle tests.

Key Concepts of Mockito

Let's explore some key Mockito concepts.

Mock Object

A mock object is a fake implementation of a real interface or class that allows predefined output to simulated method calls. Mockito allows mocking interfaces to inject a fake implementation for testing.

UserRepository mockUserRepository = Mockito.mock(UserRepository.class);

Real implementations are avoided so that tests run quickly in isolation without external dependencies.

Injecting Mocks

Once mock objects are created, they need to be injected into the code under test. This allows replacing real dependencies with mocks so that their behavior can be controlled.

@Test 
public void registerNewUserTest() {
  UserRepository mockUserRepo = Mockito.mock(UserRepository.class); 
  
  UserService userService = new UserService(mockUserRepo);
  
  // ...
}

Stubbing Methods

Stubbing a method configures it to return a specific value when called during a test:

Mockito.when(mockUserRepo.findByEmail(anyString())).thenReturn(null);

The stub causes findByEmail() to always return null. This is useful for simulating a new user registration scenario.

Verifying Interactions

Mockito verifies that methods were called with expected parameters:

Mockito.verify(mockUserRepo).findByEmail("test@example.com");

This asserts that findByEmail() was called during the test with the email "test@example.com".

Why Use Mockito for Unit Testing?

There are many advantages of using Mockito for mocks in JUnit tests:

  • Isolated Tests - Only the target code is tested, removing dependencies on external systems.

  • Well-defined Scenarios - Mocks allow pre-configuring inputs and outputs for consistent tests

  • Speed - No waiting on real dependencies to respond during tests

  • Test Precision - Increased control over inputs and expectations improves test accuracy

  • Documentation - Mocking highlights interactions and interfaces that may not be apparent in code

  • Design Feedback - Difficult mocking may indicate code smells and coupling issues

In summary, Mockito makes unit testing Java applications faster, easier and more robust.

Basic Mockito Syntax

Let's explore Mockito syntax and APIs. The key static methods of the Mockito class include:

  • mock() - Creates a mock instance of a class or interface

  • when() - Stubs a method to return a value

  • verify() - Verifies a method was called

  • doThrow() - Configures a method to throw an exception

Here is an example mock:

// Import Mockito library
import static org.mockito.Mockito.*;

// Create mock 
UserRepository mockUserRepo = mock(UserRepository.class);

// Stub method
when(mockUserRepo.findByEmail("test@example.com")).thenReturn(null); 

// Use mock in test
UserService userService = new UserService(mockUserRepo);
userService.register("test@example.com", "pwd");

// Verify interaction
verify(mockUserRepo).findByEmail("test@example.com");

This demonstrates the essential Mockito workflow:

  1. Imports Mockito matchers and methods with import static

  2. Creates a mock with mock()

  3. Configures stubbed methods with when()

  4. Uses the mock in a test

  5. Verifies interactions with mocks via verify()

Now, let's explore some key Mockito capabilities in more detail.

Mocking Classes and Interfaces

Mockito allows the mocking of both classes and interfaces.

To mock an interface:

List mockList = mock(List.class);

To mock a class:

LinkedList mockList = mock(LinkedList.class);

The mocked instances do not contain any actual code implementation. They can be injected and stubbed as needed in tests.

Matchers for Arguments

Mockito includes a variety of matchers to verify that methods were called with the correct parameters.

For example:

//Verify with exact string
verify(mockList).add("Hello");

//Verify with any string   
verify(mockList).add(anyString());

//Verify with contains string
verify(mockList).add(contains("World"));

Common matchers include anyInt(), eq(), contains() and more. They provide flexibility in verifying parameter values.

Returning Values

The Mockito when() method allows stubbing a mock method to return a specified value:

when(mockList.size()).thenReturn(5);
int size = mockList.size(); //Returns 5

This configures all calls to mockList.size() to return 5 without a real implementation.

Throwing Exceptions

Exceptions can be thrown from stubbed methods via doThrow():

doThrow(new RuntimeException()).when(mockList).clear();
mockList.clear(); //Throws RuntimeException

This can be useful for testing exception-handling logic.

Verifying Interactions

Interactions with mock objects can be verified using verify():

verify(mockList).add("Test");
verify(mockList, times(2)).add(anyString());

This validates that add() was called with expected parameters at least once or a specific number of times.

Verification in Order

By default, Mockito verifies mocks in any order. The InOrder API allows verifying sequential interactions:

InOrder inOrder = inOrder(mock1, mock2);
inOrder.verify(mock1).method1(); 
inOrder.verify(mock2).method2();

This asserts that method1() was called before method2().

Mockito Annotations

Mockito provides annotations for simplifying mocks and stubs. For those working with Spring, Mockito spring boot integration can be particularly useful:

@Mock 
List mockList;

@InjectMocks
MyClassUnderTest instance; 

@Test
public void myTest() {
  // MockList injected into instance
}

The @Mock annotation auto-creates a mock while @InjectMocks injects it into the test instance.

Mockito Best Practices

Here are some best practices for Mockito:

  • Only mock types you own - Don't mock classes like String or ArrayList

  • Don't overuse mocks - Too many mocks may indicate a design issue

  • Watch out for stale mocks - Don't reuse mocks across tests

  • Make tests repeatable - Leverage matchers instead of literal values

  • Don't verify unnecessary details - Focus assertions only on critical outputs

Following these practices results in focused, maintainable and robust unit tests.

Mockito Example - Testing with Mocks

Let's look at a complete example of using Mockito for a JUnit test.

We'll test a MessageService that uses a NotificationGateway interface:

public class MessageService {

  private NotificationGateway notificationGateway;

  public MessageService(NotificationGateway notificationGateway) {
    this.notificationGateway = notificationGateway;
  }

  public void sendMessage(String message) {
    // Send message
    notificationGateway.send(message);
  }
}  

public interface NotificationGateway {
  void send(String message);
}

Here is how this can be unit-tested with mocks:

@Test
public void testSendMessage() {

  //Create mock
  NotificationGateway gateway = Mockito.mock(NotificationGateway.class); 
  
  //Create service with mock
  MessageService service = new MessageService(gateway);

  //Call method under test
  service.sendMessage("Hello World"); 
  
  //Verify interaction with mock
  verify(gateway).send("Hello World");
  
}

Key steps:

  1. Create a NotificationGateway mock

  2. Construct MessageService with the mock

  3. Call sendMessage() on the service

  4. Assert send() was called on the mock with the message

This shows how mocks allow us to unit test MessageService in isolation without coupling it to any messaging infrastructure during the test.

Some Key Takeaways From This Mockito Tutorial

  • Mockito is a popular mocking framework for Java unit testing

  • Mocks isolate tests from dependencies and avoid counter-effects

  • Mock methods can be stubbed to simulate behaviors and scenarios

  • Verifying mock interactions ensures methods were called properly

  • Mockito provides a clean and simple API for mocking, stubbing and verifying

Some examples of what you can test using Mockito:

  • Testing expected method calls and arguments

  • Simulating business scenarios like valid vs. invalid data

  • Asserting proper system integration and component interaction

  • Verifying correct exception handling logic

In summary, Mockito makes tests clean and fast by removing external dependencies. Mocks improve test coverage, increase the speed and reliability of tests, and the design of code. 

Conclusion

This Mockito documentation is a valuable resource for students to get more detailed insights on Mockito. We have covered the rationale behind mocking in unit tests, the method to create, inject and configure mocks, useful Mockito features, mocking best practices and a full Mockito example. Mockito removes dependencies that make testing difficult and slows down development. It promotes good design principles and test-driven development. Happy mocking with Mockito!

FAQs

1. What are some key facts about Mockito?

Key things to know about Mockito are:

  • Released in 2007, Mockito 1.0 came out in 2010

  • Licensed under the MIT License

  • Mockito 3 is the current major version

  • Easy to use Java API for mocking interfaces, classes and methods

  • Supported by all modern IDEs like Eclipse, IntelliJ and NetBeans

  • Has an active open-source community with over 430 contributors

2. What are some of the key features and capabilities of Mockito?

Some of the features and capabilities of Mockito include:

  • Mocking interfaces, classes, methods, and arguments 

  • Returning custom values from mocks

  • Verifying method interactions with mocks

  • Throwing exceptions from mocks

  • Spying on real object behavior

  • Stubbing consecutive method calls

  • Parameterized mocking

3. What is the difference between @Mock and @InjectMocks?

The @Mock annotation is used to create a mock. The @InjectMocks creates an instance of the class and injects the mocks that were created with the @Mock annotation into this instance.

Leave a Reply

Your email address will not be published. Required fields are marked *