かんがるーさんの日記

最近自分が興味をもったものを調べた時の手順等を書いています。今は Spring Boot をいじっています。

Spring Boot + npm + Geb で入力フォームを作ってテストする ( その83 )( Checkstyle を 8.11 → 8.19 へ、PMD を 6.6.0 → 6.13.0 へバージョンアップ+JUnit 5 の導入+ Oracle JDK 8u202 → AdoptOpenJDK 11.0.2+9 へ、error-prone を 2.3.1 → 2.3.3 へバージョンアップする)

概要

記事一覧はこちらです。

Spring Boot + npm + Geb で入力フォームを作ってテストする ( その82 )( Gradle を 4.8.1 → 5.3.1 へ、Spring Boot を 2.0.4 → 2.1.4 へバージョンアップする ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • Checkstyle を 8.11 → 8.19 へ、PMD を 6.6.0 → 6.13.0 へバージョンアップします。
    • JUnit 5 を使用できるようにします。このプロジェクトでは Spock+Geb でしかテストを書いていないので JUnit 5 は使える環境を整えるだけになります。
    • JDKOracle JDK 8u202 → AdoptOpenJDK 11.0.2+9 へ、error-prone を 2.3.1 → 2.3.3 へバージョンアップします。

参照したサイト・書籍

  1. https://github.com/apache/groovy/commit/92bd96fcdfe35e502987e1846715a08a45620db1

    • Groovy で --add-opens オプションを付ける時に参照しました。

目次

  1. Checkstyle を 8.11 → 8.19 へ、PMD を 6.6.0 → 6.13.0 へバージョンアップする
  2. JUnit 5 を導入する
  3. Oracle JDK 8u202 → AdoptOpenJDK 11.0.2+9 へ、error-prone を 2.3.1 → 2.3.3 へバージョンアップする
  4. testJUnit4AndSpock タスクで出る警告を解消する
  5. 失敗するテストの原因を調査・解消する
  6. compileTestGroovy タスクで出る警告を解消する。。。ことは出来ませんでした
  7. gebTest タスクが成功するようにする

手順

Checkstyle を 8.11 → 8.19 へ、PMD を 6.6.0 → 6.13.0 へバージョンアップする

build.gradle の以下の点を変更します。

checkstyle {
    configFile = file("${rootProject.projectDir}/config/checkstyle/google_checks.xml")
    toolVersion = "8.19"
    sourceSets = [project.sourceSets.main]
}

..........

pmd {
    toolVersion = "6.13.0"
    sourceSets = [project.sourceSets.main]
    ignoreFailures = true
    consoleOutput = true
    ruleSetFiles = rootProject.files("/config/pmd/pmd-project-rulesets.xml")
    ruleSets = []
}
  • checkstyle block で toolVersion = "8.11"toolVersion = "8.19" に変更します。
  • pmd block で toolVersion = "6.6.0"toolVersion = "6.13.0" に変更します。

変更後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。

clean タスク実行 → Rebuild Project 実行 → build タスク実行を行うと、PMD で何件か警告が出ました。

f:id:ksby:20190414123438p:plain

  • D:\project-springboot\ksbysample-boot-miscellaneous\boot-npm-geb-sample\src\main\java\ksbysample\webapp\bootnpmgeb\Application.java:26: The constant name 'springProfiles' doesn't match '[A-Z][A-Z_0-9]*'
    • 定数名を SPRING_PROFILES に変更します。
  • D:\project-springboot\ksbysample-boot-miscellaneous\boot-npm-geb-sample\src\main\java\ksbysample\webapp\bootnpmgeb\aspect\logging\ControllerAndEventNameLogger.java:17: The constant name 'logger' doesn't match '[A-Z][A-Z_0-9]*'
  • D:\project-springboot\ksbysample-boot-miscellaneous\boot-npm-geb-sample\src\main\java\ksbysample\webapp\bootnpmgeb\aspect\logging\MethodLogger.java:20: The constant name 'logger' doesn't match '[A-Z][A-Z_0-9]*'
  • D:\project-springboot\ksbysample-boot-miscellaneous\boot-npm-geb-sample\src\main\java\ksbysample\webapp\bootnpmgeb\aspect\logging\RequestAndResponseLogger.java:34: The constant name 'logger' doesn't match '[A-Z][A-Z_0-9]*'

再度 clean タスク実行 → Rebuild Project 実行 → build タスク実行を行うと、今度は BUILD SUCCESSFUL のメッセージが出力されました。

f:id:ksby:20190414131126p:plain

JUnit 5 を導入する

build.gradle の以下の点を変更します。

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.4.2")
    }
}

