Mockito With Examples

Mockito With Examples | Mockito is built on the top of JUnit. It is given to perform unit testing by mocking the local dependent or external dependent objects. Example:- The service class has a dependency on the DAO class and the DAO class communicates with the database. The service class contains business logic and the DAO class contains persistence logic.

Service class => DAO class => Database software.

Assume the DAO class is unavailable (or not ready yet), but the Service class is available and we want to do unit testing. In that case, we need to create a mock/fake/dummy object for the DAO class and assign/inject it to the service class to write test cases on service class methods.

Other examples are Stock Broker applications and Stock Exchange applications. When a stockbroker application is under development, they may not take a subscription to the Stock exchange component because it is costly. Generally, this subscription will be taken after hosting/releasing the Stockbroker application. Till that time they need to take one mock stock exchange component and assign it to a service class to perform unit testing.

Mock objects are for temporary needs, mostly they will be used in the unit testing. These mock objects created in test methods or test case classes do not affect the real code.

We can do this mocking in 3 ways:-

  • Using Mock object/Fake object:- It provides temporary objects.
  • Using Stub object:- It provides some functionalities for the methods of the mock object like specifying for certain inputs or certain outputs should come.
  • Using spy object:- It is called partial mock object or half mock object which means if we provide new functionality to the method then it will be used otherwise real object functionality will be used. While working with spy objects, we will be having real objects also.

Instead of creating classes manually to prepare Mock, Stub, and Spy objects, we can use mocking frameworks available in the market that are capable of generating such classes dynamically at runtime as InMemory classes (classes that are generated in the JVM memory of RAM).

List of mocking frameworks:-

  • Mockito
  • JMockito
  • EasyMock
  • PowerMock

Also see:-

Mockito Example Application

Testing the LoginMgmtService class without keeping the LoginDAO class ready.

Step 1:- Create a maven project.

Create a new Maven project => Select archetype: maven-acrchetype-quickstart of org.apache.maven.acrchetype => Group Id: com.knowprogram, Artifact Id: MockitoUnitTesting-LoginApp. Open pom.xml and change the maven.compiler.source and maven.compiler.target to your workspace available Java version. Then right click => maven => update project.

<properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <maven.compiler.source>11</maven.compiler.source>
  <maven.compiler.target>11</maven.compiler.target>
</properties>

Step 2:- Remove the existing Junit dependency and add the latest JUnit Jupiter Engine in pom.xml between <dependencies> and </dependencies>:-

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.10.2</version>
    <scope>test</scope>
</dependency>

Also add Mockito dependency:-

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>5.12.0</version>
    <scope>test</scope>
</dependency>

After adding the dependencies, right-click on the project => maven => update project. The main/service classes are placed inside the src/main/java folder whereas test case classes/Test Suite classes are placed inside the src/test/java folder.

Step 3:- Develop service interface, service class, and DAO interface.

  • com.knowprogram.service
    • ILoginMgmtService.java (I)
    • LoginMgmtServiceImpl.java (c)
  • com.knowprogram.dao
    • ILoginDAO.java (I)
package com.knowprogram.dao;

public interface ILoginDAO {

    public int authenticate(String username, String password);
}
package com.knowprogram.service;

public interface ILoginMgmtService {

    public boolean login(String username, String password);
}
package com.knowprogram.service;

import com.knowprogram.dao.ILoginDAO;

public class LoginMgmtServiceImpl implements ILoginMgmtService {

    private ILoginDAO loginDAO;

    public LoginMgmtServiceImpl(ILoginDAO loginDAO) {
        this.loginDAO = loginDAO;
    }

    @Override
    public boolean login(String username, String password) {
        if (username.isBlank() || password.isBlank()) {
            throw new IllegalArgumentException("Empty Credentials");
        }
        // Use LoginDAO
        int count = loginDAO.authenticate(username, password);
        System.out.println("count: " + count);
        return count != 0 ? true : false;
    }
}
package com.knowprogram.test;

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 org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

import com.knowprogram.dao.ILoginDAO;
import com.knowprogram.service.ILoginMgmtService;
import com.knowprogram.service.LoginMgmtServiceImpl;

public class LoginMgmtServiceTest {

    private static ILoginMgmtService loginService;
    private static ILoginDAO loginDAOMock;

