JavaのMockitoを使って、対象クラスをモックにすることがあります。ただし、該当クラスのメソッドすべてではなく一部だけモックにして、他は本物のメソッドを呼びたいことがあります。
今回は、モッククラスから本当のメソッドを呼ぶ方法、デフォルト設定で本当のメソッドを呼ぶモックにする方法を記載します。
なお、このように部分的にモックすることを部分モック、Partial Mockと呼びますので、以後はそのように記載します。
環境
- Java
- 17
- org.mockito:mockito-core
- 4.5.1
ユースケース
- クラス全体ではなく、一部だけ本物のメソッドを呼びたい
私は、日付Utilクラスでよくこのユースケースが発生します。現在時刻の取得メソッドの戻り値は固定にしたいが、同クラスの現在時刻を目的のフォーマットの文字列で取得するメソッドは本物のメソッドを呼びたい、等々があります。
前提
Mockito
のwhen
は特に解説しません。
動作確認用として、メソッドを2つ用意し、1つは片方に依存しているメソッドを用意します。呼び出順番を意識したgetFirst
, getSecond
と命名しています。
public class Target { public String getFirst() { return "1"; } public String getSecond() { return getFirst(); } }
対応
本物のメソッドを呼びたい
MockitoのthenCallRealMethod
を呼び出します。
@Test void test_01() { Target target = Mockito.mock(Target.class); // モックにしただけなので、nullが返却される assertThat(target.getFirst()).isNull(); assertThat(target.getSecond()).isNull(); // getFirstをモックで固定したが、getSecondはモックのまま when(target.getFirst()).thenReturn("123"); assertThat(target.getFirst()).isEqualTo("123"); assertThat(target.getSecond()).isNull(); // getSecondは本物メソッドを呼び出したため、getSecondも値を返却している when(target.getSecond()).thenCallRealMethod(); assertThat(target.getFirst()).isEqualTo("123"); assertThat(target.getSecond()).isEqualTo("123"); }
基本は本物メソッドを呼ぶモックにする
thenCallRealMethod
はメソッドごとに設定する必要がありますので、非常に面倒です。
ネストが深かったり、本物を呼び出したいメソッドの量が多い場合は、モックのタイミングで設定しましょう。第2引数にMockito.CALLS_REAL_METHOD
を渡しましょう。
@Test void test_01() { Target target = Mockito.mock(Target.class, Mockito.CALLS_REAL_METHODS); // デフォルトの"1"を返却する assertThat(target.getFirst()).isEqualTo("1"); assertThat(target.getSecond()).isEqualTo("1"); // getFIrstを"123"に固定したので、依存するgetSecondも"123"を返却します。 when(target.getFirst()).thenReturn("123"); assertThat(target.getFirst()).isEqualTo("123"); assertThat(target.getSecond()).isEqualTo("123"); }
@Mock
, @MockBean
等々のアノテーションでモックにする場合も、パラメータで制御できます。
@Mock(answer = Answers.CALLS_REAL_METHODS) Target target; @MockBean(answer = Answers.CALLS_REAL_METHODS) Target target;
ソースコード
- https://github.com/hirotoKirimaru/cucumber-sample/blob/6f85f644bef7b96b9d3b047b1f7d951a62cbdedb/kirimaru-core/src/test/java/kirimaru/biz/domain/MockTests.java
- https://github.com/hirotoKirimaru/cucumber-sample/blob/6f85f644bef7b96b9d3b047b1f7d951a62cbdedb/kirimaru-core/src/test/java/kirimaru/biz/domain/AnnotationMockTests.java
終わりに
正直なところ、類似記事でも同様の紹介自体はしているので、そちらを読めば理解や推測もできる記事ではあります。
ただ、部分モックのやり方、本物メソッドの呼び方等々に着目したタイトルではないため、あらためて記事にしました。前回書いていなかったアノテーションでのモック方法等々も追記したので、少しだけ進歩があると自分の中で信じることにします。