Spring Boot 2.0.x の Web アプリを 2.1.x へバージョンアップする ( その5 )( テストが大量に失敗する原因を解消する2 )
概要
記事一覧はこちらです。
Spring Boot 2.0.x の Web アプリを 2.1.x へバージョンアップする ( その4 )( テストが大量に失敗する原因を解消する ) の続きです。
- 今回の手順で確認できるのは以下の内容です。
ksbysample.webapp.lending.SampleHelperTest$異常処理のテスト.SampleHelper_encryptを呼ぶとRuntimeExceptionをthrowする
テストメソッドだけ gradle の build タスクから実行された時には成功するのに IntelliJ IDEA の「Run ‘All Tests’」から実行された時には失敗するので、その原因を調査します。
参照したサイト・書籍
- Difference between AppClassloader and SystemClassloader
https://stackoverflow.com/questions/34650568/difference-between-appclassloader-and-systemclassloader
目次
- gradle の build タスクから実行された時には成功するが IntelliJ IDEA の「Run ‘All Tests’」から実行された時に失敗する原因とは?
- Spring Boot 2.0.8 に切り戻して確認してみる
- Spring Boot 2.1.2 に切り替えて「JUnit」の「Shorten command line」の設定を「JAR manifest」にして確認する
手順
gradle の build タスクから実行された時には成功するが IntelliJ IDEA の「Run ‘All Tests’」から実行された時に失敗する原因とは?
まずは状況をまとめてみます。失敗する ksbysample.webapp.lending.SampleHelperTest$異常処理のテスト.SampleHelper_encryptを呼ぶとRuntimeExceptionをthrowする
テストメソッドは以下の実装になっており、
- ksbysample.webapp.lending.SampleHelperTest テストクラスは groovy で書かれている。
- SampleHelperTest クラスの中に Spock で書かれたテストクラス「正常処理のテスト」と JUnit4 で書かれたテストクラス「異常処理のテスト」が混在している。SampleHelperTest クラスには @RunWith(Enclosed) アノテーションが付与されている。
- JUnit4 で書かれたテストクラス「異常処理のテスト」は PowerMock を使用して static メソッドのテストをしている。
エラーメッセージ Caused by: java.lang.NullPointerException at org.thymeleaf.spring5.util.SpringVersionUtils.<clinit>(SpringVersionUtils.java:52)
からエラーの発生箇所を確認すると、以下の赤枠の部分で NullPointerException が発生しています。
赤枠の行に breakpoint を設定してテストを debug 実行してみると、
breakpoint で処理が止まり、Debug Tool Window の Variables に「SpringVersion.class」と「SpringVersion.class.getPackage()」を表示させてみると以下の結果でした。
- SpringVersion.class はインスタンスが生成されている。classLoader は JavassitMockClassLoader で、parent が Launcher$AppClassLoader。
- SpringVersion.class.getPackage() は null だったので、SpringVersion.class.getPackage().getName() を呼べば NullPointerException が発生する。
今度は breakpoint はそのままで、gradle の build タスクを debug 実行してみます(Gradle Tool Window に表示されている build タスクでコンテキストメニューを表示して「Debug ...」メニューを選択します)。
普段は表示されない Connected to the target VM, address: '127.0.0.1:56365', transport: 'socket'
や Connected to the VM started by ':test' (localhost:56488). Open the debugger session tab
のメッセージが表示されて test タスクが実行された後、
breakpoint で処理が止まるので、Debug Tool Window の Variables に「SpringVersion.class」と「SpringVersion.class.getPackage()」を表示させてみると以下の結果でした。
- SpringVersion.class はインスタンスが生成されている。classLoader は Launcher$AppClassLoader。
- SpringVersion.class.getPackage() は null ではなく package 名が返ってきている。
「Run ‘All Tests’」からテストを実行した時は org.thymeleaf.spring5.util.SpringVersionUtils の classLoader が JavassitMockClassLoader(おそらく https://github.com/powermock/powermock/blob/release/2.x/powermock-core/src/main/java/org/powermock/core/classloader/javassist/JavassistMockClassLoader.java)になっていてい Mock 化されており SpringVersion.class.getPackage() が null を返すため、ということでしょうか。。。?
Spring Boot 2.0.8 に切り戻して確認してみる
Spring Boot のバージョンを 2.1.2 に上げる前は ksbysample.webapp.lending.SampleHelperTest$異常処理のテスト.SampleHelper_encryptを呼ぶとRuntimeExceptionをthrowする
テストメソッドは成功していたはずなので、一旦 master ブランチに切り替えて確認してみます。
master ブランチに切り替えてから Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新した後、テストを実行すると 2.1.2 にバージョンアップした後と同じ理由で失敗しました。
以前は成功していたはずなのになぜ?。。。と思ったのですが、よく考えたら Spring Boot 2.0.x の Web アプリを 2.1.x へバージョンアップする ( その4 )( テストが大量に失敗する原因を解消する ) の時に「Run/Debug Configurations」の画面で「JUnit」の「Shorten command line」の設定を「classpath file」に変更していたので、それが原因かもしれません。元の「user-local default: none」の設定に戻してみます。
再度テストを実行すると今度は成功しました。どうも「classpath file」の設定だと PowerMock を使用したテストで失敗することがあるという結論のようです。
ただし「user-local default: none」の設定でテストが成功することが分かっても、この設定では Spring Boot を 2.1.2 に上げた時に Command line is too long.
のメッセージが表示されてテストが実行できません。「Shorten command line」の設定には「JAR manifest」もあるので、そちらに設定を変更して試してみます。
テストを実行すると成功しました。
ということで ksbysample.webapp.lending.SampleHelperTest$異常処理のテスト.SampleHelper_encryptを呼ぶとRuntimeExceptionをthrowする
テストメソッドが失敗したのは「Run/Debug Configurations」の画面で「JUnit」の「Shorten command line」の設定を「classpath file」にしたからという結論でした。「JAR manifest」にすると成功するので、今度はこの設定で Spring Boot 2.1.2 に上げた状態に切り替えて試してみます。
Spring Boot 2.1.2 に切り替えて「JUnit」の「Shorten command line」の設定を「JAR manifest」にして確認する
Spring Boot 2.1.2 へのバージョンアップの作業をしているブランチに切り替えてから Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新した後、テストを実行してみると今度は成功しました。
Project Tool Window の src/test から「Run ‘All Tests’」を実行すると今度は全てのテストが成功しました!
「Shorten command line」の設定は「classpath file」の方が良さそうに思えたのですが「JAR manifest」の方が良かったようです。ただし PowerMock のテストでしかエラーになっていないので、普通はどちらでも良いのかもしれません。
履歴
2019/02/14
初版発行。