dependencies {
    ..........

    // 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")
}

def jvmArgsForTask = [
        "-ea",
        "-Dfile.encoding=UTF-8",
        "-Dsun.nio.cs.map=x-windows-iso2022jp/ISO-2022-JP"
]
def printTestCount = { desc, result ->
    if (!desc.parent) { // will match the outermost suite
        println "Results: ${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} successes, ${result.failedTestCount} failures, ${result.skippedTestCount} skipped)"
    }
}

bootRun {
    jvmArgs = jvmArgsForTask +
            ["-Dspring.profiles.active=develop"]
}

tasks.withType(Test) {
    jvmArgs = jvmArgsForTask +
            ["-Dspring.profiles.active=unittest"]
}
task testJUnit4AndSpock(type: Test) {
    // testJUnit4AndSpock タスクの jvmArgs は tasks.withType(Test) { ... } で定義している
    exclude "geb/**"

    testLogging {
        afterSuite printTestCount
    }
}
test.dependsOn testJUnit4AndSpock
test {
    // test タスクの jvmArgs は tasks.withType(Test) { ... } で定義している

    // for JUnit 5
    useJUnitPlatform()

    testLogging {
        afterSuite printTestCount
    }
}

..........

webdriverBinaries {
    chromedriver "73.0.3683.68"
    geckodriver "0.24.0"
}
def drivers = ["chrome", "firefox"]
drivers.each { driver ->
    task "${driver}Test"(type: Test) {
        // 前回実行時以降に何も更新されていなくても必ず実行する
        outputs.upToDateWhen { false }
        systemProperty "geb.env", driver
        exclude "ksbysample/**"
// Gradle 5.3 で internal API が変更されて gradle-processes が動かなくなったのでコメントアウトする
//        dependsOn startServer
//        finalizedBy stopServer

        testLogging {
            afterSuite printTestCount
        }
    }
}
task gebTest {
    dependsOn drivers.collect { tasks["${it}Test"] }
    enabled = false
}
  • dependencyManagement block の import block 内に mavenBom("org.junit:junit-bom:5.4.2") を追加します。
  • dependencies block に以下の2行を追加します。
    • testCompile("org.junit.jupiter:junit-jupiter")
    • testRuntime("org.junit.platform:junit-platform-launcher")
  • def jvmArgsForTask = [ ... ] を追加します。
  • def printTestCount = { ... } を追加します。
  • bootRun タスクの jvmArgs の設定を jvmArgsForTask 変数を利用したものに変更します。
  • tasks.withType(Test) { ... } の jvmArgs の設定を jvmArgsForTask 変数を利用したものに変更します。
  • task testJUnit4AndSpock(type: Test) { ... } を追加します。
  • test.dependsOn testJUnit4AndSpock を追加します。
  • test タスク内に以下の記述を追加します。
    • useJUnitPlatform()
    • testLogging { afterSuite printTestCount }
  • exclude "geb/**" の記述は test タスクから testJUnit4AndSpock タスクへ移動します。
  • drivers.each { driver -> task "${driver}Test"(type: Test) { ... } } 内に testLogging { afterSuite printTestCount } を追加します。

変更後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。

clean タスク実行 → Rebuild Project 実行 → build タスク実行をすると、テストは問題なく成功し BUILD SUCCESSFUL のメッセージが出力されました。

f:id:ksby:20190414144014p:plain

gebTest タスクも BUILD SUCCESSFUL のメッセージが出力されました。

f:id:ksby:20190414144720p:plain

Oracle JDK 8u202 → AdoptOpenJDK 11.0.2+9 へ、error-prone を 2.3.1 → 2.3.3 へバージョンアップする

IntelliJ IDEA のメインメニューから「File」-「Project Structure...」を選択して「Project Structure」ダイアログを開き、「Project SDK」で「11.0.2+9」を選択してから「OK」ボタンをクリックしてダイアログを閉じます。

f:id:ksby:20190414154450p:plain

build.gradle の以下の点を変更します。

