🚴

[Java]ユニットテスト・モック

に公開

はじめに

ここでは以下についてまとめています。

  • ユニットテストとは
  • アサーション
  • モック

ユニットテストとは

個々のメソッドやクラス単位で正しい動作を保証するためのテスト手法です。
特にバグを早期に発見しやすく、保守性や信頼性の高いコードを書くために不可欠になっています。

アサーション

メソッド 説明
assertEquals(expected, actual) 値が一致することをテスト
assertTrue(condition) 条件がtrueであることをテスト
assertFalse(condition) 条件がfalseであることをテスト
assertNull(obj) nullであることをテスト
assertNotNull(obj) nullでないことをテスト

https://junit.org/junit5/docs/5.0.1/api/org/junit/jupiter/api/Assertions.html

モック

モックはJavaのユニットテストにおいて、外部依存を排除してロジックのテストに集中するための重要な手法になっています。
具体的には、テスト対象のクラスが依存する外部クラス(DB、API、メール送信など)の代わりに動作するダミーのオブジェクトです。
モックを使用する目的は以下のようになっています。

  • 外部環境に依存せずにテスト可能
  • 呼び出し回数や引数を検証できる
  • テストの実行速度が速く、安定する
    ただし過剰なモックはテストを保守しづらくします。
種類 主な目的 機能 ライブラリ
モック(Mock) 振る舞いの検証 呼び出し検証・スタブ化も可能 Mockito
スタブ(Stub) 戻り値を固定 when(...).thenReturn(...) Mockito

モックの作成

mock(...)は インターフェースやクラスの偽オブジェクト(ダミー) を作ります。
dbは本物のDatabaseではなく、振る舞いを設定しないと何もしないオブジェクトです。

Database db = mock(Database.class);

振る舞いのスタブ

when(...).thenReturn(...)は、モックに対する返り値の定義です。
getUserById(1)が呼ばれたらnew User("Alice")を返すようにします。

when(db.getUserById(1)).thenReturn(new User("Alice"));

以下は任意の引数でも対応させたい場合です。

when(db.getUserById(anyInt())).thenReturn(new User("DefaultUser"));

テスト対象に渡して実行

Service service = new Service(db);
service.doSomething();

呼び出し検証

verify(...)は、指定したメソッドが呼び出されたかどうかを検証します。

verify(db).getUserById(1); // そのメソッドが呼ばれたか確認
verifyNoMoreInteractions(db); // 他に何も呼ばれていないか
verify(db, times(1)).getUserById(1); // 1回だけ呼ばれたか確認
verifyNoInteractions(db); //呼ばれていないことの確認

例外をスローさせる

when(paymentGatewayMock.pay(anyString(), anyDouble()))
    .thenThrow(new RuntimeException("支払いエラー"));

例)メール送信処理のテスト

以下は、MailSenderクラスがEmailGatewayを使って正しくメール送信処理を呼び出しているかを単体テストするものです。

public class MailSender {
    private EmailGateway gateway;
    public MailSender(EmailGateway gateway) {
        this.gateway = gateway;
    }

    public void sendWelcome(String email) { //本物の実装では、SMTP送信処理やAPI連携などが行われる
        gateway.send(email, "Welcome!");
    }
}

・テストコード

@Test
void testSendWelcomeEmail() {
    EmailGateway mockGateway = mock(EmailGateway.class); // ①モック作成
    MailSender sender = new MailSender(mockGateway);     // ②モックを注入

    sender.sendWelcome("user@example.com");              // ③メソッド実行

    verify(mockGateway).send("user@example.com", "Welcome!"); // ④検証
}
ステップ 内容 詳細
mock(EmailGateway.class) Mockitoを使ってEmailGatewayのモック(偽物)を作成。中身は空だけど呼び出し履歴を記録する仕組みを持つ。
new MailSender(mockGateway) 作成したモックを依存として渡す。これにより、本物のメール送信処理は呼び出されず、安全にテスト可能。
sendWelcome(...) テスト対象のメソッドを実行。「user@example.com」宛に「Welcome!」というメールを送るよう依頼。
verify(...) モックが指定の引数で呼ばれたかを確認。つまり「EmailGateway.send(...)が本当に呼ばれたか?」を検証している。

Mockitoメソッド

メソッド 説明
mock(Class<T>) モック生成
when(...).thenReturn(...) 戻り値スタブ
verify(obj).method() 呼び出し検証
verify(obj, times(n)) 呼び出し回数の検証
verifyNoMoreInteractions(obj) 追加の呼び出しがないことを検証
doThrow(...).when(...).method() 例外をスローさせる
any(), eq(), contains() 引数マッチャー

Discussion