Spring Boot + npm + Geb で入力フォームを作ってテストする ( その26 )( 入力画面2を作成する5 )
概要
記事一覧はこちらです。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その25 )( 入力画面2を作成する4 ) の続きです。
- 今回の手順で確認できるのは以下の内容です。
- 入力画面2の作成
- サーバ側のテストを作成します。長いので2回に分けます。
参照したサイト・書籍
- Verify Static Method Call using PowerMockito 1.6
https://stackoverflow.com/questions/34323909/verify-static-method-call-using-powermockito-1-6
目次
- InquiryInput02Form クラスのテストを作成する
- InquiryInput02FormNotEmptyRule クラスのテストを作成する
- EmailValidator クラスのテストを作成する
- InquiryInput02FormValidator クラスのテストを作成する
手順
InquiryInput02Form クラスのテストを作成する
src/main/java/ksbysample/webapp/bootnpmgeb/web/inquiry/form/InquiryInput02Form.java で Ctrl+Shift+T を押して「Create Test」ダイアログを表示してから、以下の画像の値にした後「OK」ボタンをクリックします。
src/test/groovy/ksbysample/webapp/bootnpmgeb/web/inquiry/form/InquiryInput02FormTest.groovy が新規作成されるので、以下の内容を記述します。
package ksbysample.webapp.bootnpmgeb.web.inquiry.form import spock.lang.Specification import spock.lang.Unroll import javax.validation.ConstraintViolation import javax.validation.Validation class InquiryInput02FormTest extends Specification { def validator def inquiryInput02Form def setup() { validator = Validation.buildDefaultValidatorFactory().getValidator() inquiryInput02Form = new InquiryInput02Form( zipcode1: "102" , zipcode2: "0072" , address: "東京都千代田区飯田橋1-1" , tel1: "03" , tel2: "1234" , tel3: "5678" , email: "taro.tanaka@sample.co.jp") } def "placeholder で表示している例の Bean Validation のテスト"() { when: Set<ConstraintViolation<InquiryInput01Form>> constraintViolations = validator.validate(inquiryInput02Form) then: constraintViolations.size() == 0 } @Unroll def "zipcode1 の Bean Validation のテスト(#zipcode1 --> #size)"() { setup: inquiryInput02Form.zipcode1 = zipcode1 Set<ConstraintViolation<InquiryInput02Form>> constraintViolations = validator.validate(inquiryInput02Form) expect: constraintViolations.size() == size where: zipcode1 || size "" || 0 "1" || 0 "1" * 3 || 0 "1" * 4 || 1 } @Unroll def "zipcode2 の Bean Validation のテスト(#zipcode2 --> #size)"() { setup: inquiryInput02Form.zipcode2 = zipcode2 Set<ConstraintViolation<InquiryInput02Form>> constraintViolations = validator.validate(inquiryInput02Form) expect: constraintViolations.size() == size where: zipcode2 || size "" || 0 "1" || 0 "1" * 4 || 0 "1" * 5 || 1 } @Unroll def "address の Bean Validation のテスト(#address --> #size)"() { setup: inquiryInput02Form.address = address Set<ConstraintViolation<InquiryInput02Form>> constraintViolations = validator.validate(inquiryInput02Form) expect: constraintViolations.size() == size where: address || size "" || 0 "a" || 0 "a" * 256 || 0 "a" * 257 || 1 } @Unroll def "tel1 の Bean Validation のテスト(#tel1 --> #size)"() { setup: inquiryInput02Form.tel1 = tel1 Set<ConstraintViolation<InquiryInput02Form>> constraintViolations = validator.validate(inquiryInput02Form) expect: constraintViolations.size() == size where: tel1 || size "" || 0 "1" || 0 "1" * 5 || 0 "1" * 6 || 1 } @Unroll def "tel2 の Bean Validation のテスト(#tel2 --> #size)"() { setup: inquiryInput02Form.tel2 = tel2 Set<ConstraintViolation<InquiryInput02Form>> constraintViolations = validator.validate(inquiryInput02Form) expect: constraintViolations.size() == size where: tel2 || size "" || 0 "1" || 0 "1" * 4 || 0 "1" * 5 || 1 } @Unroll def "tel3 の Bean Validation のテスト(#tel3 --> #size)"() { setup: inquiryInput02Form.tel3 = tel3 Set<ConstraintViolation<InquiryInput02Form>> constraintViolations = validator.validate(inquiryInput02Form) expect: constraintViolations.size() == size where: tel3 || size "" || 0 "1" || 0 "1" * 4 || 0 "1" * 5 || 1 } @Unroll def "email の Bean Validation のテスト(#email --> #size)"() { setup: inquiryInput02Form.email = email Set<ConstraintViolation<InquiryInput02Form>> constraintViolations = validator.validate(inquiryInput02Form) expect: constraintViolations.size() == size where: email || size "" || 0 "a" || 0 "a" * 256 || 0 "a" * 257 || 1 } }
テストを実行して全て成功することを確認します。
InquiryInput02FormNotEmptyRule クラスのテストを作成する
src/main/java/ksbysample/webapp/bootnpmgeb/web/inquiry/form/InquiryInput02FormNotEmptyRule.java で Ctrl+Shift+T を押して「Create Test」ダイアログを表示してから、以下の画像の値にした後「OK」ボタンをクリックします。
src/test/groovy/ksbysample/webapp/bootnpmgeb/web/inquiry/form/InquiryInput02FormNotEmptyRuleTest.groovy が新規作成されるので、以下の内容を記述します。
package ksbysample.webapp.bootnpmgeb.web.inquiry.form import spock.lang.Specification import spock.lang.Unroll import javax.validation.ConstraintViolation import javax.validation.Validation class InquiryInput02FormNotEmptyRuleTest extends Specification { def validator def inquiryInput02FormNotEmptyRule def setup() { validator = Validation.buildDefaultValidatorFactory().getValidator() inquiryInput02FormNotEmptyRule = new InquiryInput02FormNotEmptyRule( zipcode1: "102" , zipcode2: "0072" , address: "東京都千代田区飯田橋1-1" , tel1: "03" , tel2: "1234" , tel3: "5678" , email: "taro.tanaka@sample.co.jp") } def "placeholder で表示している例の Bean Validation のテスト"() { when: Set<ConstraintViolation<InquiryInput02FormNotEmptyRule>> constraintViolations = validator.validate(inquiryInput02FormNotEmptyRule) then: constraintViolations.size() == 0 } @Unroll def "zipcode1 の NotEmpty のテスト(#zipcode1 --> #size)"() { setup: inquiryInput02FormNotEmptyRule.zipcode1 = zipcode1 Set<ConstraintViolation<InquiryInput02FormNotEmptyRule>> constraintViolations = validator.validate(inquiryInput02FormNotEmptyRule) expect: constraintViolations.size() == size where: zipcode1 || size "" || 1 "1" || 0 } @Unroll def "zipcode2 の NotEmpty のテスト(#zipcode2 --> #size)"() { setup: inquiryInput02FormNotEmptyRule.zipcode2 = zipcode2 Set<ConstraintViolation<InquiryInput02FormNotEmptyRule>> constraintViolations = validator.validate(inquiryInput02FormNotEmptyRule) expect: constraintViolations.size() == size where: zipcode2 || size "" || 1 "1" || 0 } @Unroll def "address の NotEmpty のテスト(#address --> #size)"() { setup: inquiryInput02FormNotEmptyRule.address = address Set<ConstraintViolation<InquiryInput02FormNotEmptyRule>> constraintViolations = validator.validate(inquiryInput02FormNotEmptyRule) expect: constraintViolations.size() == size where: address || size "" || 1 "a" || 0 } }
テストを実行して全て成功することを確認します。
EmailValidator クラスのテストを作成する
src/main/java/ksbysample/webapp/bootnpmgeb/util/validator/EmailValidator.java で Ctrl+Shift+T を押して「Create Test」ダイアロ グを表示してから、以下の画像の値にした後「OK」ボタンをクリックします。
src/test/groovy/ksbysample/webapp/bootnpmgeb/util/validator/EmailValidatorTest.groovy が新規作成されるので、以下の内容を記述します。
package ksbysample.webapp.bootnpmgeb.util.validator import spock.lang.Specification import spock.lang.Unroll class EmailValidatorTest extends Specification { @Unroll def "メールアドレスの Validation のテスト(#email --> #result)"() { expect: EmailValidator.validate(email) == result where: email || result "" || true "@" || false "a@" || false "@b" || false "a@b" || true "@@" || false "a@@b" || false "a@b@c" || false // ASCII文字だけなので OK "taro.tanaka@sample.co.jp" || true "1234567890@1234567890" || true "ABCDEFGHOJKLMNOPQRSTUVWXYZ@ABCDEFGHOJKLMNOPQRSTUVWXYZ" || true "abcdefghojklmnopqrstuvwxyz@abcdefghojklmnopqrstuvwxyz" || true "!\"#\$%&'()*+,-./:;<=>?[\\]^_`{|}~@!\"#\$%&'()*+,-./:;<=>?[\\]^_`{|}~" || true // スペースがあるので NG "taro tanaka@sample.co.jp" || false "taro.tanaka@sample co.jp" || false // 非ASCII文字があるので NG "田中太郎@sample.co.jp" || false "taro.tanaka@サンプル co.jp" || false } }
テストを実行して全て成功することを確認します。
InquiryInput02FormValidator クラスのテストを作成する
src/main/java/ksbysample/webapp/bootnpmgeb/web/inquiry/form/InquiryInput02FormValidator.java で Ctrl+Shift+T を押して「Create Test」ダイアログを表示してから、以下の画像の値にした後「OK」ボタンをクリックします。
src/test/groovy/ksbysample/webapp/bootnpmgeb/web/inquiry/form/InquiryInput02FormValidatorTest.groovy が新規作成されるので、以下の内容を記述します。メールアドレスの入力チェックについては
package ksbysample.webapp.bootnpmgeb.web.inquiry.form import ksbysample.common.test.helper.TestHelper import ksbysample.webapp.bootnpmgeb.util.validator.EmailValidator import org.junit.Before import org.junit.Test import org.junit.experimental.runners.Enclosed import org.junit.runner.RunWith import org.mockito.Mockito import org.powermock.api.mockito.PowerMockito import org.powermock.core.classloader.annotations.PowerMockIgnore import org.powermock.core.classloader.annotations.PrepareForTest import org.powermock.modules.junit4.PowerMockRunner import org.powermock.modules.junit4.PowerMockRunnerDelegate import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.test.context.junit4.SpringRunner import org.springframework.validation.Errors import spock.lang.Specification import spock.lang.Unroll @RunWith(Enclosed) class InquiryInput02FormValidatorTest { @SpringBootTest static class InquiryInput02FormValidator_メールアドレス以外 extends Specification { @Autowired private InquiryInput02FormValidator input02FormValidator Errors errors InquiryInput02Form inquiryInput02Form def setup() { errors = TestHelper.createErrors() inquiryInput02Form = new InquiryInput02Form( zipcode1: "102" , zipcode2: "0072" , address: "東京都千代田区飯田橋1-1" , tel1: "03" , tel2: "1234" , tel3: "5678" , email: "taro.tanaka@sample.co.jp") } def "placeholder で表示している例の Bean Validation のテスト"() { setup: input02FormValidator.validate(inquiryInput02Form, errors) expect: errors.hasErrors() == false } @Unroll def "郵便番号の Validation のテスト(#zipcode1,#zipcode2 --> #hasErrors,#size)"() { setup: inquiryInput02Form.zipcode1 = zipcode1 inquiryInput02Form.zipcode2 = zipcode2 expect: input02FormValidator.validate(inquiryInput02Form, errors) errors.hasErrors() == hasErrors errors.getAllErrors().size() == size where: zipcode1 | zipcode2 || hasErrors | size "" | "" || false | 0 "999" | "" || true | 1 "" | "9999" || true | 1 "999" | "9999" || false | 0 } @Unroll def "電話番号の Validation のテスト(#tel1,#tel2,#tel3 --> #hasErrors,#size)"() { given: inquiryInput02Form.tel1 = tel1 inquiryInput02Form.tel2 = tel2 inquiryInput02Form.tel3 = tel3 inquiryInput02Form.email = email when: input02FormValidator.validate(inquiryInput02Form, errors) then: errors.hasErrors() == hasErrors errors.getAllErrors().size() == size // メールアドレスのチェックは行われていないことをチェックする 0 * EmailValidator.validate(email) where: tel1 | tel2 | tel3 | email || hasErrors | size "" | "" | "" | "" || true | 1 "03" | "" | "" | "" || true | 1 "" | "1234" | "" | "" || true | 1 "" | "" | "5678" | "" || true | 1 "03" | "1234" | "5678" | "" || false | 0 "3" | "1234" | "5678" | "" || true | 1 "03" | "123" | "5678" | "" || true | 1 "03123" | "4" | "5678" | "" || false | 0 "03" | "1234" | "567" | "" || true | 1 } } @RunWith(PowerMockRunner) @PowerMockRunnerDelegate(SpringRunner) @SpringBootTest @PrepareForTest(EmailValidator) @PowerMockIgnore("javax.management.*") static class InquiryInput02FormValidator_メールアドレス { @Autowired private InquiryInput02FormValidator input02FormValidator Errors errors InquiryInput02Form inquiryInput02Form @Before void setup() { errors = TestHelper.createErrors() inquiryInput02Form = new InquiryInput02Form( zipcode1: "102" , zipcode2: "0072" , address: "東京都千代田区飯田橋1-1" , tel1: "" , tel2: "" , tel3: "" , email: "taro.tanaka@sample.co.jp") } @Test void "メールアドレスの Validation のテスト"() { when: "EmailValidator.validate が true を返すように設定してテストする" PowerMockito.mockStatic(EmailValidator) PowerMockito.when(EmailValidator.validate(Mockito.any())) thenReturn(true) input02FormValidator.validate(inquiryInput02Form, errors) then: "入力チェックエラーは発生しない" assert errors.hasErrors() == false assert errors.getAllErrors().size() == 0 // EmailValidator.validate が呼び出されていることをチェックする PowerMockito.verifyStatic(Mockito.times(1)) EmailValidator.validate("taro.tanaka@sample.co.jp") and: "EmailValidator.validate が false を返すように設定してテストする" PowerMockito.when(EmailValidator.validate(Mockito.any())) thenReturn(false) input02FormValidator.validate(inquiryInput02Form, errors) then: "入力チェックエラーが発生する" assert errors.hasErrors() == true assert errors.getAllErrors().size() == 1 } } }
テストを実行して全て成功することを確認します。。。が、1つ失敗しました。電話番号、メールアドレスが全て空の場合に入力チェックが OK になってしまうようです。
src/main/assets/js/inquiry/input02.js と src/main/java/ksbysample/webapp/bootnpmgeb/web/inquiry/form/InquiryInput02FormValidator.java で最初の方の処理が一致していないことが原因でした。InquiryInput02FormValidator クラスの方も ignoreCheckRequired のようなものを入れる必要がありますね。。。
var validateFunction = function () { if (validator.ignoreCheckRequired && form.isAllEmpty(idList)) { return; } if (form.isAllEmpty(idList)) { var errmsg = "電話番号とメールアドレスのいずれか一方を入力してください"; form.setError(telIdFormGroup, errmsg); form.setError(emailIdFormGroup, errmsg); throw new Error(errmsg); } else {
if (StringUtils.isEmpty(tel1) && StringUtils.isEmpty(tel2) && StringUtils.isEmpty(tel3) && StringUtils.isEmpty(email)) { return; } if (StringUtils.isEmpty(tel1 + tel2 + tel3) && StringUtils.isEmpty(email)) { errors.reject("InquiryInput02Form.telOrEmail.NotEmpty"); } else {
以下の内容で修正することにします。
- input02.html に
<input type="hidden" name="ignoreCheckRequired" ... />
を追加します。 - input02 で必須チェック不要な時には
<input type="hidden" name="ignoreCheckRequired" ... />
にも true をセットします。 - InquiryInput02Form クラスに ignoreCheckRequired を用意します。
- InquiryInput02FormValidator で InquiryInput02Form.ignoreCheckRequired == true なら一番最初の必須チェックは行わないようにします。
src/main/resources/templates/web/inquiry/input02.html の以下の点を変更します。
<!--/*@thymesVar id="inquiryInput02Form" type="ksbysample.webapp.bootnpmgeb.web.inquiry.form.InquiryInput02Form"*/--> <form id="inquiryInput02Form" class="form-horizontal" method="post" action="" th:action="@{/inquiry/input/02/}" th:object="${inquiryInput02Form}"> <input type="hidden" name="copiedFromSession" id="copiedFromSession" th:value="*{copiedFromSession}"/> <input type="hidden" name="ignoreCheckRequired" id="ignoreCheckRequired" value="false"/>
<input type="hidden" name="ignoreCheckRequired" id="ignoreCheckRequired" value="false"/>
を追加します。value は固定でfalse
にします。
src/main/assets/js/inquiry/input02.js の以下の点を変更します。
var btnBackOrNextClickHandler = function (event, url, ignoreCheckRequired) { .......... // サーバにリクエストを送信する $("#ignoreCheckRequired").val(ignoreCheckRequired); $("#inquiryInput02Form").attr("action", url); $("#inquiryInput02Form").submit(); // return false は // event.preventDefault() + event.stopPropagation() らしい return false; };
- btnBackOrNextClickHandler 関数の以下の点を変更します。
$("#ignoreCheckRequired").val(ignoreCheckRequired);
を追加します。
src/main/java/ksbysample/webapp/bootnpmgeb/web/inquiry/form/InquiryInput02Form.java の以下の点を変更します。
@Data public class InquiryInput02Form implements Serializable { .......... private boolean ignoreCheckRequired = false; }
private boolean ignoreCheckRequired = false;
を追加します。
src/main/java/ksbysample/webapp/bootnpmgeb/web/inquiry/form/InquiryInput02FormValidator.java の以下の点を変更します。
@Component public class InquiryInput02FormValidator implements Validator { .......... @Override public void validate(Object target, Errors errors) { .......... checkTelAndEmail(inquiryInput02Form.isIgnoreCheckRequired() , inquiryInput02Form.getTel1() , inquiryInput02Form.getTel2() , inquiryInput02Form.getTel3() , inquiryInput02Form.getEmail() , errors); } .......... @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.ConfusingTernary"}) private void checkTelAndEmail(boolean ignoreCheckRequired, String tel1, String tel2, String tel3, String email, Errors errors) { if (ignoreCheckRequired && StringUtils.isEmpty(tel1) && StringUtils.isEmpty(tel2) && StringUtils.isEmpty(tel3) && StringUtils.isEmpty(email)) { return; } .......... } }
- checkTelAndEmail メソッドの以下の点を変更します。
- 引数に
boolean ignoreCheckRequired
を追加します。 - 最初の if 文に
ignoreCheckRequired
の条件を追加します。
- 引数に
- validate メソッド内で checkTelAndEmail メソッドを呼び出している部分の引数に
inquiryInput02Form.isIgnoreCheckRequired()
を追加します。
画面を動かして動作に問題がないことを確認した後(画面キャプチャは省略します)、src/test/groovy/ksbysample/webapp/bootnpmgeb/web/inquiry/form/InquiryInput02FormValidatorTest.groovy の以下の点を変更します。
@SpringBootTest static class InquiryInput02FormValidator_メールアドレス以外 extends Specification { .......... @Unroll def "電話番号の Validation のテスト(#tel1,#tel2,#tel3,#ignoreCheckRequired --> #hasErrors,#size)"() { given: inquiryInput02Form.tel1 = tel1 inquiryInput02Form.tel2 = tel2 inquiryInput02Form.tel3 = tel3 inquiryInput02Form.email = email inquiryInput02Form.ignoreCheckRequired = ignoreCheckRequired when: input02FormValidator.validate(inquiryInput02Form, errors) then: errors.hasErrors() == hasErrors errors.getAllErrors().size() == size // メールアドレスのチェックは行われていないことをチェックする 0 * EmailValidator.validate(email) where: tel1 | tel2 | tel3 | email | ignoreCheckRequired || hasErrors | size "" | "" | "" | "" | false || true | 1 "" | "" | "" | "" | true || false | 0 "03" | "" | "" | "" | false || true | 1 "" | "1234" | "" | "" | false || true | 1 "" | "" | "5678" | "" | false || true | 1 "03" | "1234" | "5678" | "" | false || false | 0 "3" | "1234" | "5678" | "" | false || true | 1 "03" | "123" | "5678" | "" | false || true | 1 "03123" | "4" | "5678" | "" | false || false | 0 "03" | "1234" | "567" | "" | false || true | 1 } }
InquiryInput02FormValidator_メールアドレス以外
クラスの以下の点を変更します。電話番号の Validation のテスト
メソッドのメソッド名に,#ignoreCheckRequired
を追加します。given:
のところで、inquiryInput02Form.ignoreCheckRequired = ignoreCheckRequired
を追加します。where:
にignoreCheckRequired
を追加しテスト用の値も記述します。
テストを実行すると今度は全て成功しました。
履歴
2017/10/15
初版発行。