plugins {
    id "java"
    id "eclipse"
    id "idea"
    id "org.springframework.boot" version "2.1.4.RELEASE"
    id "io.spring.dependency-management" version "1.0.7.RELEASE"
    id "groovy"
    id "net.ltgt.errorprone" version "0.7.1"
    id "checkstyle"
    id "com.github.spotbugs" version "1.6.9"
    id "pmd"
    id "com.moowork.node" version "1.3.1"
    id "com.gorylenko.gradle-git-properties" version "2.0.0"
// Gradle 5.3 で internal API が変更されて gradle-processes が動かなくなったのでコメントアウトする
//    id "com.github.johnrengelman.processes" version "0.5.0"
    id "com.energizedwork.webdriver-binaries" version "1.4"
}

sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11

..........

[compileJava, compileTestGroovy, compileTestJava]*.options*.encoding = "UTF-8"
[compileJava, compileTestGroovy, compileTestJava]*.options*.compilerArgs = ["-Xlint:all,-options,-processing,-path"]
tasks.named("compileTestJava").configure {
    options.errorprone.enabled = false
}

..........

dependencies {
    def spockVersion = "1.3-groovy-2.5"
    def domaVersion = "2.24.0"
    def lombokVersion = "1.18.6"
    def errorproneVersion = "2.3.3"
    def powermockVersion = "2.0.0"
    def seleniumVersion = "3.13.0"
    def spotbugsVersion = "3.1.11"

    ..........

    // for Geb + Spock
    testImplementation("org.gebish:geb-spock:2.3.1") {
        exclude group: "org.codehaus.groovy", module: "groovy-all"
    }
    ..........

}

def jvmArgsForTask = [
        "-ea",
        "-Dfile.encoding=UTF-8",
        "-Dsun.nio.cs.map=x-windows-iso2022jp/ISO-2022-JP"
]
// JDK 11 に変更後、test タスク実行時に groovy と powermock が JDKの内部部分にアクセスするためにコードでリフレクションを使用
// していて WARNING が出るため、JVM の起動時オプションの --add-opens を指定して WARNING が出ないようにする
def jvmArgsAddOpens = [
        "--add-opens=java.base/java.io=ALL-UNNAMED",
        "--add-opens=java.base/java.lang=ALL-UNNAMED",
        "--add-opens=java.base/java.lang.invoke=ALL-UNNAMED",
        "--add-opens=java.base/java.lang.ref=ALL-UNNAMED",
        "--add-opens=java.base/java.lang.reflect=ALL-UNNAMED",
        "--add-opens=java.base/java.net=ALL-UNNAMED",
        "--add-opens=java.base/java.security=ALL-UNNAMED",
        "--add-opens=java.base/java.util=ALL-UNNAMED",
        "--add-opens=java.base/java.util.stream=ALL-UNNAMED"
]
def printTestCount = { desc, result ->
    if (!desc.parent) { // will match the outermost suite
        println "Results: ${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} successes, ${result.failedTestCount} failures, ${result.skippedTestCount} skipped)"
    }
}

bootRun {
    jvmArgs = jvmArgsForTask +
            jvmArgsAddOpens +
            ["-Dspring.profiles.active=develop"]
}

tasks.withType(Test) {
    jvmArgs = jvmArgsForTask +
            jvmArgsAddOpens +
            ["-Dspring.profiles.active=unittest"]
}
  • plugins block の以下の点を変更します。
    • id "net.ltgt.errorprone" version "0.0.14"id "net.ltgt.errorprone" version "0.7.1"
  • sourceCompatibility、targetCompatibility に指定する値を 1.8JavaVersion.VERSION_11 に変更します。
  • compileJava.options.compilerArgs += [ ... ] を削除します。
  • tasks.named("compileTestJava").configure { options.errorprone.enabled = false } を追加します。
  • dependencies block の以下の点を変更します。
    • def errorproneVersion = "2.3.1"def errorproneVersion = "2.3.3"
  • def jvmArgsAddOpens = [ ... ] を追加します。Spring Boot 2.0.x の Web アプリを 2.1.x へバージョンアップする ( その15 )( JDK を 8u202 → 11.0.2+9 に変更する ) で指定したものと同じものを指定しておきます。
  • bootRun { ... }tasks.withType(Test) { ... } 内の jvmArgs の設定に jvmArgsAddOpens + を追加します。
  • groovy も 2.5 にバージョンアップします。
    • dependencies block 内で def spockVersion = "1.3-groovy-2.4"def spockVersion = "1.3-groovy-2.5" に変更します。
    • testImplementation("org.gebish:geb-spock:2.3.1")testImplementation("org.gebish:geb-spock:2.3.1") { exclude group: "org.codehaus.groovy", module: "groovy-all" } に変更します。

変更後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。

