Spring Boot + npm + Geb で入力フォームを作ってテストする ( 番外編 )( IntelliJ IDEA に Rainbow Brackets Plugin をインストールする )
概要
記事一覧はこちらです。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その73 )( Spring Boot を 1.5.14 → 2.0.4 へバージョンアップする ) の続きです。
Twitter を見ていたら、Rainbow Brackets という IntelliJ IDEA の Plugin の情報が流れてきました。括弧の対応に色がついて見やすくなるようです。確かに便利そうなのでインストールしてみます。
参照したサイト・書籍
Rainbow Brackets
https://plugins.jetbrains.com/plugin/10080-rainbow-bracketsIntelliJ Platform SDK DevGuide - Action System
https://www.jetbrains.org/intellij/sdk/docs/basics/action_system.html
目次
手順
Rainbow Brackets Plugin をインストールする
IntelliJ IDEA のメインメニューから「File」-「Settings…」を選択します。
「Settings」ダイアログが表示されます。画面左側のリストから「Plugins」を選択した後、画面中央下にある「Browse repositories…」ボタンをクリックします。
「Browse Repositories」ダイアログが表示されます。左上の検索フィールドに “rainbow” と入力すると、その下のリストに Rainbow Brackets Plugin が表示されますので、画面右側に表示される「Install」ボタンをクリックします。
Plugin がダウンロードされた後「Install」ボタンが「Restart IntelliJ IDEA」ボタンに変わりますので、クリックします。
一旦「Settings」ダイアログに戻りますので、画面下の「OK」ボタンをクリックします。
「IDE and Plugin Updates」ダイアログが表示されますので「Restart」ボタンをクリックします。
IntelliJ IDEA が再起動してインストールは完了です。
Rainbow Brackets Plugin を使ってみる
ソースを開いてみると、Rainbow Brackets Plugin インストール前はこんな感じでしたが、
括弧毎に色が変わって表示されていました。確かにこれは見やすいです。
また Ctrl + 右クリックすると括弧の範囲内を色を付けて表示してくれます。確かにこれは便利です。。。
Alt + 右クリックだと括弧の範囲内以外をグレー表示にします。
Java のソース以外にも HTML でもこの機能が有効です。
HTML の場合にはタグで囲まれた範囲内を色を付けて表示してくれます(ただしたまにうまく動作しない時があって、その時は IntelliJ IDEA を再起動すると直ります)。
上の機能ですが、Rainbow Brackets のページでは Ctrl + Button3
と書かれているのですが、Button3
が最初何だか分からなかったんですよね。。。 IntelliJ Platform SDK DevGuide - Action System のページの中の "button1", "button2", "button3" for the mouse buttons;
という記述を見つけて、マウスのボタンのことだと分かりました。
履歴
2018/08/04
初版発行。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その73 )( Spring Boot を 1.5.14 → 2.0.4 へバージョンアップする )
概要
記事一覧はこちらです。
感想 の続きです。
- 今回の手順で確認できるのは以下の内容です。
- Spring Boot を 1系(1.5.14) → 2系(2.0.4) へバージョンアップします。
参照したサイト・書籍
Spring Boot 2.0 Release Notes
https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.0-Release-NotesSpring Boot 2.0 Migration Guide
https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.0-Migration-GuideSpring Boot Gradle Plugin Reference Guide
https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/html/spring-gradle-plugins/dependency-management-plugin
https://github.com/spring-gradle-plugins/dependency-management-pluginSpring Boot Tomcat Connection Pool
https://www.concretepage.com/spring-boot/spring-boot-tomcat-connection-poolwhy remove "HASH_MAP" pattern on spring boot 2.x
https://github.com/spring-projects/spring-session/issues/1043Better detection of Spring Session store
https://github.com/spring-projects/spring-boot/issues/9683Spring Session - Spring Boot - 2. Spring Boot Configuration
https://docs.spring.io/spring-session/docs/current/reference/html5/guides/boot-jdbc.html#httpsession-jdbc-boot-spring-configurationCould not initialize plugin: interface org.mockito.plugins.MockMaker
https://stackoverflow.com/questions/41956692/could-not-initialize-plugin-interface-org-mockito-plugins-mockmakerThere is a issue, after I downgrade the Mockito version, it disappeared
https://github.com/mockito/mockito/issues/1207Spring Boot Security 2.0
https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-Security-2.0
目次
- build.gradle を変更する
- エラーの出ているクラスを変更する
- application.properties で spring.session.store-type の設定を
hash_map
→jdbc
に変更する(hash_map
はなくなりました) - spring-session-jdbc を追加する
- Build Project(Ctrl+F9)を実行して出るエラーを取り除く
- clean タスク → Rebuild Project → build タスクを実行する
- テストが失敗した原因を調査する
- Tomcat を起動して、起動時に spring-boot-properties-migrator が出力するメッセージに対応する
- gebTest を実行してみる
- ブラウザで画面を表示して入力してみる
- 作成された jar ファイルの中身を確認する
- 本番稼働用ディレクトリに jar ファイルをコピーして動作確認する
- build.gradle から
runtimeOnly("org.springframework.boot:spring-boot-properties-migrator")
を削除する - メモ書き
手順
build.gradle を変更する
build.gradle の以下の点を変更します。
buildscript { ext { group "ksbysample" version "1.0.2-RELEASE" } } plugins { id "java" id "eclipse" id "idea" id "org.springframework.boot" version "2.0.4.RELEASE" id "io.spring.dependency-management" version "1.0.6.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" } sourceCompatibility = 1.8 targetCompatibility = 1.8 wrapper { gradleVersion = '4.8.1' distributionType = Wrapper.DistributionType.ALL } [compileJava, compileTestGroovy, compileTestJava]*.options*.compilerArgs = ['-Xlint:all,-options,-processing,-path'] compileJava.options.compilerArgs += [ '-Xep:RemoveUnusedImports:WARN' , '-Xep:ParameterName:OFF' ] // for Doma 2 // JavaクラスとSQLファイルの出力先ディレクトリを同じにする processResources.destinationDir = compileJava.destinationDir // コンパイルより前にSQLファイルを出力先ディレクトリにコピーするために依存関係を逆転する compileJava.dependsOn processResources idea { module { inheritOutputDirs = false outputDir = file("$buildDir/classes/main/") } } configurations { // for Doma 2 domaGenRuntime } checkstyle { configFile = file("${rootProject.projectDir}/config/checkstyle/google_checks.xml") toolVersion = '8.11' sourceSets = [project.sourceSets.main] } findbugs { toolVersion = '3.0.1' sourceSets = [project.sourceSets.main] ignoreFailures = true effort = "max" excludeFilter = file("${rootProject.projectDir}/config/findbugs/findbugs-exclude.xml") } tasks.withType(FindBugs) { reports { xml.enabled = false html.enabled = true } } pmd { toolVersion = "6.5.0" sourceSets = [project.sourceSets.main] ignoreFailures = true consoleOutput = true ruleSetFiles = rootProject.files("/config/pmd/pmd-project-rulesets.xml") ruleSets = [] } repositories { mavenCentral() } dependencyManagement { imports { // mavenBom は以下の URL のものを使用する // https://repo.spring.io/release/org/springframework/boot/spring-boot-starter-parent/2.0.4.RELEASE/ // bomProperty に指定可能な property は以下の URL の BOM に記述がある // https://repo.spring.io/release/org/springframework/boot/spring-boot-dependencies/2.0.4.RELEASE/spring-boot-dependencies-2.0.4.RELEASE.pom mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES } } 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/2.0.4.RELEASE/reference/html/appendix-dependency-versions.html ) 参照 implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springframework.boot:spring-boot-starter-thymeleaf") { exclude group: "org.codehaus.groovy", module: "groovy" } 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") 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") implementation("org.apache.tomcat:tomcat-jdbc") 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 によりバージョン番号が自動で設定されないもの、あるいは最新バージョンを指定したいもの implementation("com.integralblue:log4jdbc-spring-boot-starter:1.0.2") implementation("org.flywaydb:flyway-core:5.1.4") implementation("com.h2database:h2:1.4.192") implementation("com.github.rozidan:modelmapper-spring-boot-starter:1.0.0") implementation("com.google.guava:guava:25.1-jre") implementation("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}") implementation("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-mockito2:${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}") // for Spring Boot 2.0 Migration runtimeOnly("org.springframework.boot:spring-boot-properties-migrator") } ..........
- buildscript block の以下の点を変更します。
- Web アプリのバージョン番号を
version "1.0.1-RELEASE"
→version "1.0.2-RELEASE"
に変更します。 - Spring Boot のバージョン番号は plugins block の
id "org.springframework.boot"
のところで指定するようになるので、springBootVersion = "1.5.14.RELEASE"
を削除します。
- Web アプリのバージョン番号を
- plugins block の以下の点を変更します。
// plugins {} block 内では ${springBootVersion} が使用できないので、バージョンを直接記述している
のコメントを削除します。id "org.springframework.boot" version "1.5.14.RELEASE"
→id "org.springframework.boot" version "2.0.4.RELEASE"
に変更します。id "io.spring.dependency-management" version "1.0.6.RELEASE"
を追加します。
- 明記しなくても問題ないので
bootRepackage { ... }
を削除します。 - dependencyManagement block の以下の点を変更します。
mavenBom("org.springframework.boot:spring-boot-starter-parent:${springBootVersion}")
→mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES
に変更します。- Appendix F. Dependency versions を見ると Thymeleaf のバージョンが 3.0.9.RELEASE になっているので、以下の5行を削除します。
bomProperty 'thymeleaf.version', '3.0.9.RELEASE'
bomProperty 'thymeleaf-extras-springsecurity4.version', '3.0.2.RELEASE'
bomProperty 'thymeleaf-layout-dialect.version', '2.2.2'
bomProperty 'thymeleaf-extras-data-attribute.version', '2.0.1'
bomProperty 'thymeleaf-extras-java8time.version', '3.0.1.RELEASE'
- dependencies block の以下の点を変更します。
compile(...)
→implementation(...)
に変更します。- Appendix F. Dependency versions を見ると
spring-session
は存在せず、spring-session-core
やspring-session-data-gemfire
のように後ろに-...
が付くようになっていました。implementation("org.springframework.session:spring-session")
→implementation("org.springframework.session:spring-session-core")
に変更します。 - Spring Boot 2 では HikariCP がデフォルトのコネクションプーリングに変わり、Tomcat JDBC Connection Pool はデフォルトでは入りません。今は HikariCP には変更しないので
implementation("org.apache.tomcat:tomcat-jdbc")
を追加して入れるようにします。 testImplementation("org.powermock:powermock-api-mockito:${powermockVersion}")
→testImplementation("org.powermock:powermock-api-mockito2:${powermockVersion}")
に変更します。- Spring Boot 2.0 Migration Guide - Before You Start の記述に従い
runtimeOnly("org.springframework.boot:spring-boot-properties-migrator")
を追加します。
変更後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新すると、特にエラーは出ずに更新されました。
エラーの出ているクラスを変更する
src/main/java/ksbysample/webapp/bootnpmgeb/config/ApplicationConfig.java
- DataSourceBuilder クラスが import できずエラーが出ていました。import 文を削除した後、Alt+Enter を押して import し直します。
src/main/java/ksbysample/webapp/bootnpmgeb/config/WebMvcConfig.java
WebMvcConfigurerAdapter が非推奨になりました。WebMvcConfigurerAdapter クラスの JavaDoc の説明を読むと WebMvcConfigurer インターフェースに Java 8 のデフォルトメソッドで実装が追加されたので WebMvcConfigurer インターフェースを使用するよう記述されていました。
extends WebMvcConfigurerAdapter
→implements WebMvcConfigurer
に変更します。SpringTemplateEngine クラスが import できずエラーが出ていました。import 文を削除した後、Alt+Enter を押して import class し直します。
src/main/java/ksbysample/webapp/bootnpmgeb/config/WebSecurityConfig.java
- 28. Security から
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
の記述が削除されていたので、おそらく無くなったものと思われます。@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
を削除します。
application.properties で spring.session.store-type の設定を hash_map
→ jdbc
に変更する(hash_map
はなくなりました)
spring.session.store-type
に hash_map
が指定できなくなっていました。実際選択可能な候補を表示させてみると hash_map
がありません。
理由が書かれているのは Better detection of Spring Session store のページのようです。今回は hash_map
→ jdbc
に変更して、spring-session-jdbc を入れることにします。
spring-session-jdbc を追加する
build.gradle に implementation("org.springframework.session:spring-session-jdbc")
を追加します。
dependencies { .......... 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") ..........
変更後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。
src/main/resources/application.properties に以下の設定を追加します。
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
- 以下の3行を追加します。
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.schema
に設定する SQL ファイルはorg.springframework.session:spring-session-jdbc
のライブラリの下を見ると分かります。
Build Project(Ctrl+F9)を実行して出るエラーを取り除く
org.hibernate.validator.constraints.NotEmpty
→ javax.validation.constraints.NotEmpty
に変更する
Ctrl+F9 を押して Build Project を実行すると org.hibernate.validator.constraintsのorg.hibernate.validator.constraints.NotEmptyは非推奨になりました
のメッセージが表示されました。
org.hibernate.validator.constraints.NotEmpty クラスのソースを見ると以下の画像の記述がありますので、javax.validation.constraints.NotEmpty に変更します。
変更したのは以下のソースです。import 文を削除した後、Alt+Enter で import し直しました。
- src/main/java/ksbysample/webapp/bootnpmgeb/web/inquiry/form/InquiryInput01Form.java
- src/main/java/ksbysample/webapp/bootnpmgeb/web/inquiry/form/InquiryInput02FormNotEmptyRule.java
- src/main/java/ksbysample/webapp/bootnpmgeb/web/inquiry/form/InquiryInput03FormNotEmptyRule.java
clean タスク → Rebuild Project → build タスクを実行する
clean タスク → Rebuild Project → build タスクを実行してみると、以下の画像のような結果でした。
- FindBugs で
FindBugs rule violations were found.
のメッセージが表示されました。 147 tests completed, 1 failed
とテストが1件失敗しました。
FindBugs の方は一旦後回しにして、まずはテストが失敗した原因を取り除きます。
テストが失敗した原因を調査する
java.lang.NoSuchMethodError: org.mockito.internal.handler.MockHandlerFactory.createMockHandler(Lorg/mockito/mock/MockCreationSettings;)Lorg/mockito/internal/InternalMockHandler;
build タスクの出力内容では原因が分からないので、Project Tool Window の src/test/groovy/ksbysample から「Run 'Tests in 'ksbysample''」を実行します。
失敗したテストは以下の画像のテストでした。java.lang.NoSuchMethodError: org.mockito.internal.handler.MockHandlerFactory.createMockHandler(Lorg/mockito/mock/MockCreationSettings;)Lorg/mockito/internal/InternalMockHandler;
というエラーメッセージが出ています。
エラーメッセージで検索すると There is a issue, after I downgrade the Mockito version, it disappeared という Issue が見つかりました。PowerMock のバージョンを 2.0.0-beta.5
にすると直るようです。
build.gradle の以下の点を変更します。
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 = "2.0.0-beta.5" def seleniumVersion = "3.13.0"
def powermockVersion = "1.7.4"
→def powermockVersion = "2.0.0-beta.5"
に変更します。
変更後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。
clean タスク → Rebuild Project → build タスクを実行すると、今度は BUILD SUCCESSFUL が出力されました。
Tomcat を起動して、起動時に spring-boot-properties-migrator が出力するメッセージに対応する
Tomcat を起動すると以下のメッセージが表示されました。
また、少し放置していたら、1分毎に無効になったセッションを削除するための DELETE 文が実行されていました。なるほど、spring-session-jdbc だとこういう動作になるんですね。
Key: security.basic.enabled、Reason: The security auto-configuration is no longer customizable.
Spring Boot 2.0 Migration Guide - Security と Spring Boot Security 2.0 を読んだ限りでは、application.properties から security.basic.enabled
は設定できなくなり、設定するなら WebSecurityConfigurerAdapter の継承クラスで設定するとのこと。
試しに src/main/resources/application-develop.properties から security.basic.enabled=false
の設定を削除した後 Tomcat を起動すると、Key: security.basic.enabled
のメッセージは出力されなくなり、
H2 Console(http://localhost:8080/h2-console)にアクセスしても Basic 認証のダイアログは表示されませんでした。
gebTest を実行してみる
gebTest タスクを実行してみると、BUILD SUCCESSFUL のメッセージが出力されました。
ブラウザで画面を表示して入力してみる
smtp4dev を起動した後、Tomcat を起動します。http://localhost:8080/inquiry/input/01/ にアクセスして画面からデータを入力してみます。
完了画面まで表示できました。またメールも問題なく送信されており、
DB のデータも登録されていました。
作成された jar ファイルの中身を確認する
boot-npm-geb-sample-1.0.2-RELEASE.jar を開いてみると BOOT-INF の下に lib ディレクトリが作成されて、その下に外部ライブラリの jar ファイルが格納されていました。1.5系の時と違い、build.gradle に implementation で依存関係を記述しても jar ファイルの生成には問題ありませんでした。
本番稼働用ディレクトリに jar ファイルをコピーして動作確認する
以下の手順で動作することを確認しました。
- C:\webapps\boot-npm-geb-sample\lib の下に boot-npm-geb-sample-1.0.2-RELEASE.jar をコピーする。
- C:\webapps\boot-npm-geb-sample\bat\webapp_startup.bat 内の環境変数 WEBAPP_JAR の値を boot-npm-geb-sample-1.0.2-RELEASE.jar に変更する。
- サービスではなくコマンドプロンプトから webapp_startup.bat を起動する。
- C:\webapps\boot-npm-geb-sample\logs\boot-npm-geb-sample.log の最後に Started Application ... のログが出ることを確認する。
- http://localhost:8080/inquiry/input/01/ にアクセスして画面が表示されることを確認する。
build.gradle から runtimeOnly("org.springframework.boot:spring-boot-properties-migrator")
を削除する
バージョンアップ作業が終わりましたので、build.gradle に追加していた runtimeOnly("org.springframework.boot:spring-boot-properties-migrator")
を削除します。
Spring Boot 2系へのバージョンアップは以上で完了です。
メモ書き
- Spring Boot 2系から Flyway のバージョンが 5系に上がりましたが 、Flyway はバージョンアップ前から 5系を使用していたので今回は特に何もありませんでした。
- Spring Boot 2系は Gradle 4.x 以降のみサポートされるので、Gradle が 3.x 以前の場合には Spring Boot を 2系にバージョンアップする前に Gradle のバージョンを 4.x に上げた方がよさそうです。
- build.gradle の書き方がいろいろ変わります。一番変更が大きいファイルでした。
- Spring Session が地味に仕様が変わっています(build.gradle に指定する artifactId の名前が違う、hash_map がなくなった)。
もう少し続きます。FindBugs で警告が出た箇所の確認、HikariCP への変更、及び Spring Boot Actuator の導入まで試してみる予定です。
履歴
2018/08/03
初版発行。
感想
記事一覧はこちらです。
Javascrit の開発環境は Node.js + npm + npm-scripts + webpack + browser-sync + ESLint + Prettier + Jest の組み合わせでいいかな、と思っています。これに IntelliJ IDEA を組み合わせると実装がかなり楽になります。
Spring Boot のプロジェクトでも CSS フレームワークや Javascript のライブラリのインストール・管理は npm でいいですね。WebJars を使用する話をたまに聞きますが、自分が使うことはないでしょう(Gradle で全部管理したいとは特に思わないため)。また npm と同じパッケージマネージャで Yarn があり、npmから乗り換えてわかったYarnの4つのメリット とかの記事を見ると Yarn いいなと思いましたが、今回はそこまで手を出しませんでした。Javascript 関連はツール類も次々と出てきて新しいものに変えると便利そうなのですが、ついていくのが大変なんですよね。。。
記事を書き始めた頃にタスクランナーは gulp → npm-scripts へ切り替えよう的なものをいくつか見かけたので npm-scripts を使ってみましたが、今は npm-scripts で十分だと思っています。gulp については CSS で SASS を使うならまだ gulp の方が良さそう、複雑なタスクを書くなら gulp?、のような感じでいます。
webpack はとりあえず困らない程度には使えるようになったかな、という感じです(まあ Babel とかは入れていないのでそんなに使いこなしていないのではという気もしますが)。npm で Javascript のライブラリをインストールして、jQuery でスクリプトを書いて1つの js ファイルにまとめるためには必須ですね。npm でインストールしたライブラリを利用する jQuery の結構サイズの大きなスクリプトを書いても、webpack でバンドル+Uglify するとかなりサイズが小さくなって軽快に動作するので便利です。また記事の途中でバージョンが 3 → 4 へ上がりましたが、今回の記事で使っている程度であればバージョンアップは難しくはありませんでした(英語の記事がいろいろ出ているのを見てからバージョンアップしましたが)。
ファイル変更時にブラウザを自動リロードしてくれると聞いて webpack-dev-server(今は webpack-serve) ではなく browser-sync を使ってみたのですが、これが便利でした! Javascript のファイルを変更した時に F5 を押してリロードする必要が全然ないとは驚きです。 https 環境を作りたい時も browser-sync なら設定に1行追加すればよいだけなのも便利ですね。また JRebel がないとうまく機能しませんが、browser-sync → Tomcat 連携して、html,css,js は browser-sync、それ以外は Tomcat からレスポンスを返すようにして、Java 側のモジュール変更時もリロードさせることも出来ました。1点注意があるとすれば、browser-sync で返した HTML はたまに文字化けすることがあります(今回の記事では見ませんでしたが、他で開発に使用した時に見かけました)。
Prettier は記事を書いている途中から使われているのを見かけるようになって、でもフォーマットは IntelliJ IDEA でやってくれるから特に導入する必要はないかなと思っていたのですが、IntelliJ IDEA でも Prettier によるフォーマットがサポートされて、Javascript では Prettier でフォーマットするのが当たり前的な記事も見かけるようになって、最後に Jest 23 の Jest Each でデータテーブルを記述する時に Prettier があればフォーマットしてくれると聞いて、導入することにしました。実際インストールしてみると Javascript のファイルを綺麗にフォーマットしてくれるし、package.json や webpack.config.js 等の設定ファイルもきれいにフォーマット出来るので、今後はインストール必須にしたいと思います。
ESLint は Prettier が入るとフォーマットのチェックは Prettier に依存する?ようになってチェックする内容が減りますが、フォーマット以外にもチェックして欲しい点はあるので、使った方がよいのだろうなあ、という感じです。
記事を書き始めたころは Javascript のユニットテストは何を使えばよいのかよく分からず、なんか Jest が便利だよ的な記事を見かけて Jest を使ってみたのですが、今は Jest 一択です。機能が豊富でテストが書きやすく、IntelliJ IDEA でもサポートされていて実行しやすいのも魅力です。Jest 23 からは Spock のデータテーブルのような書き方もサポートされて、Parameterized test が出来るようになったのもいいですね。
Javascript の開発では IntelliJ IDEA で書くと便利ですね。便利と思っている点を上げてみると、
- モジュール分割している時も Ctrl+B を押せば実装箇所にジャンプしてくれるし、Alt+F7 で使用箇所一覧が表示されます。
- Ctrl+Shift+T を押すとモジュールに対応するユニットテストのファイルが開きます(なぜか開くんですよね、ファイル名で見ているだけけのような気がしますが)。ただし Java のように「Create New Test...」メニューは表示されません。
- リファクタリングも動作します。変数名や関数名を変えたくらいしかしていませんが、使用している箇所も問題なく修正されました。
- debug 実行ができます。Chrome で debug するのもいいのですが、IntelliJ IDEA で実行した方が breakpoint が設定しやすかったり、変数の値が確認しやすかったりします。
- Jest で書いたテストの実行がサポートされていて、テストが実行しやすいです。
- Prettier によるフォーマットもサポートされています。
- npm-scripts の実行もサポートされています。
あと Javascript でやらなかったと思っているものを上げると、以下のものでしょうか。
- TypeScript。便利なのかもしれませんが、たぶんついていけないでしょう。。。
- Flow。型を使えるようになるので使ってみたかったのですが、途中から入れる方法がよく分からなくて諦めました。
- ES2015(+Babel)。今回使っていませんが、無条件で使った方がよいと思っています。ES2015 の新文法がとにかく便利。
- Vue.js、React、Angular.js 等のフレームワーク。今回は事情により jQuery をベースに npm-scripts や webpack と組み合わせた例が欲しかったので使用しませんでしたが、迷わず使うでいいと思います。Angular.js、React はついていけない気がしていて、採用するなら Vue.js かな。。。
- Storybook。聞いただけで何に使うものか実はよく分かっていませんが、どうも便利らしい。
Geb が便利すぎる。。。 ブラウザの画面のテストをするなら MockMvc とかは使わずに Geb で書く方が圧倒的に楽ですね。Geb は Spock を拡張したものなので、Spock で便利と思っている機能(例えばデータテーブルによる Parameterized test)は全て使えますし、Groovy SQL も使えるので、画面の試験と合わせて DB やメールの確認も簡単に書けるんですよね。Spring Boot 2 から JUnit5 がサポートされて JUnit5 の話題が多いですが、自分は Groovy+Spock+Geb から移る気が全然起きないんですよね。。。
H2+Flyway を使うと1プロジェクトで DB 処理まで完結できるサンプルが作れるのは便利でした。今後は基本的にこの組み合わせでサンプルを作りたいと思います。ただし H2 は、Spring Security を導入していると管理画面にアクセスするのに少し手間がかかったり、組込モードの H2 に IntelliJ IDEA や DomaGen からアクセスするのにコツが必要だったりする点が注意ですね。
見返してみると Spring Boot 自体についてはほとんど何もしていませんね。。。 Javascript 開発環境を Spring Boot プロジェクト内に一緒に入れる方法とか、Geb のテスト環境を入れる方法とか、H2+Flyway を使って別に DB サーバを構築しなくても動作確認ができるプロジェクトを作成する方法とかを調べるのが目的だったので。まあ目的は全部達成できて自分としては満足な結果です。以外に全部入れられるものでした。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その72 )( Windows で本番稼働させるためのディレクトリ作成、jar ファイル配置、bat ファイル作成、サービス登録、動作確認 )
概要
記事一覧はこちらです。
参照したサイト・書籍
目次
- application-product.properties に valueshelper.classpath.prefix の設定を追加する
- Windows で本番稼働させるためのディレクトリを作成する
- bat ファイルを作成する
- jar ファイルを作成、配置する
- nssm をダウンロード・配置し、Windows のサービスに登録する
- 動作確認
- Windows のサービスから削除する
- 次回は。。。
手順
application-product.properties に valueshelper.classpath.prefix の設定を追加する
ksbysample.webapp.bootnpmgeb.values.ValuesHelper クラスで使用する valueshelper.classpath.prefix の設定を記述するのを忘れていたので追加します。
src/main/resources/application-product.properties の以下の点を変更します。
.......... spring.mail.host=localhost spring.mail.port=25 valueshelper.classpath.prefix=BOOT-INF.classes.
valueshelper.classpath.prefix=BOOT-INF.classes.
を追加します。
Windows で本番稼働させるためのディレクトリを作成する
実行環境は以下のディレクトリ構成にします。ファイルは後から配置する ( ログファイルは後から作成される ) ので、まずは全てのディレクトリを作成します。
C:\webapps\boot-npm-geb-sample ├ bat │ └ webapp_startup.bat ├ lib │ └ boot-npm-geb-sample-1.0.1-RELEASE.jar ├ logs │ ├ gc.log │ ├ boot-npm-geb-sample.log │ └ slow-query.log ├ nssm │ └ nssm.exe └ work
bat ファイルを作成する
C:\webapps\boot-npm-geb-sample\bat の下に webapp_startup.bat を新規作成し、以下の内容を記述します。
@echo on setlocal set JAVA_HOME=C:\Java\jdk1.8.0_172 set PATH=%JAVA_HOME%\bin;%PATH% set WEBAPP_HOME=C:\webapps\boot-npm-geb-sample set WEBAPP_JAR=boot-npm-geb-sample-1.0.1-RELEASE.jar set LOGS_DIR=%WEBAPP_HOME%\logs set PATH_HEAPDUMPFILE=%LOGS_DIR%\heapdump.hprof set PATH_ERRORFILE=%LOGS_DIR%\hs_err.log cd /d %WEBAPP_HOME% java -server ^ -Xms1024m -Xmx1024m ^ -XX:MaxMetaspaceSize=384m ^ -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled ^ -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=75 ^ -XX:+ScavengeBeforeFullGC -XX:+CMSScavengeBeforeRemark ^ -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps ^ -Xloggc:%WEBAPP_HOME%/logs/gc.log ^ -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=10M ^ -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=%PATH_HEAPDUMPFILE% ^ -XX:+CrashOnOutOfMemoryError ^ -XX:ErrorFile=%PATH_ERRORFILE% ^ -Dfile.encoding=UTF-8 ^ -Djava.net.preferIPv4Stack=true ^ -Dsun.net.inetaddr.ttl=100 ^ -Dsun.nio.cs.map=x-windows-iso2022jp/ISO-2022-JP ^ -Dcom.sun.management.jmxremote ^ -Dcom.sun.management.jmxremote.port=7900 ^ -Dcom.sun.management.jmxremote.ssl=false ^ -Dcom.sun.management.jmxremote.authenticate=false ^ -Dspring.profiles.active=product ^ -jar lib\%WEBAPP_JAR% set YYYYMMDD=%date:~0,4%%date:~5,2%%date:~8,2% set HHMMSS=%time:~0,8% set HHMMSS=%HHMMSS::=% set HHMMSS=%HHMMSS: =% if exist %PATH_HEAPDUMPFILE% rename %PATH_HEAPDUMPFILE% heapdump_%YYYYMMDD%%HHMMSS%.hprof if exist %PATH_ERRORFILE% rename %PATH_ERRORFILE% hs_err_%YYYYMMDD%%HHMMSS%.log
jar ファイルを作成、配置する
clean タスク → Rebuild Project → build タスクを実行します。build/libs の下に boot-npm-geb-sample-1.0.1-RELEASE.jar を作成されますので、C:\webapps\boot-npm-geb-sample\lib の下にコピーします。
nssm をダウンロード・配置し、Windows のサービスに登録する
https://nssm.cc/download のページ内の「Latest release」の「nssm 2.24」リンクをクリックして nssm-2.24.zip をダウンロードします。
nssm-2.24.zip を解凍します。解凍して作成された nssm-2.24\win64 ( 32bit環境の場合には nssm-2.24\win32 ) ディレクトリの下にある nssm.exe を C:\webapps\boot-npm-geb-sample\nssm の下に配置します。
コマンドプロンプトを「管理者として実行...」モードで起動し、以下のコマンドを実行します。
> cd /d C:\webapps\boot-npm-geb-sample\nssm > nssm install boot-npm-geb-sample
「NSSM service installer」画面が表示されます。以下の画像の値を入力した後、「Install service」ボタンをクリックします。サービスの登録に成功すると「Service "ksbysample-webapp-lending" installed successfully!」のダイアログが表示されますので「OK」ボタンをクリックします。
動作確認
最初にメールを送信できるようにするため smtp4dev を起動します。
サービス画面を開きます。サービス一覧から「boot-npm-geb-sample」を選択し、「サービスの開始」リンクをクリックしてサービスを開始します。
C:\webapps\boot-npm-geb-sample\logs の下の boot-npm-geb-sample.log をエディタで開き、最後に "Started Application in ..." のログが出力されていることを確認します。
以下の手順で動作確認します ( 画面キャプチャは省略します )。
- ブラウザを起動して http://localhost:8080/inquiry/input/01/ にアクセスして入力画面1を表示します。
- 入力画面1~3に入力して確認画面を表示します。
- 確認画面から「修正する」ボタンをクリックして入力画面1~3に戻り、入力したデータが表示されること、データを修正して確認画面に戻った場合には修正したデータが反映されることを確認します。
- 確認画面で「送信する」ボタンをクリックして、メールが送信されること、及び完了画面が表示されることを確認します。
Windows のサービスから削除する
サービスを削除します。管理者モードで起動しているコマンドプロンプトから以下のコマンドを実行します。
> nssm remove boot-npm-geb-sample
「Remove the service?」のダイアログが表示されますので、「はい」ボタンをクリックします。サービスが削除されると「Service "boot-npm-geb-sample" removed successfully!」のダイアログが表示されますので「OK」ボタンをクリックします。
次回は。。。
感想を書いた後、この Web アプリを Spring Boot 2 へバージョンアップして、終わりにする予定です。
履歴
2018/07/29
初版発行。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( 番外編 )( gradle-processes を利用して Geb のテスト前に Spring Boot の Web アプリを自動起動する )
概要
記事一覧はこちらです。
- 今回の手順で確認できるのは以下の内容です。
- Geb のテストを実行する前に都度 IntelliJ IDEA から Tomcat を起動するのは手間なので自動で起動できないか調べてみたところ、gradle-processes という Gradle のプラグインを利用して実施している例を見かけました。今回番外編として試してみようと思います。
- 尚、gradle-processes は現時点では Gradle のバージョンが 4.5 以下であることが条件となっており(実際 4.6 以上だと動きません)、今は 4.8.1 までバージョンを上げていて戻すつもりはないので今回変更した内容は commit しません。
参照したサイト・書籍
gradle-processes
https://github.com/johnrengelman/gradle-processesmstine/microservices-pact/build.gradle
https://github.com/mstine/microservices-pact/blob/master/build.gradleHow to use Gradle and Gatling to automate the load tests of a Spring Boot web service
http://brokenrhythm.blog/gradle-gatling-springboot-automation
目次
- gradle のバージョンを 4.5 に変更する
- build.gradle に gradle-processes を追加する
- build.gradle に Web アプリの自動起動、自動停止のタスクを追加する
- 動作確認
手順
gradle のバージョンを 4.5 に変更する
コマンドプロンプトから gradlew wrapper --gradle-version=4.5
を実行して Gradle のバージョンを 4.5 に変更します。
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 です。
1件目をクリックすると以下の画面が表示されます。
2件目をクリックすると以下の画面が表示されます。
また gradle-processes の GitHub のページ を見ると How To Use に以下の記述があります。
以上の内容から、利用するためには以下の設定が必要なことが分かります。
- 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 タスクが実行されないことを確認します。
なぜかこのタイミングで Chrome 68 が Twitter のトレンドにランクインしていたので、バージョンアップします。
次に gebTest タスクを実行します。startServer → chromeTest, firefoxTest → stopServer の順に実行されて、BUILD SUCCESSFUL が表示されました。問題なさそうです。
chromeTest タスクだけを実行してみます。startServer → chromeTest → stopServer の順に実行されて、テストは全て成功しました。
firefoxTest タスクだけを実行してみます。startServer → firefoxTest → stopServer の順に実行されて、テストは全て成功しました。
このプラグイン、便利ですね。GitHub の Issue を見たら現在 4.6 以降に対応中のようです。
履歴
2018/07/25
初版発行。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その72 )( Executable Jar ファイルを作成しても実行できない原因を調査する+気づいた点を修正する )
概要
記事一覧はこちらです。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その71 )( Geb で入力画面1~3→確認画面→完了画面を通したテストを作成する ) の続きです。
- 今回の手順で確認できるのは以下の内容です。
- 実装すべきことが全て完了したので jar ファイルを作成して実行できることを確認しようとしたのですが、なぜか実行できませんでした。原因を調査します。
- 他に何点か気づいた点を修正します。
参照したサイト・書籍
目次
- Executable Jar ファイルを作成しても実行できない原因を調査する
- どのような問題が発生しているのか?
- build.gradle の mainClass を修正して再度実行する
java.lang.ClassNotFoundException: org.springframework.boot.SpringApplication
の原因とは?- build.gradle の dependencies で
implementation
→compile
に戻してみる - Spring Initializr を利用して Spring Boot 2.0.3 のプロジェクトを作って検証する
- Spring Initializr を利用して Spring Boot 1.5.14 のプロジェクトを作って検証する
- 結論
- build.gradle を変更する+動作確認
- 気づいた点を修正する
手順
Executable Jar ファイルを作成しても実行できない原因を調査する
どのような問題が発生しているのか?
clean タスク実行 → Rebuild Project 実行 → build タスクを実行して、build/libs の下に boot-npm-geb-sample-1.0.1-RELEASE.jar を作成します。
コマンドプロンプトから java -Dspring.profiles.active=develop -jar build\libs\boot-npm-geb-sample-1.0.1-RELEASE.jar
を実行すると Exception in thread "main" java.lang.ClassNotFoundException: ksbysample.webapp.lending.Application
というエラーメッセージが出力されて実行できませんでした。Application クラスのパッケージが lending になっているということは、build.gradle を修正するのを忘れていますね。。。
build.gradle の mainClass を修正して再度実行する
build.gradle の以下の点を変更します。
bootRepackage {
mainClass = 'ksbysample.webapp.bootnpmgeb.Application'
}
- bootRepackage の mainClass の設定を
ksbysample.webapp.lending.Application
→ksbysample.webapp.bootnpmgeb.Application
に変更します。
jar ファイルを作成し直してから java -Dspring.profiles.active=develop -jar build\libs\boot-npm-geb-sample-1.0.1-RELEASE.jar
を実行すると、今度は java.lang.ClassNotFoundException: org.springframework.boot.SpringApplication
のエラーメッセージが出力されて実行できません。
java.lang.ClassNotFoundException: org.springframework.boot.SpringApplication
の原因とは?
Spring Boot の jar ファイルが Executable Jar ファイル内に出力されていない? ExecutableJar ファイルの中を見てみると、BOOT-INF の下に lib ディレクトリが存在しないことが分かりました。
boot-npm-geb-sample-1.0.1-RELEASE.jar の BOOT-INF の下を見ると、以下のように lib ディレクトリがありませんが、
java -jar
コマンドで実行できる ksbysample-webapp-lending の ksbysample-webapp-lending-1.5.4-RELEASE.jar を開いてみると、BOOT-INF/lib ディレクトリが存在し、その下に jar ファイルが格納されています。
build.gradle の dependencies で implementation
→ compile
に戻してみる
原因がよく分からなかったのですが、build.gradle を見ていて、そう言えば Spring Boot + npm + Geb で入力フォームを作ってテストする ( その65 )( Gradle を 4.6 → 4.8.1 へ、Checkstyle を 8.8 → 8.11 へ、PMD を 6.4.0 → 6.5.0 へ、error-prone を 2.2.0 → 2.3.1 へバージョンアップする ) で依存関係の記述の仕方を compile
→ implementation
に変更したことを思い出しました。これが原因のような気がします。一旦 compile
に戻してみます。
build.gradle で1つだけ implementation
→ compile
に戻してみます。
dependencies { .......... // 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") implementation("org.springframework.boot:spring-boot-starter-thymeleaf") { exclude group: "org.codehaus.groovy", module: "groovy" }
Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。
jar ファイルを作成し直して開いてみると、今度は BOOT-INF/lib ディレクトリが存在し、その下に jar ファイルが格納されていました。
ということは、Spring Boot Gradle Plugin が implementation
に対応していないということでしょうか。。。
Spring Initializr を利用して Spring Boot 2.0.3 のプロジェクトを作って検証する
Spring Initializr を利用してプロジェクトを作成して、build.gradle に implementation
で記述していると Executable Jar ファイルを作成した時に BOOT-INF/libs を作成してくれるのか否かを検証してみます。まずは 2系の最新バージョンである 2.0.3 から。
IntelliJ IDEA で Spring Initializr を利用してプロジェクトを作成します。
プロジェクトが作成されたら build.gradle を開き、compile
→ implementation
、runtime
→ runtimeOnly
、testCompile
→ testImplementation
に変更します。あと devtools が runtime
で記述されていることに気づきました。あとで反映しましょう。
buildscript { ext { springBootVersion = '2.0.3.RELEASE' } repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } } apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'org.springframework.boot' apply plugin: 'io.spring.dependency-management' group = 'com.example' version = '0.0.1-SNAPSHOT' sourceCompatibility = 1.8 repositories { mavenCentral() } dependencies { implementation('org.springframework.boot:spring-boot-starter-web') runtimeOnly('org.springframework.boot:spring-boot-devtools') testImplementation('org.springframework.boot:spring-boot-starter-test') }
Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新した後、build タスクを実行して jar ファイルを作成します。2系から demo-0.0.1-SNAPSHOT.jar.original って出来なくなったんですね。
作成された jar ファイルを開くと BOOT-INF/lib ディレクトリが存在し、その下に jar ファイルが出力されていますね。。。?
Spring Initializr を利用して Spring Boot 1.5.14 のプロジェクトを作って検証する
1.5.14 のプロジェクトも作成してみます。
IntelliJ IDEA で Spring Initializr を利用してプロジェクトを作成します。
プロジェクトが作成されたら build.gradle を開き、compile
→ implementation
、runtime
→ runtimeOnly
、testCompile
→ testImplementation
に変更します。
buildscript { ext { springBootVersion = '1.5.14.RELEASE' } repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } } apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'org.springframework.boot' group = 'com.example' version = '0.0.1-SNAPSHOT' sourceCompatibility = 1.8 repositories { mavenCentral() } dependencies { implementation('org.springframework.boot:spring-boot-starter-web') runtimeOnly('org.springframework.boot:spring-boot-devtools') testImplementation('org.springframework.boot:spring-boot-starter-test') }
Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新した後、build タスクを実行して jar ファイルを作成します。
作成された jar ファイルを開くと BOOT-INF/lib ディレクトリが存在しませんでした。
結論
- 2系の Spring Boot Gradle Plugin は build.gradle の
implementation
に対応しているが、1系の Spring Boot Gradle Plugin は対応していない。 - 1系で build.gradle の dependencies に
compile
ではなくimplementation
で記述すると、Executable Jar ファイルを作成した時に BOOT-INF/lib ディレクトリが作成されず外部モジュールの jar ファイルが格納されないため、java -jar
コマンドで実行しようとしても実行できない。
build.gradle を変更する+動作確認
build.gradle の dependencies の以下の点を変更します。
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}") }
implementation
→compile
に戻します。compile("org.springframework.boot:spring-boot-devtools")
→runtimeOnly("org.springframework.boot:spring-boot-devtools")
に変更します。
Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。
clean タスク実行 → Rebuild Project 実行 → build タスクを実行して、build/libs の下に boot-npm-geb-sample-1.0.1-RELEASE.jar を作成します。boot-npm-geb-sample-1.0.1-RELEASE.jar を開くと BOOT-INF/lib ディレクトリが存在し jar ファイルが格納されていました。
コマンドプロンプトから java -Dspring.profiles.active=develop -jar build\libs\boot-npm-geb-sample-1.0.1-RELEASE.jar
を実行すると今度は正常に起動できました。
気づいた点を修正する
PowerMockito#verifyStatic(VerificationMode)
が deprecated になっていたので PowerMockito#verifyStatic(Class, VerificationMode)
に変更する
見つけたのは偶然ですが、InquiryInput02FormValidatorTest クラスの "メールアドレスの Validation のテスト"()
テストメソッドで PowerMockito#verifyStatic(VerificationMode)
を呼び出しているところに取り消し線が引かれていました。deprecated になっており、PowerMockito#verifyStatic(Class, VerificationMode)
に変更するよう PowerMockito#verifyStatic(VerificationMode)
の JavaDoc に記述されていましたので、変更します。
src/test/groovy/ksbysample/webapp/bootnpmgeb/web/inquiry/form/InquiryInput02FormValidatorTest.groovy の以下の点を変更します。
@Test void "メールアドレスの Validation のテスト"() { .......... 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") .......... }
PowerMockito.verifyStatic(Mockito.times(1))
→PowerMockito.verifyStatic(EmailValidator, Mockito.times(1))
に変更します。
履歴
2018/07/23
初版発行。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その71 )( Geb で入力画面1~3→確認画面→完了画面を通したテストを作成する )
概要
記事一覧はこちらです。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その70 )( 完了画面を作成する ) の続きです。
- 今回の手順で確認できるのは以下の内容です。
- Geb を利用して、入力画面1~3→確認画面→完了画面を通したテストを作成します。
- テストでは DB のデータやメールの送信内容も確認します。
参照したサイト・書籍
How do I find an element that contains specific text in Selenium Webdriver (Python)?
https://stackoverflow.com/questions/12323403/how-do-i-find-an-element-that-contains-specific-text-in-selenium-webdriver-pythChromeDriver - WebDriver for Chrome - Downloads
https://sites.google.com/a/chromium.org/chromedriver/downloads
目次
- InquiryInput01Page クラスを変更する
- InquiryInput02Page クラスを変更する
- InquiryInput03Page クラスを作成する
- InquiryConfirmPage クラスを作成する
- InquiryCompletePage クラスを作成する
- FormModule クラスを変更する
- inquirymail-body_003.txt を追加する
- InquiryTestSpec クラスに入力画面1~3→確認画面→完了画面を通したテストを追加する
- 動作確認
- 全ての Geb のテストを実行してみる
手順
InquiryInput01Page クラスを変更する
src/test/groovy/geb/page/inquiry/InquiryInput01Page.groovy に今回使用するテストデータを追加します。
class InquiryInput01Page extends Page { .......... static valueList01 = [ "#lastname" : "田中", "#firstname" : "太郎", "#lastkana" : "たなか", "#firstkana" : "たろう", "input[name='sex']": SexValues.MALE.value, "#age" : "30", "#job" : JobValues.EMPLOYEE.value, ] }
static valueList01 = [ ... ]
を追加します。
InquiryInput02Page クラスを変更する
src/test/groovy/geb/page/inquiry/InquiryInput02Page.groovy に今回使用するテストデータを追加します。
class InquiryInput02Page extends Page { .......... static valueList01 = [ "#zipcode1": "100", "#zipcode2": "0005", "#address" : "東京都千代田区飯田橋1-1", "#tel1" : "03", "#tel2" : "1234", "#tel3" : "5678", "#email" : "taro.tanaka@sample.co.jp", ] }
InquiryInput03Page クラスを作成する
src/test/groovy/geb/page/inquiry の下に InquiryInput03Page.groovy を新規作成し、以下の内容を記述します。
package geb.page.inquiry import geb.Page import geb.module.FormModule import ksbysample.webapp.bootnpmgeb.values.Type1Values import ksbysample.webapp.bootnpmgeb.values.Type2Values class InquiryInput03Page extends Page { static url = "/inquiry/input/03" static at = { title == "入力フォーム - 入力画面3" } static content = { form { module FormModule } } static initialValueList = [ "#type1" : "", "input[name='type2']" : null, "#inquiry" : "", "input[name='survey']": null, ] static valueList01 = [ "#type1" : Type1Values.PRODUCT.value, "input[name='type2']" : [ Type2Values.CATALOGUE.value, Type2Values.ESTIMATE.value, Type2Values.OTHER.value, ], "#inquiry" : "これは\nテスト\nです", "input[name='survey']": ["1", "2", "3", "4", "5", "6", "7", "8"], ] }
InquiryConfirmPage クラスを作成する
src/test/groovy/geb/page/inquiry の下に InquiryConfirmPage.groovy を新規作成し、以下の内容を記述します。
package geb.page.inquiry import geb.Page import geb.module.FormModule import ksbysample.webapp.bootnpmgeb.values.JobValues import ksbysample.webapp.bootnpmgeb.values.SexValues import ksbysample.webapp.bootnpmgeb.values.Type1Values import ksbysample.webapp.bootnpmgeb.values.Type2Values import java.util.stream.Collectors class InquiryConfirmPage extends Page { static url = "/inquiry/confirm" static at = { title == "入力フォーム - 確認画面" } static content = { form { module FormModule } } static textList01 = [ "#name" : "田中 太郎", "#kana" : "たなか たろう", "#sex" : SexValues.MALE.text, "#age" : "30 歳", "#job" : JobValues.EMPLOYEE.text, "#zipcode": "〒 100-0005", "#address": "東京都千代田区飯田橋1-1", "#tel" : "03-1234-5678", "#email" : "taro.tanaka@sample.co.jp", "#type1" : Type1Values.PRODUCT.text, "#type2" : [Type2Values.ESTIMATE.text , Type2Values.CATALOGUE.text , Type2Values.OTHER.text].stream() .collect(Collectors.joining("、")), "#inquiry": "これは\nテスト\nです", ] }
InquiryCompletePage クラスを作成する
src/test/groovy/geb/page/inquiry の下に InquiryCompletePage.groovy を新規作成し、以下の内容を記述します。
package geb.page.inquiry import geb.Page import geb.module.FormModule import org.openqa.selenium.By class InquiryCompletePage extends Page { static url = "/inquiry/confirm" static at = { title == "入力フォーム - 完了画面" } static content = { form { module FormModule } btnToInput01 { $(By.xpath("//button[contains(text(), '入力画面へ')]")) } } }
FormModule クラスを変更する
src/test/groovy/geb/module/FormModule.groovy の以下の点を変更します。
class FormModule extends Module { static content = { btnBack { $(".js-btn-back") } btnNext { $(".js-btn-next") } btnConfirm { $(".js-btn-confirm") } btnInput01 { $(".js-btn-input01") } btnSend { $(".js-btn-send") } } .......... /** * セレクタに値がセットされているかを検証する * このメソッドは Spock の then, expect で使用する想定である * * @param valueList 検証するセレクタと値を記述した Map * @return true 固定 */ boolean assertValueList(valueList) { valueList.each { key, value -> if ($(key).first().attr("type") == "radio") { WebElement element = $(key).allElements().find { it.selected } if (element == null) { assert null == value } else { assert element.getAttribute("value") == value } } else if ($(key).first().attr("type") == "checkbox") { value.each { v -> WebElement element = $(key).allElements().find { el -> el.getAttribute("value") == v && el.selected } assert element != null } } else { assert $(key).value() == value } } true } /** * セレクタにテキストがセットされているかを検証する * このメソッドは Spock の then, expect で使用する想定である * * @param textList 検証するセレクタと値を記述した Map * @return true 固定 */ boolean assertTextList(textList) { textList.each { key, value -> assert $(key).text() == value } true } }
static content = { ... }
内に以下のボタンの定義を追加します。- btnConfirm
- btnInput01
- btnSend
- assertValueList メソッド内に
else if ($(key).first().attr("type") == "checkbox") { ... }
の処理を追加します。 - assertTextList メソッドを追加します。
inquirymail-body_003.txt を追加する
メールの本文検証用のファイルを追加します。src/test/resources/ksbysample/webapp/bootnpmgeb/web/inquiry の下に inquirymail-body_003.txt を追加し、以下の内容を記述します。
問い合わせフォームから入力された内容は以下の通りです。 お名前(漢字):田中 太郎 お名前(かな):たなか たろう 性別:男性 年齢:30歳 職業:会社員 郵便番号:〒100-0005 住所:東京都千代田区飯田橋1-1 電話番号:03-1234-5678 メールアドレス:taro.tanaka@sample.co.jp お問い合わせの種類1:製品に関するお問い合わせ お問い合わせの種類2:見積が欲しい、資料が欲しい、その他の問い合わせ お問い合わせの内容: これは テスト です アンケート: ・選択肢1だけ長くしてみる ・選択肢2 ・選択肢3 ・選択肢4 ・選択肢5が少し長い ・選択肢6 ・選択肢7 ・8
InquiryTestSpec クラスに入力画面1~3→確認画面→完了画面を通したテストを追加する
src/test/groovy/geb/gebspec/inquiry/InquiryTestSpec.groovy の以下の点を変更します。
class InquiryTestSpec extends GebSpec { @Rule MailServerResource mailServerResource = new MailServerResource() Sql sql def setup() { // 外部プロセスから接続するので H2 TCP サーバへ接続する sql = Sql.newInstance("jdbc:h2:tcp://localhost:9092/mem:bootnpmgebdb", "sa", "") sql.execute("truncate table INQUIRY_DATA") } def teardown() { sql.close() } .......... def "入力画面1~3→確認画面→完了画面の全ての画面を通す"() { setup: "入力画面1を表示する" to InquiryInput01Page and: "データを入力して次へボタンをクリックし、入力画面2へ遷移する" form.setValueList(valueList01) form.btnNext.click(InquiryInput02Page) and: "データを入力して次へボタンをクリックし、入力画面3へ遷移する" form.setValueList(valueList01) form.btnNext.click(InquiryInput03Page) and: "データを入力して次へボタンをクリックし、確認画面へ遷移する" form.setValueList(valueList01) form.btnConfirm.click(InquiryConfirmPage) and: "確認画面にデータが表示されていることを確認する" form.assertTextList(textList01) $("#survey > ul > li").count(8) $("#survey > ul > li", 0).text() == "選択肢1だけ長くしてみる" $("#survey > ul > li", 7).text() == "8" and: "修正するボタンをクリックし、入力画面1へ戻る" form.btnInput01.click(InquiryInput01Page) form.assertValueList(valueList01) and: "次へボタンをクリックし、入力画面2へ遷移する" form.btnNext.click(InquiryInput02Page) form.assertValueList(valueList01) and: "次へボタンをクリックし、入力画面3へ遷移する" form.btnNext.click(InquiryInput03Page) form.assertValueList(valueList01) and: "次へボタンをクリックし、確認画面へ遷移する" form.btnConfirm.click(InquiryConfirmPage) form.assertTextList(textList01) $("#survey > ul > li").count(8) $("#survey > ul > li", 0).text() == "選択肢1だけ長くしてみる" $("#survey > ul > li", 7).text() == "8" expect: "送信するボタンをクリックし、完了画面へ遷移する" form.btnSend.click(InquiryCompletePage) // INQUIRY_DATA テーブルに1件データが登録されていることを確認する def rows = sql.rows("SELECT * FROM INQUIRY_DATA") rows.size() == 1 rows[0]["lastname"] == "田中" rows[0]["firstname"] == "太郎" rows[0]["lastkana"] == "たなか" rows[0]["firstkana"] == "たろう" rows[0]["sex"] == SexValues.MALE.value rows[0]["age"] == 30 rows[0]["job"] == JobValues.EMPLOYEE.value rows[0]["zipcode1"] == "100" rows[0]["zipcode2"] == "0005" rows[0]["address"] == "東京都千代田区飯田橋1-1" rows[0]["tel1"] == "03" rows[0]["tel2"] == "1234" rows[0]["tel3"] == "5678" rows[0]["email"] == "taro.tanaka@sample.co.jp" rows[0]["type1"] == Type1Values.PRODUCT.value rows[0]["type2"] == [Type2Values.ESTIMATE.value , Type2Values.CATALOGUE.value , Type2Values.OTHER.value].stream() .collect(Collectors.joining(",")) rows[0]["inquiry"].asciiStream.text == "これは\r\nテスト\r\nです" rows[0]["survey"] == "1,2,3,4,5,6,7,8" // メールが1件送信されていることを確認する mailServerResource.messagesCount == 1 MimeMessage message = mailServerResource.firstMessage message.subject == "問い合わせフォームからお問い合わせがありました" message.content == new ClassPathResource("ksbysample/webapp/bootnpmgeb/web/inquiry/inquirymail-body_003.txt").inputStream.text and: "再び入力画面1を表示する" btnToInput01.click(InquiryInput01Page) // 入力したデータは表示されていない form.assertValueList(initialValueList) } }
- 以下のフィールドを追加する。
@Rule MailServerResource mailServerResource = new MailServerResource()
Sql sql
setup()
、teardown()
を追加する。def "入力画面1~3→確認画面→完了画面の全ての画面を通す"() { ... }
を追加する。
動作確認
まずは Firefox でテストします。GebConfig.groovy は以下の設定です。
System.setProperty("webdriver.gecko.driver", "C:/geckodriver/0.19.0/geckodriver.bat") System.setProperty("webdriver.chrome.driver", "C:/chromedriver/2.33/chromedriver.exe") driver = { FirefoxOptions firefoxOptions = new FirefoxOptions() firefoxOptions.setHeadless(true) new FirefoxDriver(firefoxOptions) }
Tomcat を起動した後、src/test/groovy/geb/gebspec/inquiry/InquiryTestSpec.groovy の "入力画面1~3→確認画面→完了画面の全ての画面を通す"()
テストメソッド左側の矢印から Run '入力画面1~3→確認画面→完了画面の...()'
をクリックします。
テストが実行されて成功しました。
次は Chrome でテストするために、GebConfig.groovy を以下のように変更します。
System.setProperty("webdriver.gecko.driver", "C:/geckodriver/0.19.0/geckodriver.bat") System.setProperty("webdriver.chrome.driver", "C:/chromedriver/2.33/chromedriver.exe") driver = { // FirefoxOptions firefoxOptions = new FirefoxOptions() // firefoxOptions.setHeadless(true) // new FirefoxDriver(firefoxOptions) ChromeOptions chromeOptions = new ChromeOptions() chromeOptions.setHeadless(true) new ChromeDriver(chromeOptions) }
Firefox の時と同様に Run '入力画面1~3→確認画面→完了画面の...()'
をクリックすると、テストは実行されましたが今度は失敗しました。入力項目に値がセットできていないようです。
ChromeDrive の Downloads ページ を見ると 2.40 がリリースされていましたので入れ替えます。Supports Chrome v66-68
のようにサポートしている Chrome のバージョンが記載されており、2.33 だと Supports Chrome v60-62
で使用している Chrome とバージョンが合っていませんでした(現時点の Chrome のバージョンは 67)。
ChromeDriver 2.40 のリンクをクリックして、その先にある chromedriver_win32.zip をダウンロードします。ダウンロード後、解凍して作成された chromedriver.exe を C:\chromedriver\2.40 の下に配置します。
GebConfig.groovy の chromedriver.exe のパスを変更してから、
System.setProperty("webdriver.gecko.driver", "C:/geckodriver/0.19.0/geckodriver.bat") System.setProperty("webdriver.chrome.driver", "C:/chromedriver/2.40/chromedriver.exe")
テストを実行すると今度は成功しました。
全ての Geb のテストを実行してみる
今度は Geb の全てのテストを実行してみます。Gradle Tool Window から firefoxTest タスクを実行します。
半数以上失敗しましたね。。。 失敗した原因を確認したところ、以下の内容でした。
- InquiryInput01Page クラスの maxLengthValueList に全ての項目が記述されていないので、値がセットされない入力項目がある。
- InquiryInput01Page クラスの maxLengthValueList で
"#lastkana"
、"#firstkana"
にカナの値が設定されていなかったので、入力チェックエラーが発生していた。
src/test/groovy/geb/page/inquiry/InquiryInput01Page.groovy の maxLengthValueList を以下のように変更します。
static maxLengthValueList = [ "#lastname" : "田" * 20, "#firstname" : "太" * 20, "#lastkana" : "あ" * 20, "#firstkana" : "い" * 20, "input[name='sex']": SexValues.MALE.value, "#age" : "9" * 3, "#job" : JobValues.EMPLOYEE.value, ]
また maxLengthValueList で全ての値をセットするように変更したので、src/test/groovy/geb/gebspec/inquiry/InquiryTestSpec.groovy から以下の記述の行を全て取り除きます。
form.setValue("input[name='sex']", "1")
$("#inquiryInput01Form").sex == "1"
再度 firefoxTest タスクを実行すると今度は全て成功しました。
次に chromeTest タスクを実行してみると、こちらも全て成功しました。
最後に gebTest タスクを実行して全て成功することを確認します。
履歴
2018/07/22
初版発行。
2018/07/22
* Geb のテストのために Spring Boot のアプリを起動しているのは develop profile で unittest profile でないことに気づいたのと、unittest profile でも H2 TCP サーバを起動させると一部のテストが失敗するようになったので、「H2DatabaseConfig クラスを変更し、unittest profile でも H2 TCPサーバを起動させる」を削除しました。