Spring Boot 1.4.x の Web アプリを 1.5.x へバージョンアップする ( 番外編 )( Groovy + JUnit4 でテストを書いてみる、Groovy SQL を使ってみる )
概要
Groovy でテストを書く場合 Spock を使用していますが、Spring Boot 1.4.x の Web アプリを 1.5.x へバージョンアップする ( 番外編 )( static メソッドをモック化してテストするには? ) で JUnit4 形式でも書けることに気付いたので、Groovy + JUnit4 で書く場合のサンプルを作ってみます。
また Spock をもっと使えるようにしたいと思い、最近以下の本を購入して読んでいるのですが、

- 作者: Konstantinos Kapelonis
- 出版社/メーカー: Manning Pubns Co
- 発売日: 2016/03/27
- メディア: ペーパーバック
- この商品を含むブログを見る

Spock: Up and Running: Writing Expressive Tests in Java and Groovy
- 作者: Rob Fletcher
- 出版社/メーカー: O'Reilly Media
- 発売日: 2017/05/08
- メディア: Kindle版
- この商品を含むブログを見る
Groovy SQL というものがあることを知りました。DbUnit もいいのですが、DB のデータを手軽に確認したい場合には少し手間がかかるので、Groovy SQL を利用して簡単に確認する方法もサンプルに入れてみます。
参照したサイト・書籍
groovy.sql - Class Sql
http://docs.groovy-lang.org/latest/html/api/groovy/sql/Sql.htmlGroovyで楽にSQLを実行してみよう
https://www.slideshare.net/simosako/db-16699219- Groovy SQL の使い方が分かりやすくまとまっていて非常に参考になりました。
目次
- build.gradle を修正して groovy-all を依存関係に追加する
- Java + JUnit4 ではなく Groovy + JUnit4 でテストを書いた時に便利な点とは
- Groovy + JUnit4 + Groovy SQL のサンプルを書いてみる
- Groovy SQL、IntelliJ IDEA + Groovy SQL で書くと便利な点とは
- 最後に
手順
build.gradle を修正して groovy-all を依存関係に追加する
以前コンパイルした時にエラーが出たため build.gradle で groovy-all を除外していたのですが、このままでは groovy SQL が使えませんでした。使えるようにするために groovy-all を依存関係に追加します。
まず dependencies の testCompile("org.spockframework:spock-core:${spockVersion}")
, testCompile("org.spockframework:spock-spring:${spockVersion}")
のところに書いていた { exclude module: "groovy-all" }
を削除します。
dependencies { .......... testCompile("org.spockframework:spock-core:${spockVersion}") testCompile("org.spockframework:spock-spring:${spockVersion}") .......... }
変更した後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。
更新後 clean タスク → Rebuild Project を実行すると以下のエラーが出ます。
以前はこれを見て groovy-all の方を除外してしまったのですが、groovy 方を除外するようにします。コマンドラインから gradlew dependencies
を実行して出力された結果を見ると、org.codehaus.groovy:groovy
を依存関係に入れているのは org.springframework.boot:spring-boot-starter-thymeleaf
でした。
+--- org.springframework.boot:spring-boot-starter-thymeleaf: -> 1.5.4.RELEASE | +--- org.springframework.boot:spring-boot-starter:1.5.4.RELEASE (*) | +--- org.springframework.boot:spring-boot-starter-web:1.5.4.RELEASE (*) | +--- org.thymeleaf:thymeleaf-spring4:2.1.5.RELEASE -> 3.0.6.RELEASE | | +--- org.thymeleaf:thymeleaf:3.0.6.RELEASE | | | +--- ognl:ognl:3.1.12 | | | | \--- org.javassist:javassist:3.20.0-GA -> 3.21.0-GA | | | +--- org.attoparser:attoparser:2.0.4.RELEASE | | | +--- org.unbescape:unbescape:1.1.4.RELEASE | | | \--- org.slf4j:slf4j-api:1.6.6 -> 1.7.25 | | \--- org.slf4j:slf4j-api:1.6.6 -> 1.7.25 | \--- nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect:1.4.0 -> 2.2.2 | +--- nz.net.ultraq.thymeleaf:thymeleaf-expression-processor:1.1.3 | | +--- org.codehaus.groovy:groovy:2.4.6 -> 2.4.11 | | \--- org.thymeleaf:thymeleaf:3.0.0.RELEASE -> 3.0.6.RELEASE (*) | +--- org.codehaus.groovy:groovy:2.4.6 -> 2.4.11 | \--- org.thymeleaf:thymeleaf:3.0.0.RELEASE -> 3.0.6.RELEASE (*)
build.gradle の compile("org.springframework.boot:spring-boot-starter-thymeleaf")
の記述を以下のように変更します。
dependencies { .......... compile("org.springframework.boot:spring-boot-starter-thymeleaf") { exclude group: "org.codehaus.groovy", module: "groovy" } .......... }
変更した後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新してから、clean タスク → Rebuild Project を実行するとエラーが出なくなります。また build タスクをすると “BUILD SUCCESSFUL” が出力されることも確認できます。
Java + JUnit4 ではなく Groovy + JUnit4 でテストを書いた時に便利な点とは
Groovy で書くのでいろいろシンプルになりますが、特に便利と思った点をメモしておきます。
Groovy では .class は不要
Groovy では .class
を書く必要がありません。例えば @RunWith(Enclosed)
, @RunWith(SpringRunner)
のように書けます。
@RunWith(Enclosed) class SampleTest { @RunWith(SpringRunner) @SpringBootTest static class テストクラス { @Test void "Groovy + JUnit4 + Groovy SQL のテストサンプル1"() { } } }
テストメソッド名を “” で囲んで自由に書ける
Java + JUnit4 では使えなかった ‘.’, ‘-’ や半角スペース等が自由に記述できます。
@Test void "テストメソッド名に .,- () 等も使えます"() { }
テストメソッドに throws Exception
の記述が不要
上下のサンプルを見ると分かるように、Java + JUnit4 の時にはテストメソッドに付けていた throws Exception
を書く必要がなくなります。
Spcok でなくてもテストメソッド内で given:
, when:
, then:
や setup:
, expect:
が書ける(単なるコメントとしてだけのようですが)
given:
, when:
, then:
の記述は Spock だから出来るものと思っていたのですが、Groovy + JUnit4 の場合でも問題なく書けます。
@Test void "Groovy + JUnit4 + Groovy SQL のテストサンプル1"() { setup: "データを追加する" expect: "データが追加されているか確認する" }
Spock の時と同様に PowerAssert の分かりやすいレポートが出せる
※実例はこの後に書きます。
Groovy + JUnit4 + Groovy SQL のサンプルを書いてみる
以下のような処理をするテストを2パターン書きます。
- TestDataResource クラスが指定されたテーブルのバックアップを取得した後、用意されたデータをロードします。
- Groovy SQL でテーブルにデータを追加します。
- Groovy SQL でテーブルからデータを取得して検証します。
- TestDataResource クラスがバックアップのデータをリストアします。
package ksbysample.webapp.lending import groovy.sql.Sql import ksbysample.common.test.rule.db.BaseTestData import ksbysample.common.test.rule.db.TestDataResource import org.junit.After import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.experimental.runners.Enclosed import org.junit.runner.RunWith import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.test.context.junit4.SpringRunner import javax.sql.DataSource @RunWith(Enclosed) class SampleTest { // テストクラス内で共通で使用する定数を定義する class TestConst { static def TEST_ROLE_01 = "ROLE_USER" static def TEST_ROLE_02 = "ROLE_ADMIN" } @RunWith(SpringRunner) @SpringBootTest // @BaseTestData は TestDataResource クラスが使用する自作のアノテーション @BaseTestData("testdata/base") static class テストクラス { @Autowired private DataSource dataSource // 自作のテーブルのバックアップ・リストア用クラス @Rule @Autowired public TestDataResource testDataResource Sql sql @Before void setUp() { sql = new Sql(dataSource) } @After void tearDown() { sql.close() } @Test void "Groovy + JUnit4 + Groovy SQL のテストサンプル1"() { setup: "データを追加する" sql.execute("INSERT INTO user_role(role_id, user_id, role) VALUES (?, ?, ?)" , [100, 1, TestConst.TEST_ROLE_01]) expect: "データが追加されているか確認する" def row = sql.firstRow("SELECT * FROM user_role WHERE role_id = 100 AND user_id = 1") assert row.role == "ROLE_USER" } @Test void "Groovy + JUnit4 + Groovy SQL のテストサンプル2"() { setup: "データを3件追加する" sql.withBatch("INSERT INTO user_role(role_id, user_id, role) VALUES (?, ?, ?)") { it.addBatch([100, 6, TestConst.TEST_ROLE_01]) it.addBatch([101, 7, TestConst.TEST_ROLE_01]) it.addBatch([102, 7, TestConst.TEST_ROLE_02]) } expect: "追加されたデータをチェックする(カラムは全て取得するが role カラムだけチェックする)" def rows = sql.rows("SELECT * FROM user_role WHERE user_id IN (6, 7) ORDER BY role_id") assert rows.role == ["ROLE_USER", "ROLE_USER", "ROLE_ADMIN"] and: "追加されたデータをチェックする(role_id, role の2カラムのみ取得してチェックする)" rows = sql.rows("""\ SELECT role_id, role FROM user_role WHERE user_id IN (6, 7) ORDER BY role_id """) assert rows == [[role_id: 100, role: "ROLE_USER"] , [role_id: 101, role: "ROLE_USER"] , [role_id: 102, role: "ROLE_ADMIN"]] } } }
テストを実行すると成功します。
ちなみに assert row.role == "ROLE_USER"
→ assert row.role == "ROLE_xxx"
に変更してテストを失敗させると、Spock の時と同様に PowerAssert の分かりやすいレポートが出力されます。
Groovy SQL、IntelliJ IDEA + Groovy SQL で書くと便利な点とは
SQL 文に IntelliJ IDEA の SQL の Code Style が適用される
上のコードでは分かりませんが、IntelliJ IDEA 上だと下のキャプチャのように SQL 文に IntelliJ IDEA の Code Style が適用されて色付きで表示されます。
適用される Code Style の設定は IntelliJ IDEA の「Settings」ダイアログの中の「Editor」-「Code Style」-「SQL」で設定されているものです。
また Ctrl+Alt+L を押してコードフォーマットすると、一部だけですが適用されます。分かる範囲では、小文字で書いていた SQL 文が大文字に変更されましたが、自動で改行されたり不要なスペースが削除されたりはしませんでした。
例えば以下のように SQL 文を全て小文字で書いていて Ctrl+Alt+L を押すと、
以下のように大文字に変更されます。
なぜかメソッドの引数の SQL 文に、テーブル名、カラム名等の補完が効く
なんでこんなところで SQL 文の補完が有効になるの? と不思議になるくらい補完が効きます。ヒアドキュメントで書いている SQL 文でも有効でした。便利です!
SQL 文を書く時にヒアドキュメントが使える
Groovy で書いているので、文字列にヒアドキュメントが使えます。"""\ ... """
を前後に付ければ改行を入れて SQL 文が記述できます。ただし Ctrl+Alt+L を押してもヒアドキュメントの文字列はフォーマットされないので注意が必要です。
最後に
Spock ではなく JUnit4 で書く場合でも Groovy が便利だし、Groovy SQL も便利すぎます。今後テストは基本 Groovy で書こうと思います。
履歴
2017/06/17
初版発行。
2017/06/21
* テストメソッドに @Test
を付け忘れていたり、戻り値の型を void にしていない箇所を修正しました。
* テストメソッド名を "" で囲んで自由に書ける
を追加しました。
* テストメソッドに throws Exception の記述が不要
を追加しました。