Grails におけるドメインクラスのユニットテスト - Grails標準テストと Easyb プラグイン使用
Grails におけるドメインクラスのユニットテストに関して、Grails 標準テストと Easyb(BDD 用のツール) プラグインを使った 2通りを紹介する。
ドメインクラスのユニットテストを行ううえでのポイントは、実行時にドメインクラスに適用される save(), validate() などのメソッドがそのままでは使えないという事。
これを解決するために GrailsUnitTestCase には以下のようなメソッドが用意されている。(他にも mockFor, mockLogging, mockController, mockTagLib などがある)
- mockDomain : ドメインクラスにモックメソッドを用意(save や validate メソッドが使えるようになる)
- mockForConstraintsTests : 制約条件のみチェックする mockDomain の簡易版(validate メソッドが使えるようになる)
これらのメソッドは、ドメインクラスにモックメソッドを追加してくれるので、ユニットテストで制約条件のチェック等が実施できるようになる。
なお、Easyb プラグインでも上記のメソッドが使用できるので、Easyb 側の特殊な対応は不要となっている。
Easyb プラグインのインストール
まず、Grails で Easyb が実行できるように Easyb 用のプラグインをインストールする。現時点でプラグインは以下の 2種類が用意されているが、今回は easyb-1.1 の方を使用する。
インストールの仕方は以下の通り。
easyb プラグインのインストール(grails-easyb-1.1 の方)
>grails install-plugin easyb
ユニットテスト対象のドメインクラス
テスト対象のドメインクラスの内容は以下。name に対して null とブランクを許可しない制約を定義。
grails-app/domain/sample/User.groovy
package sample class User { String name static constraints = { name(nullable: false, blank: false) } }
Grails標準テストの場合
まずは、一般的な Grails のユニットテストを定義して実行する。User クラスを使用する前に mockForConstraintsTests や mockDomain で User クラスに対するモックメソッドの適用を実施。
test/unit/sample/UserTests.groovy
package sample import grails.test.* class UserTests extends GrailsUnitTestCase { protected void setUp() { super.setUp() } protected void tearDown() { super.tearDown() } //制約のテスト void testConstraints() { mockForConstraintsTests(User) //mockForConstraintsTests の代わりに以下でも可 //mockDomain(User) def user = new User() assertFalse user.validate() assertEquals "nullable", user.errors["name"] user.name = "" assertFalse user.validate() assertEquals "blank", user.errors["name"] user.name = "テスター" assertTrue user.validate() } //永続化のテスト void testPersistence() { mockDomain(User) assertEquals 0, User.count() def user = new User(name: "テスター") user.save() assertEquals 1, User.count() assertEquals "テスター", User.list()[0].name } }
実行
>grails test-app ・・・ ------------------------------------------------------- Running 2 unit tests... Running test sample.UserTests...PASSED Tests Completed in 1750ms ... ------------------------------------------------------- Tests passed: 2 Tests failed: 0 -------------------------------------------------------
Easyb の場合
次に、Easyb のストーリー形式でスペックを定義して実行する。内容的には上記のテストと同じ。
test/unit/sample/UserStory.groovy
package sample scenario "User の名前制約", { given "User オブジェクト", { mockForConstraintsTests(User) //mockForConstraintsTests の代わりに以下でも可 //mockDomain(User) user1 = new User() user2 = new User() user3 = new User() } when "名前を設定", { user2.name = "" user3.name = "テスター" } then "null は許可しない", { user1.validate().shouldBe false user1.errors["name"].shouldBe "nullable" } and "ブランクは許可しない", { user2.validate().shouldBe false user2.errors["name"].shouldBe "blank" } and "'テスター' は許可", { user3.validate().shouldBe true } } scenario "User の永続化", { given "'テスター' User オブジェクト", { mockDomain(User) user = new User(name: "テスター") } when "保存", { saveUser = { user.save() } } then "保存されている", { User.count().shouldBe 0 //save メソッドの実行 saveUser() User.count().shouldBe 1 User.list()[0].name.shouldBe "テスター" } }
実行
>grails easyb-test ・・・ ------------------------------------------------------- Running 1 unit test of framework easyb... before testHelper.runTests() after testHelper.runTests() Tests Completed in 9516ms ... ------------------------------------------------------- Tests passed: 2 Tests failed: 0 -------------------------------------------------------