経緯
mockito使って、staticメソッドを使っている箇所をモック化したのだが、他のstaticメソッドを呼んだら、nullが帰ってきた。
実装は、nullが返ってくることはないはずなんだが、なぜか帰ってきていて、悩んだので、メモ。
原因
簡単に言うと、モック化することで、他のstaticメソッドもモック化されて、nullが返ってきていた。
自分がモック化したのは、下記のコード
MockedStatic<LocalDate> mock = Mockito.mockStatic(LocalDate.class); mock.when(LocalDate::now).thenReturn(testDate);
上のやつだと、たしかにnow()は、用意したテストデータ返してくれるけど、他のstaticメソッドを呼んだときに、nullを返す。
内部の実装追ってないけど、おそらく、ラッピングしたやつが設定されて、他のstaticメソッドは、から実装(null返すだけ)になってるんじゃないかと思う。
対処
mockStaticの第二引数に、Mockito.CALLS_REAL_METHODSを設定する。
原因のところに書いたソースを直すと、以下の感じになる。
MockedStatic<LocalDate> mock = Mockito.mockStatic(LocalDate.class, Mockito.CALLS_REAL_METHODS); mock.when(LocalDate::now).thenReturn(testDate);
第二引数に、Mockito.CALLS_REAL_METHODSを設定することで、モック化前の実装が呼び出されるらしい。
で、うまく動いたのだが、まだ罠があることをこのときの俺は知らなかった。。。
トラップ発動
テストケースうまく動いたから、テストケース全体を動かしたら、なぜかエラーに。。。
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-resourse使って閉じるのがいいらしい。
try (MockedStatic<LocalDate> mock = Mockito.mockStatic(LocalDate.class, Mockito.CALLS_REAL_METHODS)) { // テストの実装 }
モックの有効範囲も明確化するので、俺もtry-with-resourseで自動クローズさせるのが良いと思いました。
雑記
トラップ発動がウザすぎる。。。
解決したと思って、全テストケース回してコケたときの絶望感が半端なかった。
神は俺に試練与えるの好きすぎだろ。
絶対にサディストだ。
特に、トイレが確保できないところでの便意は、まじで辞めて欲しい。
最近、リモート作業しないことが増えてきて、たまに電車のなかで便意が発動するのが、そうとう厄介。
参考サイト
https://nainaistar.hatenablog.com/entry/2022/07/18/120000 https://kamoqq.info/post/mockito-static-method-mock/