[Java] Sample code for basic mocking and testing with Mockito 3 + JUnit 5

3 minute read

Overview

  • Shows sample code for basic mocking and testing with Mockito 3 + JUnit 5
  • Confirmation environment of this time: Java 14 (AdoptOpenJDK 14.0.2+12) + Gradle 6.5.1 + Mockito 3.4.6 + JUnit 5.6.2 + macOS Catalina

Sample code

Source code list

├── build.gradle
└── src
    ├── main
    │  └── java
    │  ├── Client.java
    │  └── Worker.java
    └── test
        └── java
            └── ClientTest.java

build.gradle

Gradle configuration file for build/test execution.

plugins {
  id'java'
}

repositories {
  jcenter()
}

dependencies {
  // Introduce Junit 5
  // https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter
  testImplementation'org.junit.jupiter:junit-jupiter:5.6.2'

  // Introduce Mockito 3
  // https://mvnrepository.com/artifact/org.mockito/mockito-core
  testImplementation'org.mockito:mockito-core:3.4.6'

  // Introduce JUnit 5 Extension library by Mockito
  // https://mvnrepository.com/artifact/org.mockito/mockito-junit-jupiter
  testImplementation'org.mockito:mockito-junit-jupiter:3.4.6'
}

test {
  // Setting to use JUnit platform
  useJUnitPlatform()

  // Output setting during test
  testLogging {
    // display standard output and standard error output during testing
    showStandardStreams true
    // Output event (TestLogEvent)
    events'started','skipped','passed','failed'
    // Output setting when an exception occurs (TestExceptionFormat)
    exceptionFormat'full'
  }
}

src/main/java/Worker.java

The class to be mocked.

public class Worker {

  // Method with arguments and return value
  public int ariari(int x) {
    throw new IllegalStateException("Environmentally dependent exception");
  }

  // method with no arguments and no return value
  public void nasinasi() {
    throw new IllegalStateException("Environmentally dependent exception");
  }
}

src/main/java/Client.java

The class to test.

public class Client {

  private Worker worker;

  // Call method with arguments/return value
  public int callAriari(int x) {
    return worker.ariari(x * 2); // pass the doubled value to Worker#ariari
  }

  // Call the method with no arguments and no return value
  public int callNasinasi(int x) {
    worker.nasinasi(); // call Worker#nasinasi
    return x * 2; // return doubled value
  }
}

src/test/java/ClientTest.java

Test class. Mock the Worker class with Mockito 3, and test the Client class with JUnit 5.

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 static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;

@ExtendWith(MockitoExtension.class) // JUnit 5 extension with Mockito
public class ClientTest {

  // object to inject mock
  @InjectMocks
  private Client client = new Client();

  // object to mock
  @Mock
  private Worker mockedWorker;

  @Test
  public void With argument_With return value () {
    // Mock behavior: Worker#ariari returns 6 when 2 is passed
    doReturn(6).when(mockedWorker).ariari(2);
    // Test: Pass 1 to Client#callAriari, pass 2 to Worker#ariari of the mock and return 6
    assertEquals(6, client.callAriari(1));
  }

  @Test
  public void No argument_No return value () {
    // Mock behavior: do nothing when calling Worker#nasinasi
    doNothing().when(mockedWorker).nasinasi();
    // Test: Pass 1 to Client#callNasinasi, execute mock Worker#nasinasi and return 2
    assertEquals(2, client.callNasinasi(1));
  }

  @Test
  public void Exception raised () {
    // Mock behavior: throw an exception when 4 is passed to Worker#ariari
    doThrow(new IllegalArgumentException("mock exception")).when(mockedWorker).ariari(4);
    // Test: Passing 2 to Client#callAriari throws 4 with mock Worker#ariari throwing an exception
    IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> client.callAriari(2));
    // test: the exception contains the expected message
    assertEquals("Mock exception", e.getMessage());
  }

  @Test
  public void sequential call () {
    // Mock behavior: Worker#ariari throws 2 exceptions when 6 is passed and then returns 18
    doThrow(new IllegalArgumentException("Mock exception first time"))
      .doThrow(new IllegalArgumentException("Mock exception second time"))
      .doReturn(18)
      .when(mockedWorker).ariari(6);
    // Test: Passing 3 to Client#callAriari throws an exception with 6 passed to Worker#ariari in the mock
    IllegalArgumentException e1 = assertThrows(IllegalArgumentException.class, () -> client.callAriari(3));
    assertEquals("Mock exception first time", e1.getMessage());
    // Test: Passing 3 to Client#callAriari throws an exception with 6 passed to Worker#ariari in the mock
    IllegalArgumentException e2 = assertThrows(IllegalArgumentException.class, () -> client.callAriari(3));
    assertEquals("Mock exception second time", e2.getMessage());
    // Test: Pass 3 to Client#callAriari, pass 6 to Worker#ariari of the mock and return 18
    assertEquals(18, client.callAriari(3));
  }
}

Test execution

An example of executing test task with Gradle.

$ gradle test

> Task :test

ClientTest> No argument_No return value () STARTED

ClientTest> No argument_No return value () PASSED

ClientTest> With argument_With return value () STARTED

ClientTest> With argument_With return value () PASSED

ClientTest> Exception raised () STARTED

ClientTest> Exception raised () PASSED

ClientTest> Sequential call () STARTED

ClientTest> Sequential call () PASSED

BUILD SUCCESSFUL in 2s
3 actionable tasks: 3 executed

Reference materials- Mockito (Mockito 3.4.6 API)