SpringBoot2.2でJUnit5がデフォルトになったー。
他の更新はリリースノート見てくださいまし。 ちなみに私に関係ありそうなのはツイートした。触れてないのは単に使ってないってだけで、重要じゃないってわけじゃないです。
- Spring 5.1 -> 5.2
— いろふ (@irof) October 16, 2019
- Jakarta EEに移行しはじめた
- JUnit 5をデフォルトに
- HealthIndicatorはCompositeHealthContributorConfigurationに変えれ(長い……
- Java 13サポート(8と11は引き続き)
- RestTemplateBuilderのヘッダ用メソッド追加
……あたりかな。あと起動時間とメモリ改善とか。
build.gradle
の書き換え
SpringBoot2.1以前
implementation platform('org.springframework.boot:spring-boot-dependencies:2.1.6.RELEASE') testImplementation("org.springframework.boot:spring-boot-starter-test") { exclude(group: 'junit') } testImplementation platform("org.junit:junit-bom:5.4.2") testImplementation("org.junit.jupiter:junit-jupiter-api") testImplementation("org.junit.jupiter:junit-jupiter-params") testRuntimeClasspath("org.junit.platform:junit-platform-launcher") testRuntimeClasspath("org.junit.jupiter:junit-jupiter-engine")
まず junit
の除外。
入ってても実行時の悪さはしないんだけど @Test
使うときとかにJUnit4のが補完ででてきたりすると邪魔だし、うっかり使ったりしてても困るのでやっている人は多いと思います。
で、JUnit5を使うために諸々追加。
junit-bom
は使わなくても spring-boot-dependencies
で定義されてるんだけど、そっちで入る 5.3.2
じゃなく 5.4.2
を使いたかったから。
あとはSpringBoot使っててもSpringBootTestを使わない場合とかもあるんで、このセットで入れることはままあります。
SpringBoot2.2以降
implementation platform('org.springframework.boot:spring-boot-dependencies:2.2.0.RELEASE') testImplementation("org.springframework.boot:spring-boot-starter-test") { exclude(group: 'org.junit.vintage') }
シンプル。 SpringBootよりも新しいJUnit5を使いたくなったらまた記述は増えるんだろうけど、そこまで最新にこだわらないのなら勝手に入るのに任せてもいいと思います。
でもJUnit4は要らないから org.junit.vintage
は除外する。
おまけの話(こっちが本編)
単にバージョンだけあげると
こんな警告でてきます。
10月 27, 2019 4:06:30 午後 org.junit.platform.launcher.core.DefaultLauncher handleThrowable 警告: TestEngine with ID 'junit-vintage' failed to discover tests java.lang.NoClassDefFoundError: junit/runner/Version at org.junit.vintage.engine.JUnit4VersionCheck.checkSupported(JUnit4VersionCheck.java:32) at org.junit.vintage.engine.VintageTestEngine.discover(VintageTestEngine.java:61) at org.junit.platform.launcher.core.DefaultLauncher.discoverEngineRoot(DefaultLauncher.java:177) at org.junit.platform.launcher.core.DefaultLauncher.discoverRoot(DefaultLauncher.java:164) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128) at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:69) at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70) Caused by: java.lang.ClassNotFoundException: junit.runner.Version at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583) at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521) ... 9 more
警告がでるのはexclude(group: 'junit')
を指定している場合で、junit-vintage-engine
経由で入るはずの junit:junit
が入らないから。なんだ自業自得じゃん。警告なんで無視してても動きはします。
警告って難しくて、それ単体なら無理に対応しなくてもいいんだけど、出続けると警告が出てることに慣れてしまうので、逐次潰していかないと他の警告も見なくなってしまう。これは人間だから仕方ないと思います。でもきっちり対応しようって思うとそこそこかかるんですよね。悩ましい。
正しい(?)対応は以下の通り。
exclude(group: 'junit')
を削除exclude(group: 'org.junit.vintage')
を追加- 明示的に追加してた
junit-jupiter
たちを削除(これは方針次第)
そこそこかかった対応
警告に出てる例外を出しているのは junit-vintage-engine
の JUnit4VersionCheck
で、自分が動こうにもクラスパスに junit.runner.Version
がない。だから例外を投げる…… junit-vintage-engine
としては正しいかな。
警告ログを出しているのは junit-platform-launcher
の DefaultLauncher
で、例外を受けてログ出して処理続行。
そうしてるのは知ってるTestEngineをループしながら「実行できる?」って聞いてってるから。 TestEngine
は ServiceLoader
でクラスパスにあるのを拾ってきたり、設定で追加されたりされるもの。どんな TestEngine
入ってくるかは実行時任せだから、一つ実行できないのがあったからって止めるのは無しなんでしょう。
状況から VintageEngine
が ServiceLoader
に拾われていることがわかった。で、使う気のない VintageEngine
を追加してるのが誰かを gradle dependencies
で見たら spring-boot-starter-test
だった。
この辺で「あーね」となって上の対応になりました。
こう言うのを秒で対応できるようになりたい。
あと build.gradle.kts
に乗り換えようとしてるんだけど、なかなか捗らない。