IntelliJ IDEA のメインメニューから「Run」-「Edit Configurations...」を選択して「Run/Debug Configurations」ダイアログを開き、画面左側のツリーから「Templates」-「JUnit」を選択後、画面右側の「VM options」に build.gradle の def jvmArgsAddOpens = [ ... ] に記述したオプションを追加します。

f:id:ksby:20190414194725p:plain

また追加した結果 IntelliJ IDEA からテストを実行しようとすると Command line is too long. のエラーメッセージが表示されて実行できなくなるので、画面右側の「Shorten command line」で「JAR manifest」を選択します。

f:id:ksby:20190414195417p:plain

clean タスク実行 → Rebuild Project 実行 → build タスク実行して出力される以下のエラーメッセージを取り除きます。

  • エラー: An unhandled exception was thrown by the Error Prone static analysis plugin.
    • このエラーメッセージが出る箇所は PMD の @SuppressWarnings が付与されているので、@SuppressWarnings({"PMD.UnusedPrivateMethod"})@SuppressWarnings({"PMD.UnusedPrivateMethod", "UnusedMethod"}) に変更します。
  • 警告:[JavaTimeDefaultTimeZone] LocalDateTime.now() is not allowed because it silently uses the system default time-zone. You must pass an explicit time-zone (e.g., ZoneId.of("America/Los_Angeles")) to this method.
    • LocalDateTime.now()LocalDateTime.now(ZoneId.of("Asia/Tokyo")) に変更します。

ここまでやると以下の状態になります。

f:id:ksby:20190414200539p:plain f:id:ksby:20190414200639p:plain

  • compileTestGroovy タスクで警告が出る。
  • testJUnit4AndSpock タスクで警告が出る。
  • テストが1件失敗する。

testJUnit4AndSpock タスクで出る警告を解消する

出たのは以下3件のメッセージでした。

  • WARNING: Illegal reflective access by org.codehaus.groovy.reflection.CachedConstructor$1 (file:/C:/Users/root/.gradle/caches/modules-2/files-2.1/org.codehaus.groovy/groovy/2.5.6/6936e700f0fb1b50bac0698ada4347a769d40199/groovy-2.5.6.jar) to constructor java.util.stream.Collectors()
  • WARNING: Illegal reflective access by org.codehaus.groovy.reflection.CachedConstructor$1 (file:/C:/Users/root/.gradle/caches/modules-2/files-2.1/org.codehaus.groovy/groovy/2.5.6/6936e700f0fb1b50bac0698ada4347a769d40199/groovy-2.5.6.jar) to constructor java.nio.charset.StandardCharsets()
  • WARNING: Illegal reflective access by org.powermock.reflect.internal.WhiteboxImpl (file:/C:/Users/root/.gradle/caches/modules-2/files-2.1/org.powermock/powermock-reflect/2.0.0/cd452bc345ec9f88ec5efecd41139de0cb1d4265/powermock-reflect-2.0.0.jar) to method java.util.regex.Pattern.clazz(boolean)

build.gradle と IntelliJ IDEA の「Edit Configurations...」-「JUnit」の設定に以下のオプションを追加します。

  • --add-opens=java.base/java.util.stream=ALL-UNNAMED
  • --add-opens=java.base/java.nio.charset=ALL-UNNAMED
  • --add-opens=java.base/java.util.regex=ALL-UNNAMED

失敗するテストの原因を調査・解消する

エラーの原因を調べるために Project Tool Window で src/test/groovy/ksbysample でコンテキストメニューを表示して「Run 'Tests in 'ksbysample''」を選択してテストを実行してみると、

f:id:ksby:20190414210930p:plain