    @BeforeAll
    public static void setupOnce() {
        
        // Implementation class of ILoginDAO(I) is not available yet.

        // create mock/fake/dummy object
        loginDAOMock = Mockito.mock(ILoginDAO.class);
        // mock() method generates InMemory class implementing ILoginDAO(I)
        // having null method definitions for authenticate(-,-) method

        System.out.println(loginDAOMock.getClass());
        System.out.println(Arrays.toString(loginDAOMock.getClass().getInterfaces()));

        // create service class object
        loginService = new LoginMgmtServiceImpl(loginDAOMock);
    }

    @AfterAll
    public static void clearOnce() {
        loginDAOMock = null;
        loginService = null;
    }

    @Test
    public void testLoginWithValidCredentials() {
        // provide Stub (temporary functionalities) for DAO's authenticate method
        Mockito.when(loginDAOMock.authenticate("admin", "admin@123")).thenReturn(1);
        // unit testing
        assertTrue(loginService.login("admin", "admin@123"));
    }

    @Test
    public void testLoginWithInvalidCredentials() {
        // provide Stub (temporary functionalities) for DAO's authenticate method
        Mockito.when(loginDAOMock.authenticate("admin", "admin")).thenReturn(0);
        // unit testing
        assertFalse(loginService.login("admin", "admin"));
    }

    @Test
    public void testLoginWithNoCredentials() {
        assertThrows(IllegalArgumentException.class, () -> loginService.login("", ""));
    }
}

Run the LoginMgmtServiceTest test class as JUnit test. Output in console:-

Mockito.spy() Vs Mockito.mock() Method

The mock() can accept the class name only whereas the spy() object can accept the real object or class name (in this case, a real object with default values will be passed).

package com.knowprogram.test;

import java.util.ArrayList;
import java.util.List;

import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

public class MockVsSpyTest {
    
    @Test
    public void testList() {
        List<String> listMock = Mockito.mock(ArrayList.class);
        
        List<String> listSpy = Mockito.spy(new ArrayList());
        // or
        // List<String> listSpy = Mockito.spy(ArrayList.class);
        
        listMock.add("table");
        listSpy.add("table");
        
        System.out.println(listMock.size()); // 0
        System.out.println(listSpy.size()); // 1
        
    }

}

Stub on Mock and Spy object

Stub provides some functionalities for the methods of the mock object like specifying for certain inputs or certain outputs should come.

package com.knowprogram.test;

import java.util.ArrayList;
import java.util.List;

import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

public class MockVsSpyTest {
    
    @Test
    public void testList() {
        List<String> listMock = Mockito.mock(ArrayList.class);
        
        // passing real object to spy()
        List<String> listSpy = Mockito.spy(ArrayList.class);
        
        listMock.add("table");        
        // stub on mock object
        Mockito.when(listMock.size()).thenReturn(10); 
        
        listSpy.add("table");
        // stub on spy object
        Mockito.when(listSpy.size()).thenReturn(9);
        
        System.out.println(listMock.size()); // 10
        System.out.println(listSpy.size()); // 9
        
    }

}

Mockito.verify() Method

The spy objects are useful to check how many times methods are called and whether they are called or not because the spy object is always linked with real objects. For this we can use Mockito.verify() method.

package com.knowprogram.dao;

public interface ILoginDAO {

    public int authenticate(String username, String password);

    public int addUser(String user, String role);
}
package com.knowprogram.service;

public interface ILoginMgmtService {

    public boolean login(String username, String password);

    public String registerUser(String user, String role);
}
package com.knowprogram.service;

import com.knowprogram.dao.ILoginDAO;

public class LoginMgmtServiceImpl implements ILoginMgmtService {

    private ILoginDAO loginDAO;

    public LoginMgmtServiceImpl(ILoginDAO loginDAO) {
        this.loginDAO = loginDAO;
    }

    public String registerUser(String user, String role) {
        if (!role.equalsIgnoreCase("") && !role.equalsIgnoreCase("visitor")) {
            loginDAO.addUser(user, role);
            return "User Added";
        }
        return "User Not Added";
    }

}
package com.knowprogram.test;

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 java.util.Arrays;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

import com.knowprogram.dao.ILoginDAO;
import com.knowprogram.service.ILoginMgmtService;
import com.knowprogram.service.LoginMgmtServiceImpl;

public class LoginMgmtServiceTest {

    private static ILoginMgmtService loginService;
    private static ILoginDAO loginDAOMock;

