Mockitoを使用して、モックにしたメソッドの呼出回数によって正常な値と例外を返却する方法を残します。
環境
- Java
- 17
- org.mockito.junit.jupiter
- 4.0.0
ユースケース
- 1
対応
次の現在日付を返却するメソッドをモックにします。
public interface OffsetDateTimeResolver{ default OffsetDateTime now() { return OffsetDateTime.now(ZoneId.of("Asia/Tokyo")); } }
Mockito.when
を使用して、パラメータにてモック対象のメソッドを呼び出します。
そのままメソッドチェインでthenReturn
を使用すると、正常系の値を返却します。第二パラメータ以降を可変長引数で渡している場合、パラメータの順番と呼出回数による返却値が一致します。
同様にthenThrow
を使用すると、異常系の値を返却します。可変長引数も同様の挙動です。
次のコードの例は1回目が正常系、2回目が正常系、3回目が異常系、4回目が正常系、5回目が異常系を返却するテストです。
@Mock private OffsetDateTimeResolver offsetDateTimeResolver; @DisplayName("1回目OK, 2回目OK, 3回目NG, 4回目OK, 5回目NG") @Test void _1OK_2OK_3NG_4OK_5NG() { // GIVEN OffsetDateTime now = OffsetDateTime.now(); // 現在時刻 when(offsetDateTimeResolver.now()) .thenReturn(now, now) // 1回目, 2回目 .thenThrow(new RuntimeException()) // 3回目 .thenReturn(now) // 4回目 .thenThrow(new RuntimeException()); // 5回目 // THEN // 1回目 assertThat(offsetDateTimeResolver.now()).isEqualTo(now); // 2回目 assertThat(offsetDateTimeResolver.now()).isEqualTo(now); // 3回目 assertThatThrownBy(() -> offsetDateTimeResolver.now()).isInstanceOf(RuntimeException.class); // 4回目 assertThat(offsetDateTimeResolver.now()).isEqualTo(now); // 5回目 assertThatThrownBy(() -> offsetDateTimeResolver.now()).isInstanceOf(RuntimeException.class); }
備考
Mockito.when
にモック対象のメソッドをパラメータに渡すたびにモック設定がリセットされます。
次のコードの例は正常系の設定をした後に、異常系の設定をし直しているので、1回目から異常系の値を返却してしまっています。
@Test void resetされる() { // GIVEN OffsetDateTime now = OffsetDateTime.now(); when(offsetDateTimeResolver.now()).thenReturn(now); when(offsetDateTimeResolver.now()).thenThrow(new RuntimeException(ERROR_MESSAGE)); // THEN // 1回目が正常系を返却しない assertThatThrownBy(() -> offsetDateTimeResolver.now()).isInstance(RuntimeException.class) assertThatThrownBy(() -> offsetDateTimeResolver.now()).isInstance(RuntimeException.class) }
なお、あくまでソースコードは例です。
実際、上の書き方だとアサーションルーレットと呼ばれるよろしくない書き方になってしまうので、この記事を参考にしてSoftAssertions
を使用してみませんか?
ソースコード
終わりに
Mockitoにて正常系の後に異常系、異常系の後に正常系を返却できるということを勉強できてよかったです。
実際はここまで複雑なケースは出会わないかもしれないのですが、当処理で解消できそうなツイートがありましたので、出会う確率は0ではないと思います。
この記事を書くきっかけになったツイート
twitter.com2つのスレッドで同じ処理を並列実行して、少しでもあとから実行された方でのみ例外が発生するってテスト、どう書けばえんや・・・
— Masatoshi Tada🎉 (@suke_masa) 2022年3月28日