モックでの検証

Javaによるテスト入門

Maria Milusheva

Senior Software Engineer

動機: 戻り値なし

前のレッスンと演習では、戻り値に対してアサートしました。

  • しかし、戻り値がない場合は?

  • 戻り値が重要でない/情報が少ない場合は?

例: データベースへの保存。

ファイルが保存されるデータベースの図

Javaによるテスト入門

例: データベース

データベース: データを整理して保存・管理・保護するデジタルな保管庫。多くのプロバイダーがあります。 いくつかの有名なデータベースのロゴ

  • データベースサーバーは耐久・安全・信頼性が高く、容量は実質無制限

  • 本物のデータベースは単体テストには大きく複雑(結合テストでは使用可)

Javaによるテスト入門

例: ログメッセージ

ログを処理するとします。

public class MessageProcessor {
    private InfoStore infoStore;  // 情報ログを保存
    private ErrorStore errorStore; // エラーログを保存

    public void saveMessage(String message) {
        if (message.startsWith("[INFO]")) {
            infoStore.save(message);
        }
        if (message.startsWith("[ERROR]")) {
            errorStore.save(message);
        }
    }
}
Javaによるテスト入門

InfoStore と ErrorStore

テストに必要なのは基本的なインターフェースだけです。

// InfoStore と ErrorStore の設計図
// モックは実装がなくても動作します
interface InfoStore {
    void save(String message);
}

interface ErrorStore {
    void save(String message);
}
Javaによるテスト入門

Mockito の verify

データベースを作らずに、保存されたことをどうテストしますか?

モックが使われたことを検証:

import static org.mockito.Mockito.verify;

モックが使われなかったことを検証:

import static org.mockito.Mockito.verifyNoInteractions;
Javaによるテスト入門

テストのセットアップ

@Test
void process_savesToInfoStore_whenInfoMessage() {
  InfoStore infoStore = mock(InfoStore.class);
  ErrorStore errorStore = mock(ErrorStore.class);
  MessageProcessor messageProcessor = new MessageProcessor(infoStore, errorStore);

String message = "[INFO] Process started."; messageProcessor.saveMessage(message); // Will use either InfoStore or ErrorStore
// どちらのデータベースが使われたかを検証 verify(infoStore).save(message); verifyNoInteractions(errorStore); }
Javaによるテスト入門

テスト失敗メッセージ

作成するメッセージが次のような場合はどうでしょう。

String message = "[ERROR] Process failed!"

次のようなテスト失敗が発生します:

Wanted but not invoked:
infoStore.save("[ERROR] Process failed!");
Actually, there were zero interactions with this mock.
Javaによるテスト入門

さらに使える検証テクニック

呼び出し回数も正確に検証できます。

import static org.mockito.Mockito.times;
List<String> messages = new ArrayList<>(); // リストを作成して要素を追加
                messages.add("[INFO] Processing data...");
                messages.add("[INFO] Processing data...");
                messages.add("[INFO] Processing data...");

messageProcessor.saveMessageList(messages); // 3件を保存


verify(infoStore, times(3)).save("[INFO] Processing data...");
Javaによるテスト入門

Ayo berlatih!

Javaによるテスト入門

Preparing Video For Download...