    @BeforeAll
    public static void setupOnce() {

        // Implementation class of ILoginDAO(I) is not available yet.

        // create mock/fake/dummy object
        loginDAOMock = Mockito.mock(ILoginDAO.class);
        // mock() method generates InMemory class implementing ILoginDAO(I)
        // having null method definitions for authenticate(-,-) method

        System.out.println(loginDAOMock.getClass());
        System.out.println(Arrays.toString(loginDAOMock.getClass().getInterfaces()));

        // create service class object
        loginService = new LoginMgmtServiceImpl(loginDAOMock);
    }

    @AfterAll
    public static void clearOnce() {
        loginDAOMock = null;
        loginService = null;
    }

    @Test
    public void testLoginWithNoCredentials() {
        assertThrows(IllegalArgumentException.class, () -> loginService.login("", ""));
    }

    @Test
    public void testRegisterWithSpy() {
        ILoginDAO loginDAOSpy = Mockito.spy(ILoginDAO.class);
        ILoginMgmtService loginService = new LoginMgmtServiceImpl(loginDAOSpy);
        loginService.registerUser("Rocco", "admin");
        loginService.registerUser("William", "visitor");
        loginService.registerUser("Jerry", "");

        // check in the above register method calls whether adduser(-,-) is called
        // for 1 or more times internally or not for the inputs "Rocco", "admin".
        Mockito.verify(loginDAOSpy, Mockito.times(1)).addUser("Rocco", "admin");
        Mockito.verify(loginDAOSpy, Mockito.times(0)).addUser("William", "visitor");
        Mockito.verify(loginDAOSpy, Mockito.never()).addUser("Jerry", "");
    }
}

Mockito Annotations

  • @Mock:- To generate a mock object
  • @Spy:- To generate a spy object
  • @InjectMocks:- To inject mock or spy objects to service class
MockitoAnnotations.openMocks(this);

We must call this MockitoAnnotations.openMocks(this) method in @Before or constructor test case class in order to activate Mockito Annotations.

package com.knowprogram.test;

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 org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

import com.knowprogram.dao.ILoginDAO;
import com.knowprogram.service.ILoginMgmtService;
import com.knowprogram.service.LoginMgmtServiceImpl;

public class LoginMgmtServiceTestAnno {

    // use service implementation class instead of service interface
    @InjectMocks
    private LoginMgmtServiceImpl loginService;

    @Mock
    private ILoginDAO loginDAOMock;

    // to get spy object
    // @Spy
    // private ILoginDAO loginDAOSpy;

    public LoginMgmtServiceTestAnno() {
        // must call this method to activate annotations
        MockitoAnnotations.openMocks(this);
    }

    @Test
    public void testLoginWithValidCredentials() {
        Mockito.when(loginDAOMock.authenticate("admin", "admin@123")).thenReturn(1);
        assertTrue(loginService.login("admin", "admin@123"));
    }

    @Test
    public void testLoginWithInvalidCredentials() {
        Mockito.when(loginDAOMock.authenticate("admin", "admin")).thenReturn(0);
        assertFalse(loginService.login("admin", "admin"));
    }

    @Test
    public void testLoginWithNoCredentials() {
        assertThrows(IllegalArgumentException.class, () -> loginService.login("", ""));
    }

    @Test
    public void testRegisterWithSpy() {
        ILoginDAO loginDAOSpy = Mockito.spy(ILoginDAO.class);
        ILoginMgmtService loginService = new LoginMgmtServiceImpl(loginDAOSpy);
        loginService.registerUser("Rocco", "admin");
        loginService.registerUser("William", "visitor");
        loginService.registerUser("Jerry", "");

        Mockito.verify(loginDAOSpy, Mockito.times(1)).addUser("Rocco", "admin");
        Mockito.verify(loginDAOSpy, Mockito.times(0)).addUser("William", "visitor");
        Mockito.verify(loginDAOSpy, Mockito.never()).addUser("Jerry", "");
    }

}

BDDMockito

To write stub functionality according to agile user stories/JIRA stories (give.. when.. then..) BDDMockito can be used.

@Test
public void testLoginWithValidCredentials() {
    // Mockito.when(loginDAOMock.authenticate("admin", "admin@123")).thenReturn(1);
    BDDMockito.given(loginDAOMock.authenticate("admin", "admin@123"))
                         .willReturn(1);
    assertTrue(loginService.login("admin", "admin@123"));
}

If you enjoyed this post, share it with your friends. Do you want to share more information about the topic discussed above or do you find anything incorrect? Let us know in the comments. Thank you!

Leave a Comment

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