かんがるーさんの日記

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

Spring Boot + npm + Geb で入力フォームを作ってテストする ( 番外編 )( gradle-processes を利用して Geb のテスト前に Spring Boot の Web アプリを自動起動する )

概要

記事一覧はこちらです。

Spring Boot + npm + Geb で入力フォームを作ってテストする ( その72 )( Executable Jar ファイルを作成しても実行できない原因を調査する+気づいた点を修正する ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • Geb のテストを実行する前に都度 IntelliJ IDEA から Tomcat を起動するのは手間なので自動で起動できないか調べてみたところ、gradle-processes という Gradle のプラグインを利用して実施している例を見かけました。今回番外編として試してみようと思います。
    • 尚、gradle-processes は現時点では Gradle のバージョンが 4.5 以下であることが条件となっており(実際 4.6 以上だと動きません)、今は 4.8.1 までバージョンを上げていて戻すつもりはないので今回変更した内容は commit しません。

参照したサイト・書籍

目次

  1. gradle のバージョンを 4.5 に変更する
  2. build.gradle に gradle-processes を追加する
  3. build.gradle に Web アプリの自動起動、自動停止のタスクを追加する
  4. 動作確認

手順

gradle のバージョンを 4.5 に変更する

コマンドプロンプトから gradlew wrapper --gradle-version=4.5 を実行して Gradle のバージョンを 4.5 に変更します。

f:id:ksby:20180724070816p:plain

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

..........

wrapper {
    gradleVersion = '4.5'
    distributionType = Wrapper.DistributionType.ALL
}

..........

dependencies {
    def spockVersion = "1.1-groovy-2.4"
    def domaVersion = "2.19.2"
    def lombokVersion = "1.18.0"
    def errorproneVersion = "2.3.1"
    def powermockVersion = "1.7.4"
    def seleniumVersion = "3.13.0"

    // dependency-management-plugin によりバージョン番号が自動で設定されるもの
    // Appendix F. Dependency versions ( https://docs.spring.io/spring-boot/docs/1.5.10.RELEASE/reference/html/appendix-dependency-versions.html ) 参照
    compile("org.springframework.boot:spring-boot-starter-web")
    compile("org.springframework.boot:spring-boot-starter-thymeleaf") {
        exclude group: "org.codehaus.groovy", module: "groovy"
    }
    compile("org.springframework.boot:spring-boot-starter-data-jpa")
    compile("org.springframework.boot:spring-boot-starter-freemarker")
    compile("org.springframework.boot:spring-boot-starter-mail")
    compile("org.springframework.boot:spring-boot-starter-security")
    runtimeOnly("org.springframework.boot:spring-boot-devtools")
    compile("org.springframework.session:spring-session")
    compile("org.codehaus.janino:janino")
    testImplementation("org.springframework.boot:spring-boot-starter-test")
    testImplementation("org.springframework.security:spring-security-test")
    testImplementation("org.yaml:snakeyaml")
    testImplementation("org.mockito:mockito-core")

    // dependency-management-plugin によりバージョン番号が自動で設定されないもの、あるいは最新バージョンを指定したいもの
    compile("com.integralblue:log4jdbc-spring-boot-starter:1.0.2")
    compile("org.flywaydb:flyway-core:5.1.4")
    compile("com.h2database:h2:1.4.192")
    compile("com.github.rozidan:modelmapper-spring-boot-starter:1.0.0")
    compile("com.google.guava:guava:25.1-jre")
    compile("org.apache.commons:commons-lang3:3.7")
    testImplementation("org.dbunit:dbunit:2.5.4")
    testImplementation("org.assertj:assertj-core:3.10.0")
    testImplementation("org.spockframework:spock-core:${spockVersion}")
    testImplementation("org.spockframework:spock-spring:${spockVersion}")
    testImplementation("com.google.code.findbugs:jsr305:3.0.2")
    testImplementation("org.jsoup:jsoup:1.11.3")
    testImplementation("com.icegreen:greenmail:1.5.7")

    // for lombok
//    annotationProcessor("org.projectlombok:lombok:${lombokVersion}")
    compileOnly("org.projectlombok:lombok:${lombokVersion}")

    // for Doma
//    annotationProcessor("org.seasar.doma:doma:${domaVersion}")
    compile("org.seasar.doma:doma:${domaVersion}")
    domaGenRuntime("org.seasar.doma:doma-gen:${domaVersion}")
    domaGenRuntime("com.h2database:h2:1.4.192")

    // 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-mockito:${powermockVersion}")

    // for Geb + Spock
    testImplementation("org.gebish:geb-spock:2.1")
    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}")
}
  • wrapper block 内で gradleVersion = '4.8.1'gradleVersion = '4.5' に変更します。
  • dependencies block 内で annotationProcessor の行をコメントアウトします。annotationProcessor が入ったのは 4.6 からなので、4.5 では使用できません。

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

build.gradle に gradle-processes を追加する

追加する方法が少し分かりづらかったです。。。

Maven Repository で "gradle-processes" で検索すると、以下の結果が表示されます。最初の2件がどちらも gradle-processes です。

f:id:ksby:20180724071704p:plain

1件目をクリックすると以下の画面が表示されます。

f:id:ksby:20180724071909p:plain

2件目をクリックすると以下の画面が表示されます。

f:id:ksby:20180724072047p:plain f:id:ksby:20180724072235p:plain

また gradle-processes の GitHub のページ を見ると How To Use に以下の記述があります。

f:id:ksby:20180724072452p:plain

