はじめに
- validatorにはmodelにアノテーションつけるだけで良くね的なチェックもありますが気にせずに。。。
- 近いうちにSpockで実装する記事を書く!。。。かも。
サンプルvalidator
公式より拝借。ちょっとだけ変える。
9.2 Validation using Spring’s Validator interface
PersonValidator.java
public class PersonValidator implements Validator {
public boolean supports(Class clazz) {
return Person.class.equals(clazz);
}
public void validate(Object obj, Errors e) {
Person p = (Person) obj;
if (p.getAge() < 0) {
e.rejectValue("age", "negativevalue");
} else if (p.getAge() > 110) {
e.rejectValue("age", "too.darn.old");
}
ValidationUtils.rejectIfEmpty(e, "name", "name.empty");
if(!e.hasErrror()) {
if(p.getName.length() <= MAX_CHARS) {
e.rejectValue("name", "error.entry.tooManyChars");
}
}
}
}
実装
基底クラス。
PersonValidatorTestBase.java
public class PersonValidatorTestBase {
protected Person target;
protected DataBinder binder;
@Before
public void 事前処理() {
// target正常値初期化
target = new Person();
target.setAge(10);
target.setName("valid name");
// bind
binder = new DataBinder(target);
binder.setValidator(new PersonValidator());
}
}
実装クラス。
ちょっと1つのテストが2つのメソッドに分かれちゃってるのがよくないかな。。まぁ雰囲気つかむのが目的ということで。
PersonValidatorTest.java
@RunWith(Enclosed.class) //--(1)
public class PersonValidatorTest {
@RunWith(Theories.class) //--(2)
public static class 年齢テスト extends PersonValidatorTestBase {
@DataPoints("ok") //--(3)
public static MutablePropertyValues[] mpvArrOk = {
new MutablePropertyValues()
.add("age" , 0)
.add("description" , "年齢のOK境界値MIN"),
new MutablePropertyValues()
.add("age" , 110)
.add("description" , "年齢のOK境界値MAX")
};
@DataPoints("ng")
public static MutablePropertyValues[] mpvArrNg = {
new MutablePropertyValues()
.add("age" , -1)
.add("description" , "年齢がマイナステスト")
.add("errCode" , "negativevalue"),
new MutablePropertyValues()
.add("age" , 111)
.add("description" , "年齢行き過ぎテスト")
.add("errCode" , "too.darn.old")
};
@Theory //--(4)
public void アプリ相関チェック_正常系(@FromDataPoints("ok") MutablePropertyValues mpv) {
binder.bind(mpv); //--(5)
binder.validate();
BindingResult br = binder.getBindingResult();
assertThat(br.hasErrors())
.as((String)mpv.get("description"))
.isFalse();
}
@Theory
public void アプリ相関チェック_異常系(@FromDataPoints("ng") MutablePropertyValues mpv) {
binder.bind(mpv);
binder.validate();
// descriptionとerrCodeはちょっと強引
BindingResult br = binder.getBindingResult();
assertThat(br.getFieldError("age").getCode())
.as((String)mpv.get("description"))
.isEqualTo((String)mpv.get("errCode"));
}
}
@RunWith(Theories.class)
public static class 名前テスト extends PersonValidatorTestBase {
// 省略
}
}
(1) Enclosed.class
- テスト項目ごとに階層を分けるためのランナー
(2) Theories.class
- DataPointsなどを使用するためのランナー
(3) @DataPoints(名前)
- ここで指定した配列分だけテストが繰り返される
- テスト対象の「フィールド名, 値」でaddしていく
- フィールドとして定義されていないものもaddできる
※今回はdescriptionとadd。これに関してはもっといいやり方知りたい。
(4) @Theory
- DataPoints使うためのアノテーション。
- 引数にDataPointsとして定義した型の変数を指定
(5) DataBinder.bind
- bindによってテスト対象のモデルに値が代入される