Spockを使ってGrailsのドメインクラスのConstraintsを華麗にテストする
Spockのwikiでも
https://code.google.com/p/grails-spock-examples/wiki/Overview#Testing_constraints
というのが紹介されているのですが、もうちょっとカッチョいい方法が
http://www.christianoestreich.com/2011/11/domain-constraints-grails-spock/
で紹介れていたのでやってみます。
まずSpockの準備
BuildConfig.groovyにspockを追加
plugins { ... test ":spock:0.6" ... }
先のURLではConstraintUnitSpecという形で、Specificationを継承したクラスを作っているのですが、少し趣向を変えてPOJOで書いてみます。
場所は適当なところに。
class ConstraintsUnitTestMixin { void validate(obj, field, error) { assert error def validated = obj.validate() if (error == 'valid') { assert !obj.errors[field] } else { assert !validated assert obj.errors[field] assert error == obj.errors[field] } } }
準備はこれで完了。ではではこんなドメインがあったとします。
class Person { String username Integer age static constraints = { username nullable: false, size: 4..20, unique: true age nullable: true, range: 0..200 } }
でconstraintsのテストはこんな感じになります。
import grails.plugin.spock.UnitSpec import grails.test.mixin.TestFor import grails.test.mixin.TestMixin import org.apache.commons.lang.RandomStringUtils import spock.lang.Unroll @TestFor(Person) @TestMixin([ConstraintsUnitTestMixin]) class PersonSpec extends UnitSpec { def setup() { mockForConstraintsTests(Person, [new Person(username: "yamkazu")]) } @Unroll def "personの#fieldに#valを設定すると#errorとなる"() { when: def obj = new Person("$field": val) then: validate(obj, field, error) where: error | field | val 'nullable' | 'username' | null 'size' | 'username' | "abc" 'valid' | 'username' | "abcd" 'valid' | 'username' | RandomStringUtils.randomAlphabetic(20) 'size' | 'username' | RandomStringUtils.randomAlphabetic(21) 'unique' | 'username' | "yamkazu" 'valid' | 'age' | null 'range' | 'age' | -1 'valid' | 'age' | 0 'valid' | 'age' | 100 'valid' | 'age' | 200 'range' | 'age' | 201 } }
ちょっとだけ解説。
@TestMixinを使って継承しないでvalidateを読み込んでみました。今のところIDEの補完が効かなくなるのが難点ですが、、どうでしょうか。
@Unrollを使うとwhereで食わせる各パラメータがそれぞれ独立したテストとして扱われるみたいです。あと紹介したURLでは
@Unroll({"test person all constraints $field is $error"})
という形でクロージャを使っているのですが、このままだとうまく動きませんでした。今のところ現在の最新で試すと
@Unroll("test person all constraints #field is #error")
とするとうまくいきます。この記事の例でやったように単に@Unrollだけつけてメソッド名に文字列を指定してもOK。
カッチョイイ!