以上の内容から、利用するためには以下の設定が必要なことが分かります。

  • gradle-processes を利用するにはレポジトリに Gradle Plugins repository(https://plugins.gradle.org/m2/)を追加する必要がある。
  • 最新バージョンは 0.4.1。plugin block に id "com.github.johnrengelman.processes" version "0.4.1" の記述を追加する。

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

buildscript {
    ext {
        group "ksbysample"
        version "1.0.1-RELEASE"
        springBootVersion = "1.5.14.RELEASE"
    }
    repositories {
        mavenCentral()
        maven { url "https://plugins.gradle.org/m2/" }
    }
}

plugins {
    id "java"
    id "eclipse"
    id "idea"
    // plugins {} block 内では ${springBootVersion} が使用できないので、バージョンを直接記述している
    id "org.springframework.boot" version "1.5.14.RELEASE"
    id "groovy"
    id "net.ltgt.errorprone" version "0.0.14"
    id "checkstyle"
    id "findbugs"
    id "pmd"
    id "com.moowork.node" version "1.2.0"
    id "com.github.johnrengelman.processes" version "0.4.1"
}

..........
  • buildscript block に repositories { ... } を追加します。この中で maven { url "https://plugins.gradle.org/m2/" } を記述します。
  • plugins block に id "com.github.johnrengelman.processes" version "0.4.1" を追加します。version "0.4.1" の記述がないと Plugin [id: 'com.github.johnrengelman.processes'] was not found in any of the following sources: ... - Plugin Repositories (plugin dependency must include a version number for this source) というエラーが出ます。

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

build.gradle に Web アプリの自動起動、自動停止のタスクを追加する

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

buildscript {
    ext {
        group "ksbysample"
        version "1.0.1-RELEASE"
        springBootVersion = "1.5.14.RELEASE"
        mainClass = "ksbysample.webapp.bootnpmgeb.Application"
    }
    repositories {
        mavenCentral()
        maven { url "https://plugins.gradle.org/m2/" }
    }
}

..........

bootRepackage {
    mainClass = "${mainClass}"
}

..........

// for Geb + Spock Integration Test
task startServer(type: com.github.jengelman.gradle.plugins.processes.tasks.JavaFork) {
    jvmArgs = [
            '-Dspring.profiles.active=develop',
            '-Dlogging.level.root=OFF',
            '-Dlogging.level.org.springframework.web=OFF',
            '-Dlogging.level.jdbc.sqlonly=OFF',
            '-Dlogging.level.jdbc.sqltiming=OFF',
            '-Dlogging.level.jdbc.audit=OFF',
            '-Dlogging.level.jdbc.resultset=OFF',
            '-Dlogging.level.jdbc.resultsettable=OFF',
            '-Dlogging.level.jdbc.connection=OFF'
    ]
    classpath += sourceSets.main.runtimeClasspath
    main = "${mainClass}"
    doLast {
        Thread.sleep(15000)
    }
}
task stopServer {
    doLast {
        startServer.processHandle.abort()
    }
}
def drivers = ["chrome", "firefox"]
drivers.each { driver ->
    task "${driver}Test"(type: Test) {
        // 前回実行時以降に何も更新されていなくても必ず実行する
        outputs.upToDateWhen { false }
        systemProperty "geb.env", driver
        exclude "ksbysample/**"
        dependsOn startServer
        finalizedBy stopServer
    }
}
task gebTest {
    dependsOn drivers.collect { tasks["${it}Test"] }
    enabled = false
}

..........
  • buildscript block 内の ext block 内に mainClass = "ksbysample.webapp.bootnpmgeb.Application" を追加します。メインクラスを記述する箇所が2箇所になるので、共通で使用する変数を定義します。
  • bootRepackage block 内で mainClass = '${ksbysample.webapp.bootnpmgeb.Application}'mainClass = "${mainClass}" に変更します。
  • 以下の2つの task を追加します。gradle-processes では task startServer(type: Fork) のように書かれていますが、なぜか動作しなかったので com.github.jengelman.gradle.plugins.processes.tasks.JavaFork のようにパッケージも含めて記述しています。
    • task startServer(type: com.github.jengelman.gradle.plugins.processes.tasks.JavaFork) { ... }
    • task stopServer { ... }
  • drivers.each { driver -> task "${driver}Test"(type: Test) { ... } } 内に以下の2行を追加します。
    • dependsOn startServer
    • finalizedBy stopServer

動作確認

最初に clean タスク → Rebuild Project → build タスクを実行して BUILD SUCCESSFUL が表示されること、startServer と stopServer タスクが実行されないことを確認します。

f:id:ksby:20180725133039p:plain

なぜかこのタイミングで Chrome 68 が Twitter のトレンドにランクインしていたので、バージョンアップします。

次に gebTest タスクを実行します。startServer → chromeTest, firefoxTest → stopServer の順に実行されて、BUILD SUCCESSFUL が表示されました。問題なさそうです。

f:id:ksby:20180725134247p:plain

chromeTest タスクだけを実行してみます。startServer → chromeTest → stopServer の順に実行されて、テストは全て成功しました。

f:id:ksby:20180725134745p:plain

firefoxTest タスクだけを実行してみます。startServer → firefoxTest → stopServer の順に実行されて、テストは全て成功しました。

f:id:ksby:20180725140030p:plain

このプラグイン、便利ですね。GitHub の Issue を見たら現在 4.6 以降に対応中のようです。

履歴

2018/07/25
初版発行。