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
初版発行。