概要
JUnitのテストケースで、staticメソッドで呼ばれたときにmockito使って例外投げるようにしたが、なぜか意図した箇所のカバレッジが埋まらないが、チェックは正しいような動きをしていて、悩んでいたので、メモ。
環境情報
Gradleから抜粋
- 'org.junit.jupiter:junit-jupiter:5.8.1'
- sourceCompatibility = JavaVersion.VERSION_17
- targetCompatibility = JavaVersion.VERSION_17
- 'org.mockito:mockito-inline:4.5.1'
詳しく見たい人はgithubのブランチからbuild.gradle見て
詳細レポート
発生日
2024/02/23
バグ概要
テストケースと対象ソースは以下の通り。
テストソース
@Test void testTellMe_InterruptedException() throws IOException, InterruptedException { HttpClient mockClient = Mockito.mock(HttpClient.class); HttpResponse responseMock = Mockito.mock(HttpResponse.class); try (MockedStatic<HttpClient> mocked = mockStatic(HttpClient.class)) { mocked.when(HttpClient::newHttpClient).thenThrow(new IOException()); GeminiResponseDto result = geminiService.tellMe("text"); Assertions.fail(); } catch (InterruptedException e) { // 正常 } catch (Exception e) { Assertions.fail(); } }
テスト対象箇所
public GeminiResponseDto tellMe(String text) throws InterruptedException { GeminiRequestDto dto = create(text); try { HttpClient client = HttpClient.newHttpClient(); // 省略 } catch (RuntimeException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } }
詳細
テスト実施時、newHttpClientが呼び出されたら例外が発生してcatch句に行って欲しいのだが、そもそもテストソース(tellMe)まで到達してなくて、何がおかしいのかずっと悩んでた
テストケースも正常終了するし、なぜ??って感じだった。
解決
問題は単純で、newHttpClientは、throws句がなく、IOExceptionが発生しないため、mockitoでバインドさせたときに、"そんなことできませんぜ?旦那"って言われていた。
例外出してくれればいいものの、特にテストが異常終了しなくて、かなり悩んだ。
ちゃんと例外発生させるところで例外をthrowするようにモックを定義してやることで、問題は解消できた。
感想・反省
ちゃんとメソッド定義を見ていれば一発で解消できたのに。。。
該当箇所までモック化するのがめんどくさかったから、適当に例外発生させればいいだろうの考えのもと、適当にモックを作ったのが問題だった。
モック化でもメソッド定義の壁は超えられないんだな。。。
万能だと思っていたが、そうではないらしい。
補足例外だったのが、今回の敗因だった。
非補足例外だったら、たぶん、問題にはならなかったと思う。
今後の対策
楽をしようとしすぎて、逆にどツボにハマるパターンだった。
楽をするなら、適用できるのかちゃんと見ておけば良かった。
怠け癖、テキトー癖は否定しないが、逆に問題を引き起こす可能性があることをちゃんと認識できる能力がないと、そういう癖は持つべきではないなと思った。
まぁ、解決したからいいけど。
メソッドの定義を超過したモック化はしないように注意しなければ。
補足情報
自分が開発しているやつ