Mockitoがstaticメソッドのモックに対応したので試してみた
いつの間にかMockitoがstaticメソッドのモックに対応したので試してみました。
概要
以前のMockitoはstaticなメソッドのモックに対応しておらずPowerMock
を使ったりする必要がありましたが、Mockitoの3.4.0
からstaticメソッドのモックに対応したらしいです。
依存への追加
3.4.0
以降のMockitoを追加すればOKです。
testImplementation 'org.mockito:mockito-core:3.4.5'
testImplementation 'org.mockito:mockito-inline:3.4.5'
ただしmockito-core
だけではなくmockito-inline
も依存に追加する必要があります。
使うクラスはmockito-core
で定義されているのですが実行するのにmockito-inline
も必要らしくmockito-inline
無しで実行するとエラーになります。
mockito-inline
自体の依存にmockito-core
が含まれるので本来であればmockito-inline
のみでも大丈夫なのですが、SpringのアプリケーションでSpringのBOMとか読み込んでいる場合はそちらに記述されているバージョンが優先されてmockito-core
だけ低いバージョンになったりするので注意が必要です。
実装例
Instant.now()
をモックにして任意の時刻を返すようにした例です。
@Test
public void mockTest() throws Exception {
var ret = Instant.ofEpochSecond(0);
var mocked = Mockito.mockStatic(Instant.class);
mocked.when(Instant::now).thenReturn(ret);
var actual = Instant.now();
assertEquals(actual.toString(), "1970-01-01T00:00:00Z"); // OK
mocked.verify(Instant::now);
mocked.close();
}
まずMockito.mockStatic()
にモックにしたいstaticメソッドがあるクラスを指定してモックコントローラを受け取ります。
あとはモックコントローラを使ってmocked.when(...).thenReturn(...)
みたいな感じでいつものノリで設定すればOKです。
一点だけ注意が必要で最後にclose()
のメソッドを呼ぶ必要があるらしく、忘れて別のテストケースで再度モックにしようとするとエラーになります。
For java.time.Instant, static mocking is already registered in the current thread
To create a new mock, the existing static mock registration must be deregistered
org.mockito.exceptions.base.MockitoException:
For java.time.Instant, static mocking is already registered in the current thread
...
公式ドキュメントを見た感じだと try-with-resources で書くのがオススメらしくモックが適応される範囲が限定できて最後に自動でclose()
も呼んでくれるので良いみたいです。
try (var mocked = Mockito.mockStatic(Instant.class)) {
// 中だけモックが有効
}