Spring Boot + npm + Geb で入力フォームを作ってテストする ( その102 )( SpotBugs を 4.0.2 → 4.4.1 へ、PMD を 6.23.0 → 6.39.0 へ、error-prone を 2.3.4 → 2.9.0 へバージョンアップする )
概要
記事一覧はこちらです。
- 今回の手順で確認できるのは以下の内容です。
- SpotBugs を 4.0.2 → 4.4.1 へ、PMD を 6.23.0 → 6.39.0 へ、error-prone を 2.3.4 → 2.9.0 へバージョンアップします。
- Checkstyle は今回はバージョンアップしません。JDK 17 へバージョンアップした時にエラーが出なかったのと、Record の設定が反映された https://github.com/ksby/ksbysample-webapp-lending/blob/master/config/checkstyle/google_checks.xml のファイルをコピーしたいためです。JDK 17 バージョンアップ後にバージョンアップします。
参照したサイト・書籍
目次
- SpotBugs を 4.0.2 → 4.4.1 へバージョンアップする
- PMD を 6.23.0 → 6.39.0 へバージョンアップする
- error-prone を 2.3.4 → 2.9.0 へバージョンアップする
手順
SpotBugs を 4.0.2 → 4.4.1 へバージョンアップする
build.gradle の以下の点を変更します。
plugins { .......... id "com.github.spotbugs" version "4.7.7" .......... } .......... spotbugs { toolVersion = "${spotbugs.toolVersion.get()}" ignoreFailures = true spotbugsTest.enabled = false excludeFilter = file("${rootProject.projectDir}/config/spotbugs/exclude.xml") } spotbugsMain { reports { html { enabled = true } } } .......... dependencies { .......... // for SpotBugs spotbugs(configurations.spotbugsPlugins.dependencies) annotationProcessor("com.github.spotbugs:spotbugs-annotations:${spotbugs.toolVersion.get()}") spotbugsPlugins("com.h3xstream.findsecbugs:findsecbugs-plugin:1.11.0") .......... }
- plugins block の以下の点を変更します。
id "com.github.spotbugs" version "4.0.8"
→id "com.github.spotbugs" version "4.7.7"
- プラグインのバージョンを 4.7.7 にすることで SpotBugs のバージョンが 4.4.1 になります。SpotBugs version mapping 参照。
- spotbugs block の以下の点を変更します。
toolVersion = "4.0.2"
→toolVersion = "${spotbugs.toolVersion.get()}"
excludeFilter = file("${rootProject.projectDir}/config/spotbugs/exclude.xml")
を追加します。
- spotbugsMain block の以下の点を変更します。
stylesheet = "color.xsl"
を削除します。
- dependencies block の以下の点を変更します。
def spotbugsVersion = "4.0.2"
を削除します。- 以下の行を削除します。
compileOnly("com.github.spotbugs:spotbugs:${spotbugsVersion}") { exclude group: "pull-parser", module: "pull-parser" }
compileOnly("net.jcip:jcip-annotations:1.0")
compileOnly("com.github.spotbugs:spotbugs-annotations:${spotbugsVersion}")
testImplementation("com.google.code.findbugs:jsr305:3.0.2")
spotbugsStylesheets("com.github.spotbugs:spotbugs:${spotbugsVersion}")
- 以下の行を追加します。
spotbugs(configurations.spotbugsPlugins.dependencies)
compileOnly("com.github.spotbugs:spotbugs-annotations:${spotbugs.toolVersion.get()}")
spotbugsPlugins("com.h3xstream.findsecbugs:findsecbugs-plugin:1.10.1")
→spotbugsPlugins("com.h3xstream.findsecbugs:findsecbugs-plugin:1.11.0")
config ディレクトリの下に spotbugs ディレクトリを新規作成し、https://github.com/ksby/ksbysample-webapp-lending/blob/master/config/spotbugs/exclude.xml をコピーします。
Gradle Tool Window の左上にある「Reload All Gradle Projects」ボタンをクリックして更新します。
clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると "BUILD SUCCESSFUL" のメッセージが出力されました。
PMD を 6.23.0 → 6.39.0 へバージョンアップする
build.gradle の以下の点を変更します。
pmd { toolVersion = "6.39.0" sourceSets = [project.sourceSets.main] ignoreFailures = true consoleOutput = true ruleSetFiles = rootProject.files("/config/pmd/pmd-project-rulesets.xml") ruleSets = [] }
toolVersion = "6.23.0"
→toolVersion = "6.39.0"
に変更します。
Gradle Tool Window の左上にある「Reload All Gradle Projects」ボタンをクリックして更新します。
clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると PMD で警告が出ました。
レポートファイルを開くと警告は全部で 3種類、7箇所でした。
Logger calls should be surrounded by log level guards.
は https://ksby.hatenablog.com/entry/2021/09/03/211111#2-1 で対応したように config/pmd/pmd-project-rulesets.xml に設定を追加して、trace, debug のログ出力だけこのチェックが実行されるようにします。
<rule ref="category/java/bestpractices.xml"> <!-- CommentRequired はここでは exclude し、下で別途定義する --> <exclude name="GuardLogStatement"/> </rule> <rule ref="category/java/bestpractices.xml/GuardLogStatement"> <properties> <property name="logLevels" value="trace,debug"/> <property name="guardsMethods" value="isTraceEnabled,isDebugEnabled"/> </properties> </rule>
The initializer for variable 'selectOptions' is never used (overwritten on lines 22 and 24)
は SelectOptions selectOptions = null;
→ SelectOptions selectOptions;
に変更します。
SelectOptions selectOptions; if (countFlg) { selectOptions = SelectOptions.get().offset(offset).limit(limit).count(); } else { selectOptions = SelectOptions.get().offset(offset).limit(limit); }
The method 'checkTelAndEmail(boolean, String, String, String, String, Errors)' has a cognitive complexity of 20, current threshold is 15
は InquiryInput02FormValidator#checkTelAndEmail のメソッドが複雑なので警告が出ているのですが、今回はメソッドに @SuppressWarnings("PMD.CognitiveComplexity") を付与して警告が出ないようにします。
clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると無事 "BUILD SUCCESSFUL" のメッセージが出力されました。
error-prone を 2.3.4 → 2.9.0 へバージョンアップする
build.gradle の以下の点を変更します。
plugins { .......... id "net.ltgt.errorprone" version "2.0.2" .......... } .......... dependencies { .......... def errorproneVersion = "2.9.0" .......... // for Error Prone ( http://errorprone.info/ ) errorprone("com.google.errorprone:error_prone_core:${errorproneVersion}") compileOnly("com.google.errorprone:error_prone_annotations:${errorproneVersion}")
- plugins block の以下の点を変更します。
id "net.ltgt.errorprone" version "1.1.1"
→id "net.ltgt.errorprone" version "2.0.2"
- dependencies block の以下の点を変更します。
def errorproneVersion = "2.3.4"
→def errorproneVersion = "2.9.0"
Gradle Tool Window の左上にある「Reload All Gradle Projects」ボタンをクリックして更新します。
clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると compileJava タスクで大量にエラーが出ました。1つずつ解消します。
https://errorprone.info/bugpattern/SameNameButDifferent は Lombok の @Slf4j、@Data アノテーションを付与している箇所で出力されていました。build.gradle を変更して出力されないようにします。https://ksby.hatenablog.com/entry/2021/03/03/210210#2-1 参照。
[compileJava, compileTestGroovy, compileTestJava]*.options*.encoding = "UTF-8" [compileJava, compileTestGroovy, compileTestJava]*.options*.compilerArgs = ["-Xlint:all,-options,-processing,-path"] tasks.withType(JavaCompile).configureEach { options.errorprone { disableWarningsInGeneratedCode = true disable("SameNameButDifferent") } }
disable("SameNameButDifferent")
を追加します。
https://google.github.io/styleguide/javaguide.html#s7.1.3-javadoc-block-tags は Javadoc で @throws、@return の説明文を記述していなかったのが原因でした。@throws、@return に説明文を追加します。https://ksby.hatenablog.com/entry/2020/08/20/002645#2-1 参照。
https://google.github.io/styleguide/javaguide.html#s7.2-summary-fragment は Javadoc に summary fragment がない箇所で出力されていました。summary fragment を記述します。What is a Javadoc summary fragment? 参照。
https://errorprone.info/bugpattern/ReturnValueIgnored は flatMap メソッドの戻り値を元のメソッドで使用していないことが原因でした。@SuppressWarnings("ReturnValueIgnored") を付与してエラーにならないようにします。https://ksby.hatenablog.com/entry/2021/09/04/205832#2-1 参照。
https://errorprone.info/bugpattern/InvalidInlineTag は Javadoc で {@Clob}
と記述していた箇所で出力されていました。{@link Clob}
のように修正します。
以上で error-prone が出力しているエラー・警告に対応したので再度 clean タスク実行 → Rebuild Project 実行 → build タスクを実行したところ、今度は PMD が 1種類、3箇所で警告を出力していました。
Comment is too large: Too many lines
は Javadoc の行数が 6行を超えていると出力されていました。https://github.com/ksby/ksbysample-webapp-lending/blob/master/config/pmd/pmd-project-rulesets.xml を見たところ、こちらでは <exclude name="CommentSize"/>
を記述してチェックしないようにしていたので、このファイルをコピーすることにします。
再度 clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると無事 "BUILD SUCCESSFUL" のメッセージが出力されました。
履歴
2021/10/14
初版発行。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その101 )( Spring Boot を 2.5.4 → 2.5.5 へバージョンアップするが、Eclipse Adoptium OpenJDK(Eclipse Temurin)を 11.0.12+7 → 17+35 へバージョンアップするのは一旦諦める )
概要
記事一覧はこちらです。
- 今回の手順で確認できるのは以下の内容です。
参照したサイト・書籍
目次
- Spring Boot を 2.5.4 → 2.5.5 へバージョンアップする
- Eclipse Adoptium OpenJDK(Eclipse Temurin) を 11.0.12+7 → 17+35 へバージョンアップする。。。のは一旦諦める
手順
Spring Boot を 2.5.4 → 2.5.5 へバージョンアップする
build.gradle の以下の点を変更します。
buildscript { ext { group "ksbysample" version "2.5.5" } repositories { mavenCentral() gradlePluginPortal() } dependencies { // for doma-codegen-plugin classpath "com.h2database:h2:1.4.200" } } plugins { id "java" id "groovy" id "eclipse" id "idea" id "org.springframework.boot" version "2.5.5" id "io.spring.dependency-management" version "1.0.11.RELEASE" id "net.ltgt.errorprone" version "1.1.1" id "checkstyle" id "com.github.spotbugs" version "4.0.8" id "pmd" id "com.github.node-gradle.node" version "3.1.1" id "com.gorylenko.gradle-git-properties" version "2.3.1" id "com.github.erdi.webdriver-binaries" version "2.6" id "org.seasar.doma.codegen" version "1.4.1" }
Spring Boot 2.5.5 へのバージョンアップとして以下の点を変更します。
- buildscript block の以下の点を変更します。
version "2.5.4"
→version "2.5.5"
- plugins block の以下の点を変更します。
id "org.springframework.boot" version "2.5.4"
→id "org.springframework.boot" version "2.5.5"
Gradle Tool Window の左上にある「Reload All Gradle Projects」ボタンをクリックして更新します。
clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると test タスクで大量にテストが失敗しました。
失敗したテストを確認すると、全てのテストで Caused by: org.xml.sax.SAXNotRecognizedException at Driver.java:178
が出力されてました。
InquiryMailHelperTest > 全ての項目に値がセットされている場合のテスト FAILED java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:132 Caused by: java.lang.IllegalStateException at LoggingApplicationListener.java:328 Caused by: java.lang.IllegalStateException at LogbackLoggingSystem.java:168 Caused by: ch.qos.logback.core.joran.spi.JoranException at SaxEventRecorder.java:89 Caused by: org.xml.sax.SAXNotRecognizedException at Driver.java:178
失敗しているテストを 1つ IntelliJ IDEA から実行すると同様に失敗して、
この時出力されているログを見ると以下の出力があり、
.......... 15:07:38,542 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback-test.xml] 15:07:38,542 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.groovy] 15:07:38,543 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Found resource [logback.xml] at [file:/D:/project-springboot/ksbysample-boot-miscellaneous/boot-npm-geb-sample/out/test/resources/logback.xml] 15:07:38,706 |-ERROR in ch.qos.logback.core.joran.event.SaxEventRecorder@44c79f32 - Parser configuration error occurred org.xml.sax.SAXNotRecognizedException: unrecognized feature http://xml.org/sax/features/external-general-entities ..........
out/test/resources/logback.xml に問題がある模様。ファイルを開いてみると以下の内容でした。
<?xml version="1.0" encoding="UTF-8"?> <configuration> <!-- Geb+Spock で Firefox を headless モードで動かした時に大量に以下の DEBUG ログ が出力されるのを抑制するために作成しているファイルである。ファイルがあればログを抑 制できるので、特に logger の定義は記述していない。 [Forwarding ... on session ... to remote] DEBUG org.apache.http --> </configuration>
実際のファイルは src/test/resources/logback.xml なので、このファイルを削除してみます。
再び clean タスク実行。。。してみましたが、out ディレクトリを削除してくれないことに気づきました。clean タスクで out ディレクトリと、ついでに src/main/generated、src/test/generated_tests ディレクトリを削除するよう build.gradle に設定を追加します。
bootRun { jvmArgs = jvmArgsForTask + [ "-Dspring.profiles.active=develop", "-XX:TieredStopAtLevel=1" ] } clean { doLast { rootProject.file("out").deleteDir() rootProject.file("src/main/generated").deleteDir() rootProject.file("src/test/generated_tests").deleteDir() } }
再度 clean タスク実行 → Rebuild Project 実行 → build タスクを実行してみましたが、test タスクで大量にテストが失敗する状況が変わりません。
src/test/resources/logback.xml を削除しましたが、関係ないようなので元に戻します。
Web でいろいろ検索してみるとなぜか珍しく自分の過去の記事の Spring Boot 2.2.x の Web アプリを 2.3.x へバージョンアップする ( その2 )( Spring Boot を 2.2.2 → 2.2.9 へ、Gradle を 6.0.1 → 6.5.1 へバージョンアップする ) がヒットしました。この時は org.xml.sax.SAXNotSupportedException: not supported setting property http://xml.org/sax/properties/lexical-handler
というエラーでしたが、SpotBugs の依存関係から pull-parser を削除して解決しています。
今回は Parser configuration error occurred org.xml.sax.SAXNotRecognizedException: unrecognized feature http://xml.org/sax/features/external-general-entities
というエラーが出て失敗していますが、同じ原因のような気がするので SpotBugs の依存関係から pull-parser を削除してみます。
build.gradle を以下のように変更します。
dependencies { .......... // for SpotBugs compileOnly("com.github.spotbugs:spotbugs:${spotbugsVersion}") { exclude group: "pull-parser", module: "pull-parser" } ..........
exclude group: "pull-parser", module: "pull-parser"
を追加します。
clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると "BUILD SUCCESSFUL" のメッセージが出力されました。
2.5.4 までは問題なかったのに 2.5.5 でエラーになったのかは謎です。。。
Eclipse Adoptium OpenJDK(Eclipse Temurin) を 11.0.12+7 → 17+35 へバージョンアップする。。。のは一旦諦める
Eclipse Adoptium OpenJDK(Eclipse Temurin)の 17+35 は Spring Boot 2.4.x の Web アプリを 2.5.x へバージョンアップする ( その13 )( Spring Boot を 2.5.4 → 2.5.5 へ、Eclipse Adoptium OpenJDK(Eclipse Temurin) を 11.0.12+7 → 17+35 へバージョンアップする ) でインストール済なので、プロジェクトで使用する JDK の設定を変更します。
IntelliJ IDEA のメインメニューから「File」-「Project Structure...」を選択し、「Project Structure」ダイアログが表示されたら「Project SDK」で「17+35」を選択して「OK」ボタンをクリックします。
メイン画面に戻ると画面右下に「Indexing...」の表示が出るので、終了するまで待ちます。
build.gradle の以下の点を変更します。
sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17
JavaVersion.VERSION_11
→JavaVersion.VERSION_17
に変更します。
Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。
clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると compileJava タスクが error-prone が原因でエラーになるので、一旦 build.gradle の error-prone の設定を全てコメントアウトします(後でバージョンアップして解消する予定)。
再度 clean タスク実行 → Rebuild Project 実行 → build タスクを実行しますが、今度は spotBugsMain タスクが大量にログを出力し、configureChromeDriverBinary タスクでエラーになりました。
SpotBugs や error-prone をバージョンアップしてから JDK 17 にバージョンアップした方が良さそうな気がしたので、今回は JDK 11 に切り戻すことにします。
切り戻してから clean タスク実行 → Rebuild Project 実行 → build タスクを実行して "BUILD SUCCESSFUL" のメッセージが出力されることを確認しておきます。
Spring Boot のバージョンアップや JDK 17 へのバージョンアップは難しくないイメージがあったのですが、今回は結構辛いです。。。 バージョンアップはこまめにやった方がいいな、というのが正直な感想です。
履歴
2021/10/12
初版発行。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その100 )( Gradle を 6.9.1 → 7.2 へ、Spring Boot を 2.4.10 → 2.5.4 へ、Geb を 4.1 → 5.0 へバージョンアップする2 )
概要
記事一覧はこちらです。
- 今回の手順で確認できるのは以下の内容です。
- 前回からの続きです。
参照したサイト・書籍
Difference between mockito-core vs mockito-inline
https://stackoverflow.com/questions/65986197/difference-between-mockito-core-vs-mockito-inlineMocking static methods (since 3.4.0)
https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#static_mocksmvc controller test with session attribute
https://stackoverflow.com/questions/26341400/mvc-controller-test-with-session-attribute
目次
- JUnit 4 の依存関係が残っているので削除する
- gebTest タスクが成功するか確認する
- powermock を利用しているテストを powermock なしで動作するよう変更する
- mockito-inline を依存関係に追加した後にテストが失敗する原因を調査する
apply(sharedHttpSession())
を呼び出して MockMvc の request 間で session 情報が自動で共有されるようにする- @Unroll アノテーションを削除する
手順
JUnit 4 の依存関係が残っているので削除する
gradlew dependencies
コマンドを実行して、出力結果から JUnit 4(junit:junit:4
) を検索すると以下の2つのモジュールでヒットしました。
org.springframework.boot:spring-boot-starter-web
com.icegreen:greenmail
+--- org.springframework.boot:spring-boot-starter-web -> 2.5.4 | .......... | +--- org.springframework.boot:spring-boot-starter-json:2.5.4 | | +--- org.springframework.boot:spring-boot-starter:2.5.4 (*) | | +--- org.springframework:spring-web:5.3.9 | | | +--- org.springframework:spring-beans:5.3.9 (*) | | | \--- org.springframework:spring-core:5.3.9 (*) | | +--- com.fasterxml.jackson.core:jackson-databind:2.12.4 | | | +--- com.fasterxml.jackson.core:jackson-annotations:2.12.4 | | | | \--- com.fasterxml.jackson:jackson-bom:2.12.4 | | | | +--- junit:junit:4.13.1 -> 4.13.2 (c) | | | | +--- com.fasterxml.jackson.core:jackson-annotations:2.12.4 (c) | | | | +--- com.fasterxml.jackson.core:jackson-core:2.12.4 (c) | | | | +--- com.fasterxml.jackson.core:jackson-databind:2.12.4 (c) | | | | +--- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.12.4 (c) | | | | +--- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.12.4 (c) | | | | \--- com.fasterxml.jackson.module:jackson-module-parameter-names:2.12.4 (c) | | | +--- com.fasterxml.jackson.core:jackson-core:2.12.4 | | | | \--- com.fasterxml.jackson:jackson-bom:2.12.4 (*) | | | \--- com.fasterxml.jackson:jackson-bom:2.12.4 (*) | | +--- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.12.4 | | | +--- com.fasterxml.jackson.core:jackson-core:2.12.4 (*) | | | +--- com.fasterxml.jackson.core:jackson-databind:2.12.4 (*) | | | \--- com.fasterxml.jackson:jackson-bom:2.12.4 (*) | | +--- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.12.4 | | | +--- com.fasterxml.jackson.core:jackson-annotations:2.12.4 (*) | | | +--- com.fasterxml.jackson.core:jackson-core:2.12.4 (*) | | | +--- com.fasterxml.jackson.core:jackson-databind:2.12.4 (*) | | | \--- com.fasterxml.jackson:jackson-bom:2.12.4 (*) | | \--- com.fasterxml.jackson.module:jackson-module-parameter-names:2.12.4 | | +--- com.fasterxml.jackson.core:jackson-core:2.12.4 (*) | | +--- com.fasterxml.jackson.core:jackson-databind:2.12.4 (*) | | \--- com.fasterxml.jackson:jackson-bom:2.12.4 (*) | .......... .......... +--- com.icegreen:greenmail:1.6.5 | +--- com.sun.mail:jakarta.mail:1.6.7 (*) | +--- org.slf4j:slf4j-api:1.7.32 | \--- junit:junit:4.13.2
build.gradle を変更します。
dependencies { .......... // dependency-management-plugin によりバージョン番号が自動で設定されるもの // Appendix F. Dependency versions ( https://docs.spring.io/spring-boot/docs/2.1.4.RELEASE/reference/html/appendix-dependency-versions.html ) 参照 implementation("org.springframework.boot:spring-boot-starter-web") { exclude group: "junit", module: "junit" } .......... // dependency-management-plugin によりバージョン番号が自動で設定されないもの、あるいは最新バージョンを指定したいもの .......... testImplementation("com.icegreen:greenmail:1.6.5") { exclude group: "junit", module: "junit" }
implementation("org.springframework.boot:spring-boot-starter-web")
とtestImplementation("com.icegreen:greenmail:1.6.5")
にexclude group: "junit", module: "junit"
を追加します。
Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。
再度 gradlew dependencies
コマンドを実行して JUnit 4 が依存関係から削除されていることを確認します。
clean タスク実行 → Rebuild Project を実行すると、ksbysample/webapp/bootnpmgeb/web/inquiry/form/InquiryInput02FormValidatorTest.groovy でエラーが発生しました。
エラーメッセージの箇所にジャンプすると @RunWith(Enclosed)
が使用されていました。テストが認識されていないのはこのファイルでした。
以下の点を変更します。
@RunWith(Enclosed)
を削除します。
clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると "BUILD SUCCESSFUL" のメッセージが出力されて、成功したテストの件数が 147 → 146 になりました。powermock を利用したテストを 1件コメントアウトしているので、これで全てのテストが認識されたことになります。
gebTest タスクが成功するか確認する
まず src/test/groovy/geb/gebspec/inquiry/InquiryTestSpec.groovy で MailServerResource が使用されていたので MailServerExtension に変更します。
class InquiryTestSpec extends GebSpec { MailServerExtension mailServerExtension = new MailServerExtension() Sql sql def setup() { mailServerExtension.start() // 外部プロセスから接続するので H2 TCP サーバへ接続する sql = Sql.newInstance("jdbc:h2:tcp://localhost:9092/mem:bootnpmgebdb", "sa", "") sql.execute("truncate table INQUIRY_DATA") } def cleanup() { mailServerExtension.stop() sql.close() }
- InquiryTestSpec クラスでは
@SringBootTest
アノテーションを付与していないため@Autowired
を付与しても意味がないので、@Rule
アノテーションを削除しMailServerResource mailServerResource = new MailServerResource()
→MailServerExtension mailServerExtension = new MailServerExtension()
に変更します。 - setup メソッド内に
mailServerExtension.start()
を追加します。 - cleanup メソッド内に
mailServerExtension.stop()
を追加します。 - テストクラス内の
mailServerResource.
→mailServerExtension.
に変更します。
gebTest タスクを実行すると、テストが 1件も実行されていません。。。
Geb のテストクラスに @Test
アノテーションは付与していないしテストが認識されない原因は何だろう?と思いつつ調査した結果、build.gradle に記述されている chromeTest、filrefoxTest タスクに useJUnitPlatform()
が記述されていないためでした。
build.gradle の task "${driver}Test"(type: Test) { ... }
内に useJUnitPlatform()
を追加します。
def drivers = ["chrome", "firefox"] drivers.each { driver -> task "${driver}Test"(type: Test) { // 前回実行時以降に何も更新されていなくても必ず実行する outputs.upToDateWhen { false } systemProperty "geb.env", driver exclude "ksbysample/**" // for JUnit 5 useJUnitPlatform() testLogging { afterSuite printTestCount } } } task gebTest { dependsOn drivers.collect { tasks["${it}Test"] } enabled = false }
gebTest タスクを実行すると全てのテストが実行されて成功しました。
powermock を利用しているテストを powermock なしで動作するよう変更する
src/test/groovy/ksbysample/webapp/bootnpmgeb/web/inquiry/form/InquiryInput02FormValidatorTest.groovy に記述している powermock を利用しているテストを、
@RunWith(PowerMockRunner) @PowerMockRunnerDelegate(SpringRunner) @SpringBootTest @PrepareForTest(EmailValidator) @PowerMockIgnore(["javax.management.*", "com.sun.org.apache.xerces.*", "javax.xml.*", "org.xml.*", "org.w3c.dom.*", "com.sun.org.apache.xalan.*"]) static class InquiryInput02FormValidator_メールアドレス { @Autowired private InquiryInput02FormValidator input02FormValidator Errors errors InquiryInput02Form inquiryInput02Form @Before void setup() { errors = TestHelper.createErrors() inquiryInput02Form = new InquiryInput02Form( zipcode1: "102" , zipcode2: "0072" , address: "東京都千代田区飯田橋1-1" , tel1: "" , tel2: "" , tel3: "" , email: "taro.tanaka@sample.co.jp") } @Test void "メールアドレスの Validation のテスト"() { when: "EmailValidator.validate が true を返すように設定してテストする" PowerMockito.mockStatic(EmailValidator) PowerMockito.when(EmailValidator.validate(Mockito.any())) thenReturn(true) input02FormValidator.validate(inquiryInput02Form, errors) then: "入力チェックエラーは発生しない" assert errors.hasErrors() == false assert errors.getAllErrors().size() == 0 // EmailValidator.validate が呼び出されていることをチェックする PowerMockito.verifyStatic(EmailValidator, Mockito.times(1)) EmailValidator.validate("taro.tanaka@sample.co.jp") and: "EmailValidator.validate が false を返すように設定してテストする" PowerMockito.when(EmailValidator.validate(Mockito.any())) thenReturn(false) input02FormValidator.validate(inquiryInput02Form, errors) then: "入力チェックエラーが発生する" assert errors.hasErrors() == true assert errors.getAllErrors().size() == 1 } }
以下のように変更します。
@Nested @SpringBootTest static class InquiryInput02FormValidator_メールアドレス { @Autowired private InquiryInput02FormValidator input02FormValidator Errors errors InquiryInput02Form inquiryInput02Form @BeforeEach void setup() { errors = TestHelper.createErrors() inquiryInput02Form = new InquiryInput02Form( zipcode1: "102" , zipcode2: "0072" , address: "東京都千代田区飯田橋1-1" , tel1: "" , tel2: "" , tel3: "" , email: "taro.tanaka@sample.co.jp") } @Test void "メールアドレスの Validation のテスト"() { when: "EmailValidator.validate が true を返すように設定してテストする" Mockito.mockStatic(EmailValidator) Mockito.when(EmailValidator.validate(Mockito.any())).thenReturn(true) input02FormValidator.validate(inquiryInput02Form, errors) then: "入力チェックエラーは発生しない" assert errors.hasErrors() == false assert errors.getAllErrors().size() == 0 // EmailValidator.validate が呼び出されていることをチェックする Mockito.verify(EmailValidator, Mockito.times(1)) EmailValidator.validate("taro.tanaka@sample.co.jp") and: "EmailValidator.validate が false を返すように設定してテストする" Mockito.when(EmailValidator.validate(Mockito.any())) thenReturn(false) input02FormValidator.validate(inquiryInput02Form, errors) then: "入力チェックエラーが発生する" assert errors.hasErrors() == true assert errors.getAllErrors().size() == 1 } }
Mockito で static method のテストを実装するには mockito-inline が必要なので、build.gradle の dependencies block に testImplementation("org.mockito:mockito-inline")
を追加します。
dependencies { .......... testImplementation("org.codehaus.groovy:groovy-sql") testImplementation("org.mockito:mockito-inline")
Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。
テスト単体で実行すると成功しました。
clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると、test タスクで今回変更したテスト以外のテストがなぜか失敗しました。。。
mockito-inline を依存関係に追加した後にテストが失敗する原因を調査する
エラーの原因を調べようとテストを IntelliJ IDEA から単体で実行してみると成功します。
mockito-inline を依存関係に追加したのが原因だろうと思い、依存関係から外して powermock を利用しているテストを powermock なしで動作するよう変更する で変更したテストもコメントアウトして build タスクを実行すると、テストは全て成功します。
mockito-inline を依存関係に追加し、コメントアウトしたテストも元に戻します。
コンソールに出力されているエラーメッセージだけでは詳細が分からないので build/reports/tests/test/index.html のレポートファイルを開いてみると、失敗した手テスト全てで Caused by: java.lang.IllegalArgumentException: セットされるはずのデータがセットされていません
のログが出力されていました。
上のログから該当箇所を確認してみると、mockito-inline が依存関係に追加されると mockMvc.perform(TestHelper.postForm("/inquiry/input/02?move=next", inquiryInput02Form_001).with(csrf()).session(session))
でデータを渡せなくなる(TestHelper.postForm メソッドでデータをセットできない?)ように見えるのですが、これだけでは解決の仕方が分かりません。
Web でいろいろ検索して調べたところ、以下の2つのページを見つけました。
Mockito.mockStatic メソッドを使用する場合には try-with-resources 構文を使うように書かれていますね。。。 まさか、Mockito.mockStatic 戻り値を変数に取っておいて close メソッドを呼び出す必要があるとは思いませんでした。
powermock を利用しているテストを powermock なしで動作するよう変更する で変更したテストを以下のように変更します。
@Test void "メールアドレスの Validation のテスト"() { given: MockedStatic mockedEmailValidator = Mockito.mockStatic(EmailValidator) when: "EmailValidator.validate が true を返すように設定してテストする" Mockito.when(EmailValidator.validate(Mockito.any())).thenReturn(true) input02FormValidator.validate(inquiryInput02Form, errors) then: "入力チェックエラーは発生しない" assert errors.hasErrors() == false assert errors.getAllErrors().size() == 0 // EmailValidator.validate が呼び出されていることをチェックする Mockito.verify(EmailValidator, Mockito.times(1)) EmailValidator.validate("taro.tanaka@sample.co.jp") and: "EmailValidator.validate が false を返すように設定してテストする" Mockito.when(EmailValidator.validate(Mockito.any())) thenReturn(false) input02FormValidator.validate(inquiryInput02Form, errors) then: "入力チェックエラーが発生する" assert errors.hasErrors() == true assert errors.getAllErrors().size() == 1 cleanup: mockedEmailValidator.close() }
- given block を追加して Mockito.mockStatic を呼び出している行をこの下に移動し、
Mockito.mockStatic(EmailValidator)
→MockedStatic mockedEmailValidator = Mockito.mockStatic(EmailValidator)
に変更します。 - cleanup block を追加し、
mockedEmailValidator.close()
を追加します。
clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると "BUILD SUCCESSFUL" のメッセージが出力されました。
apply(sharedHttpSession())
を呼び出して MockMvc の request 間で session 情報が自動で共有されるようにする
mockito-inline を依存関係に追加した後にテストが失敗する原因を調査する の調査をしていた時に mvc controller test with session attribute のページを見つけました。MockMvc のインスタンスを生成する時に apply(sharedHttpSession())
を呼び出せば session 情報が自動で共有されるようになるとのこと。
以下のような実装の場合、
@BeforeEach void setup() { mockMvc = MockMvcBuilders.webAppContextSetup(context) .apply(springSecurity()) .build() } @Test void "完了画面で「入力画面へ」ボタンをクリックして入力画面1へ戻ると入力していたデータがクリアされる"() { when: "入力画面1で項目全てに入力して「次へ」ボタンをクリックする" MvcResult result = mockMvc.perform(TestHelper.postForm("/inquiry/input/01?move=next", inquiryInput01Form_001).with(csrf())) .andExpect(status().isFound()) .andExpect(redirectedUrlPattern("**/inquiry/input/02")) .andReturn() MockHttpSession session = result.getRequest().getSession() and: "入力画面2で項目全てに入力して「次へ」ボタンをクリックする" mockMvc.perform(TestHelper.postForm("/inquiry/input/02?move=next", inquiryInput02Form_001).with(csrf()).session(session)) .andExpect(status().isFound()) .andExpect(redirectedUrlPattern("**/inquiry/input/03")) .......... }
以下のように変更します。
@BeforeEach void setup() { mockMvc = MockMvcBuilders.webAppContextSetup(context) .apply(springSecurity()) .apply(sharedHttpSession()) .build() } @Test void "完了画面で「入力画面へ」ボタンをクリックして入力画面1へ戻ると入力していたデータがクリアされる"() { when: "入力画面1で項目全てに入力して「次へ」ボタンをクリックする" mockMvc.perform(TestHelper.postForm("/inquiry/input/01?move=next", inquiryInput01Form_001).with(csrf())) .andExpect(status().isFound()) .andExpect(redirectedUrlPattern("**/inquiry/input/02")) and: "入力画面2で項目全てに入力して「次へ」ボタンをクリックする" mockMvc.perform(TestHelper.postForm("/inquiry/input/02?move=next", inquiryInput02Form_001).with(csrf())) .andExpect(status().isFound()) .andExpect(redirectedUrlPattern("**/inquiry/input/03")) .......... }
- MockMvcBuilders クラスで MockMvc のインスタンスを生成している処理に
.apply(sharedHttpSession())
を追加します。 - テストメソッド内で
MvcResult result =
と.andReturn()
を削除します。 MockHttpSession session = result.getRequest().getSession()
も削除します。- その下の
.session(session)
の部分を全て削除します。
clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると "BUILD SUCCESSFUL" のメッセージが出力されました。
ちなみに @AutoConfigureMockMvc アノテーションを付与して MockMvc のインスタンスを自動生成した場合、session 情報は共有されませんでした。apply(sharedHttpSession())
による session 情報共有の機能を利用したい場合には自分でインスタンスを生成する必要があります。
@Unroll アノテーションを削除する
Spock 2 から @Unroll アノテーションの記述が不要になったので、削除します。
削除後に clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると "BUILD SUCCESSFUL" のメッセージが出力されて、テスト数も削除前と同じ 147 でした。
履歴
2021/10/12
初版発行。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その99 )( Gradle を 6.9.1 → 7.2 へ、Spring Boot を 2.4.10 → 2.5.4 へ、Geb を 4.1 → 5.0 へバージョンアップする )
概要
記事一覧はこちらです。
- 今回の手順で確認できるのは以下の内容です。
- Gradle を 6.9.1 → 7.2 へバージョンアップします。
- Spring Boot を 2.4.10 → 2.5.4 へ、Geb を 4.1 → 5.0 へバージョンアップします。
- 今回だけでは完了しなかったので、2回に分けます。
参照したサイト・書籍
- erdi / webdriver-binaries-gradle-plugin
https://github.com/erdi/webdriver-binaries-gradle-plugin
目次
- Gradle を 6.9.1 → 7.2 へバージョンアップする
- Spring Boot を 2.4.10 → 2.5.4 へ、Geb を 4.1 → 5.0 へバージョンアップする。。。がエラーが出てバージョンアップできず
- configureChromeDriverBinary タスクでエラーになる原因を調査した結果、Gradle Plugin を com.energizedwork.webdriver-binaries → com.github.erdi.webdriver-binaries に切り替える
- test タスクで実行されるテストから src/test/groovy/geb/ の下のテストを除外する
- org.junit.Test アノテーションが付いているテストを org.junit.jupiter.api.Test アノテーションに変更する
- 続く。。。
手順
Gradle を 6.9.1 → 7.2 へバージョンアップする
build.gradle の wrapper タスクの記述を以下のように変更します。
wrapper {
gradleVersion = "7.2"
distributionType = Wrapper.DistributionType.ALL
}
gradleVersion = "6.9.1"
→gradleVersion = "7.2"
に変更します。
コマンドプロンプトから gradlew wrapper --gradle-version=7.2
、gradlew --version
コマンドを実行します。gradlew --stop
で Gradle Deamon を止めただけでは java.lang.IllegalArgumentException: Unsupported class file major version 61
のエラーメッセージが出たので、PC を再起動してからコマンドを実行しています。
gradle/wrapper/gradle-wrapper.properties は以下の内容になります。
distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists
Spring Boot 2.4.x の Web アプリを 2.5.x へバージョンアップする ( その4 )( Gradle を 6.9.1 → 7.2 へバージョンアップする ) で実施した変更内容を build.gradle に反映します。
tasks.named("compileTestJava").configure { options.errorprone.enabled = false } bootJar { duplicatesStrategy = DuplicatesStrategy.INCLUDE } jar { enabled = false } // for Doma 2 // Copy the resources referred by the Doma annotation processors to // the destinationDir of the compileJava task task copyDomaResources(type: Sync) { from sourceSets.main.resources.srcDirs into compileJava.destinationDirectory include "doma.compile.config" include "META-INF/**/*.sql" include "META-INF/**/*.script" } compileJava.dependsOn copyDomaResources
bootJar { duplicatesStrategy = DuplicatesStrategy.INCLUDE }
を追加します。jar { enabled = false }
を追加します。- copyDomaResources タスクの以下の点を変更します。
into compileJava.destinationDir
→into compileJava.destinationDirectory
Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。。。が、Could not find method testCompile()
のエラーメッセージが表示されました。
古い文法のままでした。。。 その下の testRuntime も testRuntimeOnly に変更されているので、build.gradle を以下のように変更します。
dependencies { .......... // for JUnit 5 // junit-jupiter で junit-jupiter-api, junit-jupiter-params, junit-jupiter-engine の3つが依存関係に追加される testImplementation("org.junit.jupiter:junit-jupiter") testRuntimeOnly("org.junit.platform:junit-platform-launcher") }
testCompile("org.junit.jupiter:junit-jupiter")
→testImplementation("org.junit.jupiter:junit-jupiter")
に変更します。testRuntime("org.junit.platform:junit-platform-launcher")
→testRuntimeOnly("org.junit.platform:junit-platform-launcher")
に変更します。
再度 Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新すると、今度は問題なく終了しました。
Spring Boot を 2.4.10 → 2.5.4 へ、Geb を 4.1 → 5.0 へバージョンアップする。。。がエラーが出てバージョンアップできず
build.gradle の以下の点を変更します。
buildscript { ext { group "ksbysample" version "2.5.4" } repositories { mavenCentral() gradlePluginPortal() } dependencies { // for doma-codegen-plugin classpath "com.h2database:h2:1.4.200" } } plugins { id "java" id "groovy" id "eclipse" id "idea" id "org.springframework.boot" version "2.5.4" id "io.spring.dependency-management" version "1.0.11.RELEASE" id "net.ltgt.errorprone" version "1.1.1" id "checkstyle" id "com.github.spotbugs" version "4.0.8" id "pmd" id "com.github.node-gradle.node" version "3.1.1" id "com.gorylenko.gradle-git-properties" version "2.3.1" id "com.energizedwork.webdriver-binaries" version "1.4" id "org.seasar.doma.codegen" version "1.4.1" } .......... dependencyManagement { imports { // mavenBom は以下の URL のものを使用する // https://repo.spring.io/release/org/springframework/boot/spring-boot-starter-parent/2.1.4.RELEASE/ // bomProperty に指定可能な property は以下の URL の BOM に記述がある // https://repo.spring.io/release/org/springframework/boot/spring-boot-dependencies/2.1.4.RELEASE/spring-boot-dependencies-2.1.4.RELEASE.pom mavenBom(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES) mavenBom("org.junit:junit-bom:5.8.1") } } dependencies { def spockVersion = "2.0-groovy-3.0" def lombokVersion = "1.18.20" def domaVersion = "2.49.0" def errorproneVersion = "2.3.4" def seleniumVersion = "3.141.59" def spotbugsVersion = "4.0.2" // dependency-management-plugin によりバージョン番号が自動で設定されるもの // Appendix F. Dependency versions ( https://docs.spring.io/spring-boot/docs/2.1.4.RELEASE/reference/html/appendix-dependency-versions.html ) 参照 implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springframework.boot:spring-boot-starter-validation") implementation("org.springframework.boot:spring-boot-starter-thymeleaf") implementation("org.springframework.boot:spring-boot-starter-data-jpa") implementation("org.springframework.boot:spring-boot-starter-freemarker") implementation("org.springframework.boot:spring-boot-starter-mail") implementation("org.springframework.boot:spring-boot-starter-security") implementation("org.springframework.boot:spring-boot-starter-actuator") runtimeOnly("org.springframework.boot:spring-boot-devtools") implementation("org.springframework.session:spring-session-core") implementation("org.springframework.session:spring-session-jdbc") implementation("org.codehaus.janino:janino") testImplementation("org.springframework.boot:spring-boot-starter-test") { exclude group: "org.junit.vintage", module: "junit-vintage-engine" } testImplementation("org.springframework.security:spring-security-test") testImplementation("org.yaml:snakeyaml") testImplementation("org.codehaus.groovy:groovy-sql") // dependency-management-plugin によりバージョン番号が自動で設定されないもの、あるいは最新バージョンを指定したいもの implementation("com.integralblue:log4jdbc-spring-boot-starter:2.0.0") implementation("org.flywaydb:flyway-core:7.14.1") implementation("com.h2database:h2:1.4.200") implementation("com.github.rozidan:modelmapper-spring-boot-starter:2.3.1") implementation("com.google.guava:guava:31.0.1-jre") implementation("org.apache.commons:commons-lang3:3.12.0") testImplementation("org.dbunit:dbunit:2.7.2") testImplementation("org.assertj:assertj-core:3.21.0") testImplementation("org.spockframework:spock-core:${spockVersion}") testImplementation("org.spockframework:spock-spring:${spockVersion}") testImplementation("org.jsoup:jsoup:1.14.3") testImplementation("com.icegreen:greenmail:1.6.5") // for lombok annotationProcessor("org.projectlombok:lombok:${lombokVersion}") compileOnly("org.projectlombok:lombok:${lombokVersion}") // for Doma implementation("org.seasar.doma:doma-core:${domaVersion}") annotationProcessor("org.seasar.doma:doma-processor:${domaVersion}") // for Error Prone ( http://errorprone.info/ ) errorprone("com.google.errorprone:error_prone_core:${errorproneVersion}") compileOnly("com.google.errorprone:error_prone_annotations:${errorproneVersion}") // PowerMock testImplementation("org.powermock:powermock-module-junit4:${powermockVersion}") testImplementation("org.powermock:powermock-api-mockito2:${powermockVersion}") // for Geb + Spock testImplementation("org.gebish:geb-spock:5.0") testImplementation("org.seleniumhq.selenium:selenium-chrome-driver:${seleniumVersion}") testImplementation("org.seleniumhq.selenium:selenium-firefox-driver:${seleniumVersion}") testImplementation("org.seleniumhq.selenium:selenium-support:${seleniumVersion}") // for SpotBugs compileOnly("com.github.spotbugs:spotbugs:${spotbugsVersion}") compileOnly("net.jcip:jcip-annotations:1.0") compileOnly("com.github.spotbugs:spotbugs-annotations:${spotbugsVersion}") testImplementation("com.google.code.findbugs:jsr305:3.0.2") spotbugsStylesheets("com.github.spotbugs:spotbugs:${spotbugsVersion}") spotbugsPlugins("com.h3xstream.findsecbugs:findsecbugs-plugin:1.10.1") // for JUnit 5 // junit-jupiter で junit-jupiter-api, junit-jupiter-params, junit-jupiter-engine の3つが依存関係に追加される testImplementation("org.junit.jupiter:junit-jupiter") testRuntimeOnly("org.junit.platform:junit-platform-launcher") } .......... bootRun { jvmArgs = jvmArgsForTask + [ "-Dspring.profiles.active=develop", "-XX:TieredStopAtLevel=1" ] } tasks.withType(Test) { jvmArgs = jvmArgsForTask + ["-Dspring.profiles.active=unittest"] } test { // test タスクの jvmArgs は tasks.withType(Test) { ... } で定義している // for JUnit 5 useJUnitPlatform() testLogging { afterSuite printTestCount } } ..........
Spring Boot 2.5.4 へのバージョンアップとして以下の点を変更します。
- buildscript block の以下の点を変更します。
version "2.4.10"
→version "2.5.4"
- plugins block の以下の点を変更します。
id "org.springframework.boot" version "2.4.10"
→id "org.springframework.boot" version "2.5.4"
- dependencyManagement block の以下の点を変更します。
mavenBom(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES) { bomProperty "groovy.version", "2.5.15" }
→mavenBom(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)
各種ライブラリのバージョンアップとして以下の点を変更します。
- dependencyManagement block の以下の点を変更します。
mavenBom("org.junit:junit-bom:5.7.2")
→mavenBom("org.junit:junit-bom:5.8.1")
- dependencies block の以下の点を変更します。
def spockVersion = "1.3-groovy-2.5"
→def spockVersion = "2.0-groovy-3.0"
testImplementation("org.codehaus.groovy:groovy-sql")
を追加します。testImplementation("org.gebish:geb-spock:4.1") { exclude group: "org.codehaus.groovy", module: "groovy-all" }
→testImplementation("org.gebish:geb-spock:5.0")
- https://gebish.org/manual/current/#installation-usage を見ると selenium-api、selenium-remote-driver の2つは必要ないようなので、以下の2行を削除します。
testImplementation("org.seleniumhq.selenium:selenium-api:${seleniumVersion}")
testImplementation("org.seleniumhq.selenium:selenium-remote-driver:${seleniumVersion}")
- powermock を依存関係から削除するため、以下の3行を削除します。
def powermockVersion = "2.0.7"
testImplementation("org.powermock:powermock-module-junit4:${powermockVersion}")
testImplementation("org.powermock:powermock-api-mockito2:${powermockVersion}")
def jvmArgsAddOpens = [ ... ]
を削除します。- テストが全て JUnit 5 ベースになるので、testJUnit4AndSpock タスクを削除します。
task testJUnit4AndSpock(type: Test) { ... }
test.dependsOn testJUnit4AndSpock
ksbysample/webapp/bootnpmgeb/web/inquiry/form/InquiryInput02FormValidatorTest.groovy に powermock を利用したテストが記述されていますが、このままでは build が通らないので対象のテストをコメントアウトします(後で実装し直します)。
Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。
clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると、configureChromeDriverBinary タスクでエラーになりました。。。
configureChromeDriverBinary タスクでエラーになる原因を調査した結果、Gradle Plugin を com.energizedwork.webdriver-binaries → com.github.erdi.webdriver-binaries に切り替える
gradlew configureChromeDriverBinary --stacktrace
コマンドを実行してみると Caused by: java.lang.NoSuchMethodError: 'void org.gradle.wrapper.PathAssembler.<init>(java.io.File)'
のエラーメッセージが出力されましたが、これでは原因がよく分かりません。
com.energizedwork.webdriver-binaries
で Google で検索したところ、erdi / webdriver-binaries-gradle-plugin のページにたどり着きました。新しい Gradle Plugin が出ているようなので、こちらに切り替えます。
plugins { .......... id "com.github.erdi.webdriver-binaries" version "2.6" .......... } .......... webdriverBinaries { chromedriver { version = "94.0.4606.41" architecture = "X86" fallbackTo32Bit = true } geckodriver { version = "0.29.1" architecture = "X86_64" } }
- plugins block の以下の点を変更します。
id "com.energizedwork.webdriver-binaries" version "1.4"
→id "com.github.erdi.webdriver-binaries" version "2.6"
- https://github.com/webdriverextensions/webdriverextensions-maven-plugin-repository/blob/master/repository-3.0.json を参照して webdriverBinaries block の記述を変更します。chromedriver は 32bit版しか存在しないので
fallbackTo32Bit = true
を付けるのが注意点です。
Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。
clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると、configureChromeDriverBinary タスクは正常終了しましたが test タスクでエラーが発生しました。
test タスクで実行されるテストから src/test/groovy/geb/ の下のテストを除外する
エラーになったテスト 13個は全て src/test/groovy/geb/gebspec/inquiry/InquiryTestSpec.groovy のテストでした。Spock、Geb がバージョンアップされたことに伴い JUnit 5 ベースのテストに変わったので、test タスクの実行対象になったことが原因です。Geb のテストを test タスクで実行する必要はないので除外します。
build.gradle の test タスクに exclude "geb/**"
を追加します。
test { // test タスクの jvmArgs は tasks.withType(Test) { ... } で定義している // Geb のテストを test タスクで実行されないようにする exclude "geb/**" // for JUnit 5 useJUnitPlatform() testLogging { afterSuite printTestCount } }
また src/test/groovy/geb/gebspec/inquiry/InquiryTestSpec.groovy を見て気づいたのですが、JUnit 4 のクラスである org.junit.Rule
の色がグレーになっていませんでした。build.gradle に記述されているモジュールの依存関係にまだ JUnit 4 が残っているようなので、後で JUnit 4 を依存関係から取り除くようにします。
clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると "BUILD SUCCESSFUL" のメッセージが出力されましたが、成功したテストの件数が 147 → 116 と大きく減っていました。おそらく org.junit.Test アノテーションが付いているテストがあって、JUnit 5 から認識されないことが原因でしょう。
org.junit.Test アノテーションが付いているテストを org.junit.jupiter.api.Test アノテーションに変更する
org.junit.Test で検索すると以下の2つのファイルがヒットしました。というより Spock ベースで作成していないテストが全て JUnit 4 ベースで実装されていました。。。
- src/test/groovy/ksbysample/webapp/bootnpmgeb/web/inquiry/InquiryCompleteControllerTest.groovy
- src/test/groovy/ksbysample/webapp/bootnpmgeb/web/inquiry/InquiryInputControllerTest.groovy
まず GreenMail の起動・停止に使用している src/test/java/ksbysample/common/test/rule/mail/MailServerResource.java が JUnit 4 の org.junit.rules.ExternalResource を継承して作成されているので、JUnit 5 でも動作するよう変更します。
src/test/java/ksbysample/common/test の下に extension.mail パッケージを作成した後、MailServerExtension.java を新規作成して以下の内容を記述します。最初 BeforeEachCallback, AfterEachCallback インターフェースを実装して自動で起動・停止させようと思ったのですが、Spock では @RegisterExtension
を付与しても自動起動・停止しなかったので止めました。
package ksbysample.common.test.extension.mail; import com.icegreen.greenmail.util.GreenMail; import com.icegreen.greenmail.util.ServerSetup; import org.springframework.stereotype.Component; import javax.mail.internet.MimeMessage; import java.util.Arrays; import java.util.List; @Component public class MailServerExtension { private GreenMail greenMail = new GreenMail(new ServerSetup(25, "localhost", ServerSetup.PROTOCOL_SMTP)); public void start() { greenMail.start(); } public void stop() { greenMail.stop(); } public int getMessagesCount() { return greenMail.getReceivedMessages().length; } public List<MimeMessage> getMessages() { return Arrays.asList(greenMail.getReceivedMessages()); } public MimeMessage getFirstMessage() { MimeMessage message = null; MimeMessage[] receivedMessages = greenMail.getReceivedMessages(); if (receivedMessages.length > 0) { message = receivedMessages[0]; } return message; } }
src/test/java/ksbysample/common/test/rule/mail/MailServerResource.java は削除します。
次に JUnit 4 ベースで作成されている2つのファイルを以下の内容で変更します。
import org.junit.Test
→import org.junit.jupiter.api.Test
に変更します。@RunWith(Enclosed)
を削除します。@RunWith(SpringRunner)
を削除します。- クラスの中にテストクラスを記述して階層構造にしている場合には、中のクラスに
@Nested
アノテーションを付与します。 - MailServerResource を MailServerExtension を使用するよう変更します。GreenMail のメールサーバの起動・停止は
@BeforeEach
、@AfterEach
アノテーションが付与されたメソッド内で行います。
@Rule public MailServerResource mailServerResource = new MailServerResource()
↓
@Autowired private MailServerExtension mailServerExtension @BeforeEach void setup() { mailServerExtension.start() .......... } @AfterEach void cleanup() { mailServerExtension.stop() }
@Before
→@BeforeEach
に変更します。
Spock ベースで実装している src/test/groovy/ksbysample/webapp/bootnpmgeb/web/inquiry/InquiryConfirmControllerTest.groovy も MailServerResource を使用していたので、以下の点を変更します。
@RunWith(Enclosed)
を削除します。- MailServerResource を MailServerExtension を使用するよう変更します。GreenMail のメールサーバの起動・停止は setup メソッド、cleanup メソッド内で行います。
@Rule
MailServerResource mailServerResource = new MailServerResource()
↓
@Autowired private MailServerExtension mailServerExtension def setup() { mailServerExtension.start() .......... } def cleanup() { mailServerExtension.stop() .......... }
- テストメソッド内の
mailServerResource.
→mailServerExtension.
に変更します。
clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると "BUILD SUCCESSFUL" のメッセージが出力されましたが、成功したテストの件数が 147 → 131 になりました。まだテストメソッドが認識されないものが残っているようです。
続く。。。
長くなったので、次回へ続きます。以下の内容を行う予定です。
- JUnit 4 の依存関係が残っているので削除する。
- テスト件数が減っている原因を調査・解消する。
- gebTest タスクが成功するか確認する。成功しない場合には、その原因を調査・解消する。
- powermock で実装されたテストを powermock なしで動作するよう変更する。
履歴
2021/10/10
初版発行。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その98 )( Gradle を 6.4 → 6.9.1 へ、Spring Boot を 2.2.7 → 2.4.10 へ、Geb を 3.4 → 4.1 へバージョンアップする )
概要
記事一覧はこちらです。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その97 )( webpack を 4.43.0 → 5.56.0 へバージョンアップする ) の続きです。
- 今回の手順で確認できるのは以下の内容です。
- Gradle を 6.4 → 6.9.1 へバージョンアップします。
- Spring Boot を 2.2.7 → 2.4.10 へ、Geb を 3.4 → 4.1 へバージョンアップします。
参照したサイト・書籍
Spring Boot 2.4.2 and Thymeleaf 3.0.12 - access static methods
https://stackoverflow.com/questions/66048129/spring-boot-2-4-2-and-thymeleaf-3-0-12-access-static-methods/66053568Improve restricted expression evaluation mode
https://github.com/thymeleaf/thymeleaf/issues/809
目次
- バージョンアップの進め方を決める
- Gradle を 6.4 → 6.9.1 へバージョンアップする
- Spring Boot を 2.2.7 → 2.4.10 へ、Geb を 3.4 → 4.1 へバージョンアップする
手順
バージョンアップの進め方を決める
以下の手順で進めます。
- JDK 11 のまま、Gradle を 6系最新へ、Spring Boot を 2.2.7 → 2.4.10 へ、Geb を 3.4 → 4.1 へバージョンアップする(Groovy は 2系のまま)。
- JDK 11 のまま、Gradle を 7系最新へ、Spring Boot を 2.4.10 → 2.5.4 へ、Geb を 4.1 → 5.0 へバージョンアップする(Groovy を 3系へ)。
- JDK 17 へ、Spring Boot を 2.5.4 → 2.5.5 へバージョンアップする。
Gradle を 6.4 → 6.9.1 へバージョンアップする
build.gradle の wrapper タスクの記述を以下のように変更します。
wrapper {
gradleVersion = "6.9.1"
distributionType = Wrapper.DistributionType.ALL
}
gradleVersion = "6.4"
→gradleVersion = "6.9.1"
に変更します。
コマンドプロンプトから gradlew wrapper --gradle-version=6.9.1
コマンドを実行します。。。が、java.lang.IllegalArgumentException: Unsupported class file major version 61
のエラーが出力されてバージョンアップできませんでした。
いろいろ試してみたところ、どうも 6.4 の Gradle Deamon が起動している時に gradlew wrapper --gradle-version=6.9.1
コマンドを実行すると、このエラーが出るような気がします。PC を再起動して Gradle Daemon が何も実行されていない状態にしてみます(後で知りましたが gradlew --stop
コマンドを実行すれば Gradle Daemon は停止できました)。
PC 再起動後、コマンドプロンプトから gradlew wrapper --gradle-version=6.9.1
、gradlew --version
コマンドを実行すると今度は正常に終了しました。
gradle/wrapper/gradle-wrapper.properties は以下の内容になります。
distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists
Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。
clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると "BUILD SUCCESSFUL" のメッセージが出力されました。
Spring Boot を 2.2.7 → 2.4.10 へ、Geb を 3.4 → 4.1 へバージョンアップする
build.gradle の以下の点を変更します。
buildscript { ext { group "ksbysample" version "2.4.10" } repositories { mavenCentral() gradlePluginPortal() } dependencies { // for doma-codegen-plugin classpath "com.h2database:h2:1.4.200" } } plugins { id "java" id "eclipse" id "idea" id "org.springframework.boot" version "2.4.10" id "io.spring.dependency-management" version "1.0.11.RELEASE" id "groovy" id "net.ltgt.errorprone" version "1.1.1" id "checkstyle" id "com.github.spotbugs" version "4.0.8" id "pmd" id "com.github.node-gradle.node" version "3.1.1" id "com.gorylenko.gradle-git-properties" version "2.3.1" id "com.energizedwork.webdriver-binaries" version "1.4" id "org.seasar.doma.codegen" version "1.4.1" } .......... dependencyManagement { imports { // mavenBom は以下の URL のものを使用する // https://repo.spring.io/release/org/springframework/boot/spring-boot-starter-parent/2.1.4.RELEASE/ // bomProperty に指定可能な property は以下の URL の BOM に記述がある // https://repo.spring.io/release/org/springframework/boot/spring-boot-dependencies/2.1.4.RELEASE/spring-boot-dependencies-2.1.4.RELEASE.pom mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES mavenBom("org.junit:junit-bom:5.7.2") } } dependencies { def spockVersion = "1.3-groovy-2.5" def domaVersion = "2.49.0" def lombokVersion = "1.18.22" def errorproneVersion = "2.3.4" def powermockVersion = "2.0.7" def seleniumVersion = "3.141.59" def spotbugsVersion = "4.0.2" // dependency-management-plugin によりバージョン番号が自動で設定されるもの // Appendix F. Dependency versions ( https://docs.spring.io/spring-boot/docs/2.1.4.RELEASE/reference/html/appendix-dependency-versions.html ) 参照 implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springframework.boot:spring-boot-starter-validation") implementation("org.springframework.boot:spring-boot-starter-thymeleaf") implementation("org.springframework.boot:spring-boot-starter-data-jpa") implementation("org.springframework.boot:spring-boot-starter-freemarker") implementation("org.springframework.boot:spring-boot-starter-mail") implementation("org.springframework.boot:spring-boot-starter-security") implementation("org.springframework.boot:spring-boot-starter-actuator") runtimeOnly("org.springframework.boot:spring-boot-devtools") implementation("org.springframework.session:spring-session-core") implementation("org.springframework.session:spring-session-jdbc") implementation("org.codehaus.janino:janino") testImplementation("org.springframework.boot:spring-boot-starter-test") { exclude group: "org.junit.vintage", module: "junit-vintage-engine" } testImplementation("org.springframework.security:spring-security-test") testImplementation("org.yaml:snakeyaml") // dependency-management-plugin によりバージョン番号が自動で設定されないもの、あるいは最新バージョンを指定したいもの implementation("com.integralblue:log4jdbc-spring-boot-starter:2.0.0") implementation("org.flywaydb:flyway-core:5.2.4") implementation("com.h2database:h2:1.4.200") implementation("com.github.rozidan:modelmapper-spring-boot-starter:2.3.1") implementation("com.google.guava:guava:27.1-jre") implementation("org.apache.commons:commons-lang3:3.8.1") testImplementation("org.dbunit:dbunit:2.7.0") testImplementation("org.assertj:assertj-core:3.16.0") testImplementation("org.spockframework:spock-core:${spockVersion}") testImplementation("org.spockframework:spock-spring:${spockVersion}") testImplementation("org.jsoup:jsoup:1.13.1") testImplementation("com.icegreen:greenmail:1.5.13") // for lombok annotationProcessor("org.projectlombok:lombok:${lombokVersion}") compileOnly("org.projectlombok:lombok:${lombokVersion}") // for Doma implementation("org.seasar.doma:doma-core:${domaVersion}") annotationProcessor("org.seasar.doma:doma-processor:${domaVersion}") // for Error Prone ( http://errorprone.info/ ) errorprone("com.google.errorprone:error_prone_core:${errorproneVersion}") compileOnly("com.google.errorprone:error_prone_annotations:${errorproneVersion}") // PowerMock testImplementation("org.powermock:powermock-module-junit4:${powermockVersion}") testImplementation("org.powermock:powermock-api-mockito2:${powermockVersion}") // for Geb + Spock testImplementation("org.gebish:geb-spock:3.4") { exclude group: "org.codehaus.groovy", module: "groovy-all" } testImplementation("org.seleniumhq.selenium:selenium-chrome-driver:${seleniumVersion}") testImplementation("org.seleniumhq.selenium:selenium-firefox-driver:${seleniumVersion}") testImplementation("org.seleniumhq.selenium:selenium-support:${seleniumVersion}") testImplementation("org.seleniumhq.selenium:selenium-api:${seleniumVersion}") testImplementation("org.seleniumhq.selenium:selenium-remote-driver:${seleniumVersion}") // for SpotBugs compileOnly("com.github.spotbugs:spotbugs:${spotbugsVersion}") compileOnly("net.jcip:jcip-annotations:1.0") compileOnly("com.github.spotbugs:spotbugs-annotations:${spotbugsVersion}") testImplementation("com.google.code.findbugs:jsr305:3.0.2") spotbugsStylesheets("com.github.spotbugs:spotbugs:${spotbugsVersion}") spotbugsPlugins("com.h3xstream.findsecbugs:findsecbugs-plugin:1.10.1") // for JUnit 5 // junit-jupiter で junit-jupiter-api, junit-jupiter-params, junit-jupiter-engine の3つが依存関係に追加される testCompile("org.junit.jupiter:junit-jupiter") testRuntime("org.junit.platform:junit-platform-launcher") } ..........
Spring Boot 2.4.10 へのバージョンアップとして以下の点を変更します。
- buildscript block の以下の点を変更します。
version "2.2.7-RELEASE"
→version "2.4.10"
- plugins block の以下の点を変更します。
id "org.springframework.boot" version "2.2.7.RELEASE"
→id "org.springframework.boot" version "2.4.10"
id "io.spring.dependency-management" version "1.0.9.RELEASE"
→id "io.spring.dependency-management" version "1.0.11.RELEASE"
- dependencies block の以下の点を変更します。
implementation("org.springframework.boot:spring-boot-starter-validation")
を追加します。
各種ライブラリのバージョンアップとして以下の点を変更します。
- plugins block の以下の点を変更します。
id "com.gorylenko.gradle-git-properties" version "2.2.2"
→id "com.gorylenko.gradle-git-properties" version "2.3.1"
id "org.seasar.doma.codegen" version "0.0.2"
→id "org.seasar.doma.codegen" version "1.4.1"
- dependencyManagement block の以下の点を変更します。
mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES
→mavenBom(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES) { bomProperty "groovy.version", "2.5.15" }
mavenBom("org.junit:junit-bom:5.6.2")
→mavenBom("org.junit:junit-bom:5.7.2")
- dependencies block の以下の点を変更します。
def lombokVersion = "1.18.12"
→def lombokVersion = "1.18.20"
def domaVersion = "2.34.0"
→def domaVersion = "2.49.0"
implementation("org.flywaydb:flyway-core:5.2.4")
→implementation("org.flywaydb:flyway-core:7.14.1")
implementation("com.google.guava:guava:27.1-jre")
→implementation("com.google.guava:guava:31.0.1-jre")
implementation("org.apache.commons:commons-lang3:3.8.1")
→implementation("org.apache.commons:commons-lang3:3.12.0")
testImplementation("org.dbunit:dbunit:2.7.0")
→testImplementation("org.dbunit:dbunit:2.7.2")
testImplementation("org.assertj:assertj-core:3.16.0")
→testImplementation("org.assertj:assertj-core:3.21.0")
testImplementation("org.jsoup:jsoup:1.13.1")
→testImplementation("org.jsoup:jsoup:1.14.3")
testImplementation("com.icegreen:greenmail:1.5.13")
→testImplementation("com.icegreen:greenmail:1.6.5")
testImplementation("org.gebish:geb-spock:3.4") {
→testImplementation("org.gebish:geb-spock:4.1") {
Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。
clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると compileJava タスクで警告が1件、testJUnit4AndSpock タスクでテストが大量に失敗しました。
compileJava タスクの警告は error-prone が build/generated の下のソースをチェックして出力していました。自動生成されたコードをチェックしないよう build.gradle に disableWarningsInGeneratedCode = true
の設定を追加します。
[compileJava, compileTestGroovy, compileTestJava]*.options*.encoding = "UTF-8" [compileJava, compileTestGroovy, compileTestJava]*.options*.compilerArgs = ["-Xlint:all,-options,-processing,-path"] tasks.withType(JavaCompile).configureEach { options.errorprone { disableWarningsInGeneratedCode = true } } tasks.named("compileTestJava").configure { options.errorprone.enabled = false }
testJUnit4AndSpock タスクでテストが大量に失敗している方は、失敗したテストを 1件だけ IntelliJ IDEA 上から実行してみると Caused by: org.flywaydb.core.api.FlywayException: Found non-empty schema(s) "PUBLIC" but no schema history table. Use baseline() or set baselineOnMigrate to true to initialize the schema history table.
というエラーメッセージが出力されていました。
Flyway が実行される時に PUBLIC スキーマが空でなく、spring.flyway.baseline-on-migrate=true
を設定すれば schema history table を初期化してくれるとのことですが、spring.flyway.baseline-on-migrate=true
を設定するのではなく PUBLIC テーブルが空でない原因を調べることにします。
application.properties を見ると以下の設定が記述されており、明らかにこれですね。。。 おそらくバージョンアップ前は Flywasy が先に実行されて Sprig Session のテーブル作成はその後に実行されていたのが、バージョンアップ後はその順序が逆になったものと思われます。
spring.session.store-type=jdbc spring.session.jdbc.initialize-schema=embedded spring.session.jdbc.schema=classpath:org/springframework/session/jdbc/schema-h2.sql spring.session.jdbc.table-name=SPRING_SESSION
spring.session.jdbc.initialize-schema=embedded
→ spring.session.jdbc.initialize-schema=never
に変更して Spring Session のテーブルを自動作成しないように変更してから、
spring.session.store-type=jdbc spring.session.jdbc.initialize-schema=never spring.session.jdbc.table-name=SPRING_SESSION
失敗していたテスト(このテストは Spring Session の機能を利用していない)を実行してみると、成功するようになりました。
spring.session.jdbc.initialize-schema=never
の設定はそのままにして、Flyway で Spring Session のテーブルを作成するようにします。
src/main/resources/db/migration の下に V1.2__create_spring_session_schema.sql を新規作成した後、org/springframework/session/jdbc/schema-h2.sql の内容をコピーします。
-- copy from org/springframework/session/jdbc/schema-h2.sql CREATE TABLE SPRING_SESSION ( PRIMARY_ID CHAR(36) NOT NULL, SESSION_ID CHAR(36) NOT NULL, CREATION_TIME BIGINT NOT NULL, LAST_ACCESS_TIME BIGINT NOT NULL, MAX_INACTIVE_INTERVAL INT NOT NULL, EXPIRY_TIME BIGINT NOT NULL, PRINCIPAL_NAME VARCHAR(100), CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID) ); CREATE UNIQUE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (SESSION_ID); CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (EXPIRY_TIME); CREATE INDEX SPRING_SESSION_IX3 ON SPRING_SESSION (PRINCIPAL_NAME); CREATE TABLE SPRING_SESSION_ATTRIBUTES ( SESSION_PRIMARY_ID CHAR(36) NOT NULL, ATTRIBUTE_NAME VARCHAR(200) NOT NULL, ATTRIBUTE_BYTES LONGVARBINARY NOT NULL, CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME), CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION (PRIMARY_ID) ON DELETE CASCADE );
再度 clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると、テストがまだ 2件失敗します。
原因を調査すると、改行コードを <br/>
に変換している th:utext="*{inquiry} ? ${#strings.replace(#strings.escapeXml(confirmForm.inquiry), T(java.lang.System).getProperty('line.separator'), '<br />')} : ''"
のところで org.attoparser.ParseException: Instantiation of new objects and access to static classes is forbidden in this context
というエラーメッセージが出力されていました。
<tr> <th nowrap>お問い合わせの内容</th> <td id="inquiry" th:utext="*{inquiry} ? ${#strings.replace(#strings.escapeXml(confirmForm.inquiry), T(java.lang.System).getProperty('line.separator'), '<br />')} : ''"> ここに、<br/> 入力されたお問い合わせの内容が表示されます。 </td> </tr>
Web で調べると Spring Boot 2.4.2 and Thymeleaf 3.0.12 - access static methods を見つけました。Thymeleaf 3.0.12 からセキュリティ強化のために T(identifier) in SpringEL
の形式では呼び出せなくなったとのこと。
System.getProperty を呼び出す Bean を作成して、Thymeleaf テンプレートから呼び出すように変更します。
まず src/main/java/ksbysample/webapp/bootnpmgeb/helper の下に thymeleaf パッケージを作成し、その下に SystemPropertiesHelper.java を新規作成して以下の内容を記述します。
package ksbysample.webapp.bootnpmgeb.helper.thymeleaf; import org.springframework.boot.system.SystemProperties; import org.springframework.stereotype.Component; /** * System Property 値取得用 Helper クラス */ @Component("sph") public class SystemPropertiesHelper { /** * System#getProperty を呼び出して指定された system property の値を取得する * * @param properties 値を取得する system property 名 * @return 取得した system property の値 */ public String getProperty(String... properties) { return SystemProperties.get(properties); } }
src/main/resources/templates/web/inquiry/confirm.html を以下のように変更します。
<tr> <th nowrap>お問い合わせの内容</th> <td id="inquiry" th:utext="*{inquiry} ? ${#strings.replace(#strings.escapeXml(confirmForm.inquiry), @sph.getProperty('line.separator'), '<br />')} : ''"> ここに、<br/> 入力されたお問い合わせの内容が表示されます。 </td> </tr>
T(java.lang.System).getProperty('line.separator')
→@sph.getProperty('line.separator')
に変更します。
再度 clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると、今度は "BUILD SUCCESSFUL" のメッセージが出力されました。
gebTest タスクも "BUILD SUCCESSFUL" のメッセージが表示されました。Geb のバージョンアップは特に問題は発生しないようです。
履歴
2021/10/10
初版発行。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その97 )( webpack を 4.43.0 → 5.56.0 へバージョンアップする )
概要
記事一覧はこちらです。
- 今回の手順で確認できるのは以下の内容です。
- webpack を 4.43.0 → 5.56.0 へ、webpack-cli を 3.3.11 → 4.8.0 へバージョンアップします。
参照したサイト・書籍
To v5 from v4
https://webpack.js.org/migrate/5/TerserWebpackPlugin
https://webpack.js.org/plugins/terser-webpack-plugin/webpack-contrib / terser-webpack-plugin
https://github.com/webpack-contrib/terser-webpack-plugin#terseroptionsterser / terser
https://github.com/terser/terserwebpack@5の主な変更点まとめ
https://blog.hiroppy.me/entry/webpack5webpack 5 にアップグレードしました
https://medium.com/studist-dev/migration-webpack-from-4-to-5-3df31da8e7a2browserslist / browserslist
https://github.com/browserslist/browserslistCache
https://webpack.js.org/configuration/cache/#cachebuilddependencies
目次
- webpack を 4.43.0 → 4.46.0 へ、webpack-cli を 3.3.11 → 4.8.0 へバージョンアップする
- webpack を 4.46.0 → 5.56.0 へバージョンアップする
- uglifyjs-webpack-plugin を terser-webpack-plugin に変更する
- package.json に browserslist を追加する
- cache の設定を追加する
- 最後に各種コマンドや build で問題がないか確認する
手順
webpack を 4.43.0 → 4.46.0 へ、webpack-cli を 3.3.11 → 4.8.0 へバージョンアップする
To v5 from v4 の Upgrade webpack 4 and its plugins/loaders に webpack 4、webpack-cli を最新バージョンに上げるよう記述されているので、以下のコマンドを実行します。
npm install --save-dev webpack@4.46.0
npm install --save-dev webpack-cli@4.8.0
webpack を 4.46.0 → 5.56.0 へバージョンアップする
Make sure your build has no errors or warnings に記載されている
node --trace-deprecation node_modules/webpack/bin/webpack.js
を実行します。
mode は起動時オプションで指定するようにしているので、まずは node --trace-deprecation node_modules/webpack/bin/webpack.js --mode production
を実行してみると特に警告やエラーのメッセージは出力されませんでした。
次に node --trace-deprecation node_modules/webpack/bin/webpack.js --mode development
を実行してみますが、こちらもメッセージは何も出力されませんでした。
Test webpack 5 compatibility に記載されているオプションを webpack.config.js に追加してから、
module.exports = (env, argv) => { return { node: { Buffer: false, process: false, }, entry: { "js/inquiry/input01": ["./src/main/assets/js/inquiry/input01.js"], ..........
node --trace-deprecation node_modules/webpack/bin/webpack.js --mode production
コマンドを実行してみましたが、メッセージ等は表示されませんでした。webpack.config.js に追加したオプションは削除します。
問題ないようなので、以下のコマンドを実行し webpack を 5 の最新バージョンにバージョンアップします。
npm install --save-dev webpack@5.56.0
使用していない prettier-webpack-plugin に関するメッセージが出力されているので、以下のコマンドを実行して削除します。
npm uninstall --save-dev prettier-webpack-plugin
uglifyjs-webpack-plugin は後で削除するので、今はこのままにします。
npm run build
コマンドを実行すると webpack 5 に対応していない uglifyjs-webpack-plugin の設定を残している影響でエラーメッセージが大量に出力されます。
uglifyjs-webpack-plugin を terser-webpack-plugin に変更する
以下のコマンドを実行して uglifyjs-webpack-plugin をアンインストール、terser-webpack-plugin をインストールします。
npm uninstall --save-dev uglifyjs-webpack-plugin
npm install --save-dev terser-webpack-plugin@5.2.4
terser-webpack-plugin は uglifyjs-webpack-plugin とほぼ同じオプションが指定できるそうなので webpack.config.js の optimization を以下の内容に変更します。
const webpack = require("webpack"); const TerserPlugin = require("terser-webpack-plugin"); // --mode オプションで指定された文字列を参照したい場合には argv.mode を参照する module.exports = (env, argv) => { return { .......... optimization: { minimizer: [ new TerserPlugin({ terserOptions: { ecma: 5, output: { comments: false, }, compress: { dead_code: true, drop_console: true, }, }, }), ], }, .......... devtool: argv.mode === "production" ? false : "inline-source-map", }; };
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
→const TerserPlugin = require("terser-webpack-plugin");
に変更します。new UglifyJsPlugin({
→new TerserPlugin({
に変更します。uglifyOptions: {
→terserOptions: {
に変更します。- compress オプションの指定が
compress: true
とcompress: { ... }
の2つ書かれていたことに気づいたので、compress: true
の方を削除します。 - source map を生成するか否かは devtools の設定に依存するようになったので、
sourceMap: false
を削除します。 - production モードの場合には source map を生成しないよう
devtool: "inline-source-map"
→devtool: argv.mode === "production" ? false : "inline-source-map",
に変更します。
‘npm run build‘ コマンドを実行するとエラーメッセージは出なくなりました。
生成された js ファイルを見ると、~.LICENSE.txt というファイルも生成されるようになりました。
package.json に browserslist を追加する
Need to support an older browser like IE 11? を読むと package.json に browserslist を記述しておくと webpack 5 がコードスタイルを決めてくれるようになったそうです。https://github.com/postcss/autoprefixer を見ると autoprefixer も browserslist の設定を見てくれるようなので、package.json の最後に "browserslist": [ ... ]
を追加します。
.......... "browserslist": [ "last 1 version", "> 1%", "IE 11" ] }
postcss.config.js も以下のように変更します。
module.exports = { plugins: [ require("stylelint"), require("autoprefixer"), require("cssnano")({ preset: "default", }), ], };
require("autoprefixer")({ browserlist: ["last 2 versions"] }),
→require("autoprefixer"),
に変更します。
browserslist を追加する前は npx browserslist
コマンドを実行すると以下のように出力されますが、
追加した後は以下のよう変わりました。
cache の設定を追加する
webpack 5 からファイルシステムによるキャッシュが導入されて大幅に速度改善できるようになったとのことなので、設定を追加します。
webpack.config.js に cache を追加します。development 環境では有効、production 環境では無効にします。
output: { .......... }, cache: argv.mode === "production" ? false : { type: "filesystem", buildDependencies: { config: [__filename], }, }, resolve: { ..........
最後に各種コマンドや build で問題がないか確認する
最後にコマンド、build で問題がないか一通り確認します。
npm test
コマンドは問題ありません。
npm run build
コマンドも問題ありません。
clean タスク実行 → Rebuild Project 実行 → build タスク実行も問題ありません。
gebTest タスクも問題ありません。
履歴
2021/10/08
初版発行。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その96 )( postcss を 7.0.29 → 8.3.8 へ、postcss-cli を 7.1.1 → 9.0.1 へ、prettier を 2.0.5 → 2.4.1 へ、stylelint を 13.3.3 → 13.13.1 へバージョンアップする )
概要
記事一覧はこちらです。
- 今回の手順で確認できるのは以下の内容です。
- autoprefixer を 9.7.6 → 10.3.6 へ、cssnano を 4.1.10 → 5.0.8 へ、postcss を 7.0.29 → 8.3.8 へ、postcss-cli を 7.1.1 → 9.0.1 へバージョンアップします。
- prettier を 2.0.5 → 2.4.1 へバージョンアップします。
- stylelint を 13.3.3 → 13.13.1 へ、stylelint-config-standard を 20.0.0 → 22.0.0 へバージョンアップします。
参照したサイト・書籍
目次
- autoprefixer を 9.7.6 → 10.3.6 へ、cssnano を 4.1.10 → 5.0.8 へ、postcss を 7.0.29 → 8.3.8 へ、postcss-cli を 7.1.1 → 9.0.1 へバージョンアップする
- prettier を 2.0.5 → 2.4.1 へバージョンアップする
- stylelint を 13.3.3 → 13.13.1 へ、stylelint-config-standard を 20.0.0 → 22.0.0 へバージョンアップする
- 最後に各種コマンドや build で問題がないか確認する
手順
autoprefixer を 9.7.6 → 10.3.6 へ、cssnano を 4.1.10 → 5.0.8 へ、postcss を 7.0.29 → 8.3.8 へ、postcss-cli を 7.1.1 → 9.0.1 へバージョンアップする
以下のコマンドを実行して最新のバージョンにします。
npm install --save-dev autoprefixer@10.3.6
npm install --save-dev cssnano@5.0.8
npm install --save-dev postcss-cli@9.0.1
npm test
コマンドを実行するとテストは全て成功しましたが、
npm run build
コマンドを実行すると Please install PostCSS 8 or above
のメッセージが出力されました。postcss-cli をバージョンアップしただけでは postcss はバージョンアップされないようです。
node_modules/postcss/CHANGELOG.md を確認したところ 7.0.29 がインストールされていました。https://www.npmjs.com/package/postcss を見ると最新バージョンは 8.3.8 なので、以下のコマンドを実行します。
npm install --save-dev postcss@8.3.8
npm run build
コマンドを実行すると今度は何の警告・エラーメッセージも出力されずに終了しました。
prettier を 2.0.5 → 2.4.1 へバージョンアップする
以下のコマンドを実行して最新のバージョンにします。
npm install --save-dev prettier@2.4.1
npm test
コマンド、npm run build
コマンドのどちらも何の警告・エラーメッセージも出力されずに終了しました。
今回のバージョンアップでは1ファイルだけフォーマットし直されており、改行位置が少し変更されていました。
stylelint を 13.3.3 → 13.13.1 へ、stylelint-config-standard を 20.0.0 → 22.0.0 へバージョンアップする
以下のコマンドを実行して最新のバージョンにします。
npm install --save-dev stylelint@13.13.1
npm install --save-dev stylelint-config-standard@22.0.0
npm test
コマンド、npm run build
コマンドのどちらも何の警告・エラーメッセージも出力されずに終了しました。
最後に各種コマンドや build で問題がないか確認する
最後にコマンド、build で問題がないか一通り確認します。
npm test
コマンドは問題ありません。
npm run build
コマンドも問題ありません。
clean タスク実行 → Rebuild Project 実行 → build タスク実行も問題ありません。
gebTest タスクも問題ありません。
IntelliJ IDEA の「Settings」ダイアログを開いて「Language & Frameworks」-「Node.js and NPM」を表示し、バージョンアップ後の状態も記載しておきます。
履歴
2021/10/04
初版発行。