Spring Boot + npm + Geb で入力フォームを作ってテストする ( その21 )( 入力画面1を作成する5 )
概要
記事一覧はこちらです。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その20 )( 入力画面1を作成する4 ) の続きです。
- 今回の手順で確認できるのは以下の内容です。
- 入力画面1の作成
- サーバ側のテストを作成します。
参照したサイト・書籍
- Learning Ant path style
https://stackoverflow.com/questions/2952196/learning-ant-path-style
目次
- InquiryInput01Form クラスのテストを作成する
- ksbysample-webapp-lending から TestHelper, HtmlResultMatchers クラスをコピーする
- HtmlResultMatchers クラスに val メソッドを追加する
- テストデータを用意する
- InquiryInputController クラスのテストを作成する
- 次回は。。。
手順
InquiryInput01Form クラスのテストを作成する
src/main/java/ksbysample/webapp/bootnpmgeb/web/inquiry/form/InquiryInput01Form.java で Ctrl+Shift+T を押して「Create Test」ダイアログを表示してから、以下の画像の値にした後「OK」ボタンをクリックします。
src/test/groovy/ksbysample/webapp/bootnpmgeb/web/inquiry/form/InquiryInput01FormTest.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 InquiryInput01FormTest extends Specification { def validator def inquiryInput01Form def setup() { validator = Validation.buildDefaultValidatorFactory().getValidator() inquiryInput01Form = new InquiryInput01Form( lastname: "田中" , firstname: "太郎" , lastkana: "たなか" , firstkana: "たろう" , sex: "1" , age: "30" , job: "1") } def "placeholder で表示している例の Bean Validation のテスト"() { when: Set<ConstraintViolation<InquiryInput01Form>> constraintViolations = validator.validate(inquiryInput01Form) then: constraintViolations.size() == 0 } @Unroll def "lastname の Bean Validation の Bean Validation のテスト(#lastname --> #size)"() { setup: inquiryInput01Form.lastname = lastname Set<ConstraintViolation<InquiryInput01Form>> constraintViolations = validator.validate(inquiryInput01Form) expect: constraintViolations.size() == size where: lastname || size "" || 2 "a" || 0 "a" * 20 || 0 "a" * 21 || 1 } @Unroll def "firstname の Bean Validation のテスト(#firstname --> #size)"() { setup: inquiryInput01Form.firstname = firstname Set<ConstraintViolation<InquiryInput01Form>> constraintViolations = validator.validate(inquiryInput01Form) expect: constraintViolations.size() == size where: firstname || size "" || 2 "a" || 0 "a" * 20 || 0 "a" * 21 || 1 } @Unroll def "lastkana の Bean Validation のテスト(#lastkana --> #size)"() { setup: inquiryInput01Form.lastkana = lastkana Set<ConstraintViolation<InquiryInput01Form>> constraintViolations = validator.validate(inquiryInput01Form) expect: constraintViolations.size() == size where: lastkana || size "" || 3 "a" || 1 "a" * 20 || 1 "a" * 21 || 2 "あ" || 0 "あ" * 20 || 0 "あ" * 21 || 1 "ア" || 1 "A" || 1 "1" || 1 "あa" || 1 } @Unroll def "firstkana の Bean Validation のテスト(#firstkana --> #size)"() { setup: inquiryInput01Form.firstkana = firstkana Set<ConstraintViolation<InquiryInput01Form>> constraintViolations = validator.validate(inquiryInput01Form) expect: constraintViolations.size() == size where: firstkana || size "" || 3 "a" || 1 "a" * 20 || 1 "a" * 21 || 2 "あ" || 0 "あ" * 20 || 0 "あ" * 21 || 1 "ア" || 1 "A" || 1 "1" || 1 "あa" || 1 } @Unroll def "sex の Bean Validation のテスト(#sex --> #size)"() { setup: inquiryInput01Form.sex = sex Set<ConstraintViolation<InquiryInput01Form>> constraintViolations = validator.validate(inquiryInput01Form) expect: constraintViolations.size() == size where: sex || size "" || 1 "0" || 1 "1" || 0 "2" || 0 "3" || 1 } @Unroll def "age の Bean Validation のテスト(#age --> #size)"() { setup: inquiryInput01Form.age = age Set<ConstraintViolation<InquiryInput01Form>> constraintViolations = validator.validate(inquiryInput01Form) expect: constraintViolations.size() == size where: age || size "" || 2 "0" || 0 "1" || 0 "999" || 0 "1000" || 1 "0.1" || 1 } @Unroll def "job の Bean Validation のテスト(#job --> #size)"() { setup: inquiryInput01Form.job = job Set<ConstraintViolation<InquiryInput01Form>> constraintViolations = validator.validate(inquiryInput01Form) expect: constraintViolations.size() == size where: job || size "" || 0 "0" || 1 "1" || 0 "2" || 0 "3" || 0 "4" || 1 } }
テストを実行して全て成功することを確認します。
ksbysample-webapp-lending から TestHelper, HtmlResultMatchers クラスをコピーする
テストに使用したいので、ksbysample-webapp-lending から TestHelper, HtmlResultMatchers クラスをコピーします。
src/test/java の下に ksbysample.common.test.helper パッケージを作成します。
src/test/java/ksbysample/common/test/helper の下に TestHelper.java をコピーします。
src/test/java/ksbysample/common/test の下に matcher パッケージを作成します。
src/test/java/ksbysample/common/test/matcher の下に HtmlResultMatchers.java をコピーします。
HtmlResultMatchers クラスは jsoup が必要なので導入します。build.gradle の以下の点を変更します。
dependencies { .......... // dependency-management-plugin によりバージョン番号が自動で設定されないもの、あるいは最新バージョンを指定したいもの .......... testCompile("com.google.code.findbugs:jsr305:3.0.2") testCompile("org.jsoup:jsoup:1.10.3") .......... }
testCompile("org.jsoup:jsoup:1.10.3")
を追加します。
変更後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。
HtmlResultMatchers クラスに val メソッドを追加する
今回のテストでは value 属性の値をチェックしたいのですが、今の HtmlResultMatchers クラスには value 属性を検証するためのメソッドが用意されていないので追加します。
src/test/java/ksbysample/common/test/matcher/HtmlResultMatchers.java の以下の点を変更します。
public class HtmlResultMatchers { .......... public ResultMatcher text(final String expectedText) { return mvcResult -> assertThat(selectFirst(mvcResult).text(), is(expectedText)); } /** * HTML 内の cssQuery で指定された Element の value 属性の値を取得し、 * 引数で渡された文字列と同じかチェックする * * @param expectedText 文字列の期待値 * @return {@link ResultMatcher} */ public ResultMatcher val(final String expectedText) { return mvcResult -> assertThat(selectFirst(mvcResult).val(), is(expectedText)); } .......... }
val
メソッドを追加します。
テストデータを用意する
src/test/resources の下に ksbysample/webapp/bootnpmgeb/web/inquiry ディレクトリを新規作成します。
src/test/resources/ksbysample/webapp/bootnpmgeb/web/inquiry の下に InquiryInput01Form_001.yaml を新規作成し、以下の内容を記述します。
!!ksbysample.webapp.bootnpmgeb.web.inquiry.form.InquiryInput01Form # 最大文字数のデータ、選択肢の場合には一番最後のデータをセットする lastname: 12345678901234567890 firstname: 12345678901234567890 lastkana: あいうえおかきくけこさしすせそたちつてと firstkana: なにぬねのはひふへほまみむめもあいうえお sex: 2 age: 999 job: 3
InquiryInputController クラスのテストを作成する
src/main/java/ksbysample/webapp/bootnpmgeb/web/inquiry/InquiryInputController.java で Ctrl+Shift+T を押して「Create Test」ダイアログを表示してから、以下の画像の値にした後「OK」ボタンをクリックします。
MockMvc を使用するので Groovy + Spock ではなく Groovy + JUnit4 で作成するのですが、「Create Test」ダイアログで JUnit4 を選択すると拡張子が .java になってしまうので、Spock を選択してファイルを生成してから中身を Groovy + JUnit4 に変更します。
src/test/groovy/ksbysample/webapp/bootnpmgeb/web/inquiry/InquiryInputControllerTest.groovy が新規作成されるので、以下の内容を記述します。
package ksbysample.webapp.bootnpmgeb.web.inquiry import ksbysample.common.test.helper.TestHelper import ksbysample.webapp.bootnpmgeb.web.inquiry.form.InquiryInput01Form import org.junit.Before 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.mock.web.MockHttpSession import org.springframework.test.context.junit4.SpringRunner import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.MvcResult import org.springframework.test.web.servlet.setup.MockMvcBuilders import org.springframework.web.context.WebApplicationContext import org.yaml.snakeyaml.Yaml import static ksbysample.common.test.matcher.HtmlResultMatchers.html import static org.assertj.core.api.Assertions.catchThrowable import static org.assertj.core.api.AssertionsForClassTypes.assertThat import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrlPattern import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status @RunWith(Enclosed) class InquiryInputControllerTest { @RunWith(SpringRunner) @SpringBootTest static class 入力画面1のテスト { private InquiryInput01Form inquiryInput01Form_001 = (InquiryInput01Form) new Yaml().load(getClass().getResourceAsStream("InquiryInput01Form_001.yaml")) @Autowired private WebApplicationContext context MockMvc mockMvc @Before void setup() { mockMvc = MockMvcBuilders.webAppContextSetup(context) .build() } @Test void "初期表示時は画面の項目には何もセットされない"() { expect: mockMvc.perform(get("/inquiry/input/01")) .andExpect(status().isOk()) .andExpect(html("#lastname").val("")) .andExpect(html("#firstname").val("")) .andExpect(html("#lastkana").val("")) .andExpect(html("#firstkana").val("")) .andExpect(html("input[name='sex'][checked='checked']").notExists()) .andExpect(html("#age").val("")) .andExpect(html("select[name=job] option[selected]").notExists()) } @Test void "項目全てに入力して入力画面2へ遷移してから戻ると以前入力したデータがセットされて表示される"() { expect: "項目全てに入力して「次へ」ボタンをクリックする" MvcResult result = mockMvc.perform( TestHelper.postForm("/inquiry/input/01?move=next", inquiryInput01Form_001)) .andExpect(status().isFound()) .andExpect(redirectedUrlPattern("**/inquiry/input/02")) .andReturn() MockHttpSession session = result.getRequest().getSession() and: "再び入力画面1を表示する" mockMvc.perform(get("/inquiry/input/01").session(session)) .andExpect(status().isOk()) .andExpect(html("#lastname").val(inquiryInput01Form_001.lastname)) .andExpect(html("#firstname").val(inquiryInput01Form_001.firstname)) .andExpect(html("#lastkana").val(inquiryInput01Form_001.lastkana)) .andExpect(html("#firstkana").val(inquiryInput01Form_001.firstkana)) .andExpect(html("input[name='sex'][checked='checked']").val(inquiryInput01Form_001.sex)) .andExpect(html("#age").val(inquiryInput01Form_001.age)) .andExpect(html("select[name=job] option[selected]").val(inquiryInput01Form_001.job)) } @Test void "入力チェックエラーのあるデータで入力画面2へ遷移しようとするとIllegalArgumentExceptionが発生する"() { setup: "入力チェックエラーになるデータを用意する" inquiryInput01Form_001.lastname = "x" * 21 expect: "入力画面1の「次へ」ボタンをクリックする" Throwable thrown = catchThrowable({ mockMvc.perform( TestHelper.postForm("/inquiry/input/01?move=next", inquiryInput01Form_001)) .andExpect(status().isOk()) }) assertThat(thrown.cause).isInstanceOf(IllegalArgumentException) } } }
テストを実行して全て成功することを確認します。
次回は。。。
入力画面2を作成します。
履歴
2017/09/13
初版発行。