9
10

More than 3 years have passed since last update.

Mockito 3 + JUnit 5 で基本的なモック化とテストをするサンプルコード

Last updated at Posted at 2020-08-05

概要

  • Mockito 3 + JUnit 5 で基本的なモック化とテストをするサンプルコードを示す
  • 今回の動作確認環境: Java 15 (AdoptOpenJDK 15.0.1+9) + Gradle 6.7 + Mockito 3.6.0 + JUnit 5.7.0 + macOS Catalina

サンプルコード

ソースコード一覧

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

build.gradle

ビルド・テスト実行用 Gradle 設定ファイル。

plugins {
  id 'java'
}

repositories {
  jcenter()
}

dependencies {
  // Junit 5 を導入
  // https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter
  testImplementation 'org.junit.jupiter:junit-jupiter:5.7.0'

  // Mockito 3 を導入
  // https://mvnrepository.com/artifact/org.mockito/mockito-core
  testImplementation 'org.mockito:mockito-core:3.6.0'

  // Mockito による JUnit 5 Extension ライブラリを導入
  // https://mvnrepository.com/artifact/org.mockito/mockito-junit-jupiter
  testImplementation 'org.mockito:mockito-junit-jupiter:3.6.0'
}

test {
  // JUnit platform を使う設定
  useJUnitPlatform()

  // テスト時の出力設定
  testLogging {
    // テスト時の標準出力と標準エラー出力を表示する
    showStandardStreams true
    // イベントを出力する (TestLogEvent)
    events 'started', 'skipped', 'passed', 'failed'
    // 例外発生時の出力設定 (TestExceptionFormat)
    exceptionFormat 'full'
  }
}

src/main/java/Worker.java

モック化の対象となるクラス。

public class Worker {

  // 引数あり・戻り値ありメソッド
  public int ariari(int x) {
    throw new IllegalStateException("環境依存で発生するみたいな例外");
  }

  // 引数なし・戻り値なしメソッド
  public void nasinasi() {
    throw new IllegalStateException("環境依存で発生するみたいな例外");
  }
}

src/main/java/Client.java

テスト対象のクラス。

public class Client {

  private Worker worker = new Worker();

  // 引数あり・戻り値ありメソッドを呼び出す
  public int callAriari(int x) {
    return worker.ariari(x * 2); // 2倍にした値を Worker#ariari に渡す
  }

  // 引数なし・戻り値なしメソッドを呼び出す
  public int callNasinasi(int x) {
    worker.nasinasi(); // Worker#nasinasi を呼び出す
    return x * 2; // 2倍にした値を返す
  }
}

src/test/java/ClientTest.java

テストクラス。
Worker クラスを Mockito 3 でモック化し、Client クラスのテストを 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) // Mockito による JUnit 5 エクステンション
public class ClientTest {

  // モックを注入するオブジェクト
  @InjectMocks
  private Client client = new Client();

  // モック化するオブジェクト
  @Mock
  private Worker mockedWorker;

  @Test
  public void 引数あり_戻り値あり() {
    // モックの振る舞い: Worker#ariari に 2 が渡されたときに 6 を返す
    doReturn(6).when(mockedWorker).ariari(2);
    // テスト: Client#callAriari に 1 を渡すとモックの Worker#ariari に 2 を渡して 6 が返ってくる
    assertEquals(6, client.callAriari(1));
  }

  @Test
  public void 引数なし_戻り値なし() {
    // モックの振る舞い: Worker#nasinasi を呼び出したときに何もしない
    doNothing().when(mockedWorker).nasinasi();
    // テスト: Client#callNasinasi に 1 を渡すとモックの Worker#nasinasi を実行して 2 が返ってくる
    assertEquals(2, client.callNasinasi(1));
  }

  @Test
  public void 例外発生() {
    // モックの振る舞い: Worker#ariari に 4 が渡されたときに例外を投げる
    doThrow(new IllegalArgumentException("モック例外")).when(mockedWorker).ariari(4);
    // テスト: Client#callAriari に 2 を渡すとモックの Worker#ariari に 4 を渡して例外が投げられる
    IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> client.callAriari(2));
    // テスト: 例外に想定したメッセージが含まれている
    assertEquals("モック例外", e.getMessage());
  }

  @Test
  public void 順次呼び出し() {
    // モックの振る舞い: Worker#ariari に 6 が渡されたときに例外を2回投げたあと 18 を返す
    doThrow(new IllegalArgumentException("モック例外1回目"))
      .doThrow(new IllegalArgumentException("モック例外2回目"))
      .doReturn(18)
      .when(mockedWorker).ariari(6);
    // テスト: Client#callAriari に 3 を渡すとモックの Worker#ariari に 6 を渡して例外が投げられる
    IllegalArgumentException e1 = assertThrows(IllegalArgumentException.class, () -> client.callAriari(3));
    assertEquals("モック例外1回目", e1.getMessage());
    // テスト: Client#callAriari に 3 を渡すとモックの Worker#ariari に 6 を渡して例外が投げられる
    IllegalArgumentException e2 = assertThrows(IllegalArgumentException.class, () -> client.callAriari(3));
    assertEquals("モック例外2回目", e2.getMessage());
    // テスト: Client#callAriari に 3 を渡すとモックの Worker#ariari に 6 を渡して 18 が返ってくる
    assertEquals(18, client.callAriari(3));
  }
}

テスト実行

Gradle で test タスクを実行した例。

$ gradle test
Starting a Gradle Daemon (subsequent builds will be faster)

> Task :test

ClientTest > 引数なし_戻り値なし() STARTED

ClientTest > 引数なし_戻り値なし() PASSED

ClientTest > 引数あり_戻り値あり() STARTED

ClientTest > 引数あり_戻り値あり() PASSED

ClientTest > 例外発生() STARTED

ClientTest > 例外発生() PASSED

ClientTest > 順次呼び出し() STARTED

ClientTest > 順次呼び出し() PASSED

BUILD SUCCESSFUL in 19s
3 actionable tasks: 3 executed

参考資料

9
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
10