Mockitoで複数回のメソッド呼び出しをモックする

2020.02.29

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

こんにちは、最近は週5でリングフイットの佐々木です。

この記事はMockitoで呼び出し回数に応じてモックの挙動を変える方法を年に2回くらい調べている気がしてきたので、今度こそは記事にしようと書いたメモです。

使ったライブラリのバージョンなど

  • Java Coretto 8.242.08.1-1
  • mockito-core 3.3.1

やりたいこと

データの永続化層をモックしていて次のようなことが稀によくあります。

  1. モックからデータを参照する
  2. データの変更を保存する
  3. モックから再度同じデータを参照する(このとき更新済みのデータを返してほしい)

この場合同じモックオブジェクトの同一メソッドに対して異なる結果を返すようにセットアップする必要があります。

複数回の呼び出しをセットアップする

やり方は簡単で1回だけのメソッド呼び出しをセットアップする時と同じ要領で#thenReturn#thenThrow を必要なだけ呼び出します。

final List<String> list = mock(List.class);
when(list.get(0))
        .thenReturn("first")
        .thenReturn("second")
        .thenThrow(new RuntimeException("No more !"));
assertEquals("first", list.get(0));
assertEquals("second", list.get(0));
assertThrows(RuntimeException.class, () -> list.get(0));

#doReturnから始まるパターンでも同様です。

doReturn("first")
    .doReturn("second")
    .doThrow(new RuntimeException("No more !"))
    .when(list)
    .get(0);
assertEquals("first", list.get(0));
assertEquals("second", list.get(0));
assertThrows(RuntimeException.class, () -> list.get(0));

ただし以下は意図した動きになりません。

doReturn("One").when(list).get(0);
doReturn("Two").when(list).get(0);
assertEquals("One", list.get(0)); //expected: <One> but was: <Two>

まとめ

記憶では最初のパターンでだけ実現できると思っていたのですが今回検証してみると2つ目のパターンでもできたので意外でした。