テストが失敗したのは src/test/groovy/ksbysample/webapp/bootnpmgeb/web/inquiry/form/InquiryInput02FormValidatorTest.groovy で、以下のように実装されていました。

    @RunWith(PowerMockRunner)
    @PowerMockRunnerDelegate(SpringRunner)
    @SpringBootTest
    @PrepareForTest(EmailValidator)
    @PowerMockIgnore("javax.management.*")
    static class InquiryInput02FormValidator_メールアドレス {

        @Autowired
        private InquiryInput02FormValidator input02FormValidator

        ..........

@PowerMockIgnore("javax.management.*") を変更し忘れていただけでした。。。 @PowerMockIgnore("javax.management.*")@PowerMockIgnore(["javax.management.*", "com.sun.org.apache.xerces.*", "javax.xml.*", "org.xml.*", "org.w3c.dom.*", "com.sun.org.apache.xalan.*"]) に変更します。ksbysample-webapp-lending と同じ変更だと Caused by: java.lang.IllegalAccessError: class com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl (in unnamed module @0x12e035a8) cannot access class jdk.xml.internal.JdkXmlUtils (in module java.xml) because module java.xml does not export jdk.xml.internal to unnamed module @0x12e035a8 というエラーメッセージが表示されたので、, "com.sun.org.apache.xalan.*" を追加しています。

compileTestGroovy タスクで出る警告を解消する。。。ことは出来ませんでした

WARNING: Illegal reflective access by org.codehaus.groovy.reflection.CachedClass (file:/C:/Users/root/.gradle/caches/modules-2/files-2.1/org.codehaus.groovy/groovy/2.5.6/6936e700f0fb1b50bac0698ada4347a769d40199/groovy-2.5.6.jar) to method java.util.AbstractCollection.hugeCapacity(int) というエラーメッセージが出ているので compileTestGroovy タスクの jvmArgs にも --add-opens オプションを設定しようと思い設定方法を調べたところ、gradle/gradle に Unable to add multiple --add-opens args to forked Groovy compiler #7045 という Issue を見つけました。

試してみたところ "--add-opens" を1行だけ書いた時は問題ないのですが、以下のように2行記述すると、

[compileJava, compileTestGroovy, compileTestJava]*.options*.encoding = "UTF-8"
[compileJava, compileTestGroovy, compileTestJava]*.options*.compilerArgs = ["-Xlint:all,-options,-processing,-path"]
tasks.named("compileTestJava").configure {
    options.errorprone.enabled = false
}
compileTestGroovy {
    options.forkOptions.jvmArgs += [
            "--add-opens", "java.base/java.util=ALL-UNNAMED",
            "--add-opens", "java.base/java.lang.annotation=ALL-UNNAMED"
    ]
}

下の画像のエラーメッセージが表示されます。

f:id:ksby:20190415225416p:plain

他にも調べてみましたがさっぱり解決方法が分かりませんでした。Issue のクローズ待ちでしょうか。。。 今回は compileTestGroovy の警告メッセージは解消するのは諦めます。

ここまでの対応で clean タスク実行 → Rebuild Project 実行 → build タスク実行を行うと compileTestGroovy タスクで警告のメッセージが出ますが、BUILD SUCCESSFUL のメッセージが表示されるようになりました。

f:id:ksby:20190415231548p:plain

gebTest タスクが成功するようにする

gebTest タスクを実行すると1件警告が出ます。

  • WARNING: Illegal reflective access by org.codehaus.groovy.reflection.CachedConstructor$1 (file:/C:/Users/root/.gradle/caches/modules-2/files-2.1/org.codehaus.groovy/groovy/2.5.6/6936e700f0fb1b50bac0698ada4347a769d40199/groovy-2.5.6.jar) to constructor java.beans.Introspector(java.lang.Class,java.lang.Class,int)

java.beans は https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/java/beans/package-summary.html を見ると Module java.desktop と書かれていたので、

f:id:ksby:20190416062245p:plain

build.gradle と IntelliJ IDEA の「Edit Configurations...」-「JUnit」の設定に "--add-opens=java.desktop/java.beans=ALL-UNNAMED" を追加します。

def jvmArgsAddOpens = [
        "--add-opens=java.base/java.io=ALL-UNNAMED",
        "--add-opens=java.base/java.lang=ALL-UNNAMED",
        "--add-opens=java.base/java.lang.invoke=ALL-UNNAMED",
        "--add-opens=java.base/java.lang.ref=ALL-UNNAMED",
        "--add-opens=java.base/java.lang.reflect=ALL-UNNAMED",
        "--add-opens=java.base/java.net=ALL-UNNAMED",
        "--add-opens=java.base/java.nio.charset=ALL-UNNAMED",
        "--add-opens=java.base/java.security=ALL-UNNAMED",
        "--add-opens=java.base/java.util=ALL-UNNAMED",
        "--add-opens=java.base/java.util.regex=ALL-UNNAMED",
        "--add-opens=java.base/java.util.stream=ALL-UNNAMED",
        "--add-opens=java.desktop/java.beans=ALL-UNNAMED"
]

これで gebTest タスクは正常に終了するようになりました。

f:id:ksby:20190416063337p:plain

以上で今回の boot-npm-geb-sample プロジェクトのバージョンアップ作業は完了です。

履歴

2019/04/16
初版発行。