Spring Boot + npm + Geb で入力フォームを作ってテストする ( その71 )( Geb で入力画面1~3→確認画面→完了画面を通したテストを作成する )
概要
記事一覧はこちらです。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その70 )( 完了画面を作成する ) の続きです。
- 今回の手順で確認できるのは以下の内容です。
- Geb を利用して、入力画面1~3→確認画面→完了画面を通したテストを作成します。
- テストでは DB のデータやメールの送信内容も確認します。
参照したサイト・書籍
How do I find an element that contains specific text in Selenium Webdriver (Python)?
https://stackoverflow.com/questions/12323403/how-do-i-find-an-element-that-contains-specific-text-in-selenium-webdriver-pythChromeDriver - WebDriver for Chrome - Downloads
https://sites.google.com/a/chromium.org/chromedriver/downloads
目次
- InquiryInput01Page クラスを変更する
- InquiryInput02Page クラスを変更する
- InquiryInput03Page クラスを作成する
- InquiryConfirmPage クラスを作成する
- InquiryCompletePage クラスを作成する
- FormModule クラスを変更する
- inquirymail-body_003.txt を追加する
- InquiryTestSpec クラスに入力画面1~3→確認画面→完了画面を通したテストを追加する
- 動作確認
- 全ての Geb のテストを実行してみる
手順
InquiryInput01Page クラスを変更する
src/test/groovy/geb/page/inquiry/InquiryInput01Page.groovy に今回使用するテストデータを追加します。
class InquiryInput01Page extends Page { .......... static valueList01 = [ "#lastname" : "田中", "#firstname" : "太郎", "#lastkana" : "たなか", "#firstkana" : "たろう", "input[name='sex']": SexValues.MALE.value, "#age" : "30", "#job" : JobValues.EMPLOYEE.value, ] }
static valueList01 = [ ... ]
を追加します。
InquiryInput02Page クラスを変更する
src/test/groovy/geb/page/inquiry/InquiryInput02Page.groovy に今回使用するテストデータを追加します。
class InquiryInput02Page extends Page { .......... static valueList01 = [ "#zipcode1": "100", "#zipcode2": "0005", "#address" : "東京都千代田区飯田橋1-1", "#tel1" : "03", "#tel2" : "1234", "#tel3" : "5678", "#email" : "taro.tanaka@sample.co.jp", ] }
InquiryInput03Page クラスを作成する
src/test/groovy/geb/page/inquiry の下に InquiryInput03Page.groovy を新規作成し、以下の内容を記述します。
package geb.page.inquiry import geb.Page import geb.module.FormModule import ksbysample.webapp.bootnpmgeb.values.Type1Values import ksbysample.webapp.bootnpmgeb.values.Type2Values class InquiryInput03Page extends Page { static url = "/inquiry/input/03" static at = { title == "入力フォーム - 入力画面3" } static content = { form { module FormModule } } static initialValueList = [ "#type1" : "", "input[name='type2']" : null, "#inquiry" : "", "input[name='survey']": null, ] static valueList01 = [ "#type1" : Type1Values.PRODUCT.value, "input[name='type2']" : [ Type2Values.CATALOGUE.value, Type2Values.ESTIMATE.value, Type2Values.OTHER.value, ], "#inquiry" : "これは\nテスト\nです", "input[name='survey']": ["1", "2", "3", "4", "5", "6", "7", "8"], ] }
InquiryConfirmPage クラスを作成する
src/test/groovy/geb/page/inquiry の下に InquiryConfirmPage.groovy を新規作成し、以下の内容を記述します。
package geb.page.inquiry import geb.Page import geb.module.FormModule import ksbysample.webapp.bootnpmgeb.values.JobValues import ksbysample.webapp.bootnpmgeb.values.SexValues import ksbysample.webapp.bootnpmgeb.values.Type1Values import ksbysample.webapp.bootnpmgeb.values.Type2Values import java.util.stream.Collectors class InquiryConfirmPage extends Page { static url = "/inquiry/confirm" static at = { title == "入力フォーム - 確認画面" } static content = { form { module FormModule } } static textList01 = [ "#name" : "田中 太郎", "#kana" : "たなか たろう", "#sex" : SexValues.MALE.text, "#age" : "30 歳", "#job" : JobValues.EMPLOYEE.text, "#zipcode": "〒 100-0005", "#address": "東京都千代田区飯田橋1-1", "#tel" : "03-1234-5678", "#email" : "taro.tanaka@sample.co.jp", "#type1" : Type1Values.PRODUCT.text, "#type2" : [Type2Values.ESTIMATE.text , Type2Values.CATALOGUE.text , Type2Values.OTHER.text].stream() .collect(Collectors.joining("、")), "#inquiry": "これは\nテスト\nです", ] }
InquiryCompletePage クラスを作成する
src/test/groovy/geb/page/inquiry の下に InquiryCompletePage.groovy を新規作成し、以下の内容を記述します。
package geb.page.inquiry import geb.Page import geb.module.FormModule import org.openqa.selenium.By class InquiryCompletePage extends Page { static url = "/inquiry/confirm" static at = { title == "入力フォーム - 完了画面" } static content = { form { module FormModule } btnToInput01 { $(By.xpath("//button[contains(text(), '入力画面へ')]")) } } }
FormModule クラスを変更する
src/test/groovy/geb/module/FormModule.groovy の以下の点を変更します。
class FormModule extends Module { static content = { btnBack { $(".js-btn-back") } btnNext { $(".js-btn-next") } btnConfirm { $(".js-btn-confirm") } btnInput01 { $(".js-btn-input01") } btnSend { $(".js-btn-send") } } .......... /** * セレクタに値がセットされているかを検証する * このメソッドは Spock の then, expect で使用する想定である * * @param valueList 検証するセレクタと値を記述した Map * @return true 固定 */ boolean assertValueList(valueList) { valueList.each { key, value -> if ($(key).first().attr("type") == "radio") { WebElement element = $(key).allElements().find { it.selected } if (element == null) { assert null == value } else { assert element.getAttribute("value") == value } } else if ($(key).first().attr("type") == "checkbox") { value.each { v -> WebElement element = $(key).allElements().find { el -> el.getAttribute("value") == v && el.selected } assert element != null } } else { assert $(key).value() == value } } true } /** * セレクタにテキストがセットされているかを検証する * このメソッドは Spock の then, expect で使用する想定である * * @param textList 検証するセレクタと値を記述した Map * @return true 固定 */ boolean assertTextList(textList) { textList.each { key, value -> assert $(key).text() == value } true } }
static content = { ... }
内に以下のボタンの定義を追加します。- btnConfirm
- btnInput01
- btnSend
- assertValueList メソッド内に
else if ($(key).first().attr("type") == "checkbox") { ... }
の処理を追加します。 - assertTextList メソッドを追加します。
inquirymail-body_003.txt を追加する
メールの本文検証用のファイルを追加します。src/test/resources/ksbysample/webapp/bootnpmgeb/web/inquiry の下に inquirymail-body_003.txt を追加し、以下の内容を記述します。
問い合わせフォームから入力された内容は以下の通りです。 お名前(漢字):田中 太郎 お名前(かな):たなか たろう 性別:男性 年齢:30歳 職業:会社員 郵便番号:〒100-0005 住所:東京都千代田区飯田橋1-1 電話番号:03-1234-5678 メールアドレス:taro.tanaka@sample.co.jp お問い合わせの種類1:製品に関するお問い合わせ お問い合わせの種類2:見積が欲しい、資料が欲しい、その他の問い合わせ お問い合わせの内容: これは テスト です アンケート: ・選択肢1だけ長くしてみる ・選択肢2 ・選択肢3 ・選択肢4 ・選択肢5が少し長い ・選択肢6 ・選択肢7 ・8
InquiryTestSpec クラスに入力画面1~3→確認画面→完了画面を通したテストを追加する
src/test/groovy/geb/gebspec/inquiry/InquiryTestSpec.groovy の以下の点を変更します。
class InquiryTestSpec extends GebSpec { @Rule MailServerResource mailServerResource = new MailServerResource() Sql sql def setup() { // 外部プロセスから接続するので H2 TCP サーバへ接続する sql = Sql.newInstance("jdbc:h2:tcp://localhost:9092/mem:bootnpmgebdb", "sa", "") sql.execute("truncate table INQUIRY_DATA") } def teardown() { sql.close() } .......... def "入力画面1~3→確認画面→完了画面の全ての画面を通す"() { setup: "入力画面1を表示する" to InquiryInput01Page and: "データを入力して次へボタンをクリックし、入力画面2へ遷移する" form.setValueList(valueList01) form.btnNext.click(InquiryInput02Page) and: "データを入力して次へボタンをクリックし、入力画面3へ遷移する" form.setValueList(valueList01) form.btnNext.click(InquiryInput03Page) and: "データを入力して次へボタンをクリックし、確認画面へ遷移する" form.setValueList(valueList01) form.btnConfirm.click(InquiryConfirmPage) and: "確認画面にデータが表示されていることを確認する" form.assertTextList(textList01) $("#survey > ul > li").count(8) $("#survey > ul > li", 0).text() == "選択肢1だけ長くしてみる" $("#survey > ul > li", 7).text() == "8" and: "修正するボタンをクリックし、入力画面1へ戻る" form.btnInput01.click(InquiryInput01Page) form.assertValueList(valueList01) and: "次へボタンをクリックし、入力画面2へ遷移する" form.btnNext.click(InquiryInput02Page) form.assertValueList(valueList01) and: "次へボタンをクリックし、入力画面3へ遷移する" form.btnNext.click(InquiryInput03Page) form.assertValueList(valueList01) and: "次へボタンをクリックし、確認画面へ遷移する" form.btnConfirm.click(InquiryConfirmPage) form.assertTextList(textList01) $("#survey > ul > li").count(8) $("#survey > ul > li", 0).text() == "選択肢1だけ長くしてみる" $("#survey > ul > li", 7).text() == "8" expect: "送信するボタンをクリックし、完了画面へ遷移する" form.btnSend.click(InquiryCompletePage) // INQUIRY_DATA テーブルに1件データが登録されていることを確認する def rows = sql.rows("SELECT * FROM INQUIRY_DATA") rows.size() == 1 rows[0]["lastname"] == "田中" rows[0]["firstname"] == "太郎" rows[0]["lastkana"] == "たなか" rows[0]["firstkana"] == "たろう" rows[0]["sex"] == SexValues.MALE.value rows[0]["age"] == 30 rows[0]["job"] == JobValues.EMPLOYEE.value rows[0]["zipcode1"] == "100" rows[0]["zipcode2"] == "0005" rows[0]["address"] == "東京都千代田区飯田橋1-1" rows[0]["tel1"] == "03" rows[0]["tel2"] == "1234" rows[0]["tel3"] == "5678" rows[0]["email"] == "taro.tanaka@sample.co.jp" rows[0]["type1"] == Type1Values.PRODUCT.value rows[0]["type2"] == [Type2Values.ESTIMATE.value , Type2Values.CATALOGUE.value , Type2Values.OTHER.value].stream() .collect(Collectors.joining(",")) rows[0]["inquiry"].asciiStream.text == "これは\r\nテスト\r\nです" rows[0]["survey"] == "1,2,3,4,5,6,7,8" // メールが1件送信されていることを確認する mailServerResource.messagesCount == 1 MimeMessage message = mailServerResource.firstMessage message.subject == "問い合わせフォームからお問い合わせがありました" message.content == new ClassPathResource("ksbysample/webapp/bootnpmgeb/web/inquiry/inquirymail-body_003.txt").inputStream.text and: "再び入力画面1を表示する" btnToInput01.click(InquiryInput01Page) // 入力したデータは表示されていない form.assertValueList(initialValueList) } }
- 以下のフィールドを追加する。
@Rule MailServerResource mailServerResource = new MailServerResource()
Sql sql
setup()
、teardown()
を追加する。def "入力画面1~3→確認画面→完了画面の全ての画面を通す"() { ... }
を追加する。
動作確認
まずは Firefox でテストします。GebConfig.groovy は以下の設定です。
System.setProperty("webdriver.gecko.driver", "C:/geckodriver/0.19.0/geckodriver.bat") System.setProperty("webdriver.chrome.driver", "C:/chromedriver/2.33/chromedriver.exe") driver = { FirefoxOptions firefoxOptions = new FirefoxOptions() firefoxOptions.setHeadless(true) new FirefoxDriver(firefoxOptions) }
Tomcat を起動した後、src/test/groovy/geb/gebspec/inquiry/InquiryTestSpec.groovy の "入力画面1~3→確認画面→完了画面の全ての画面を通す"()
テストメソッド左側の矢印から Run '入力画面1~3→確認画面→完了画面の...()'
をクリックします。
テストが実行されて成功しました。
次は Chrome でテストするために、GebConfig.groovy を以下のように変更します。
System.setProperty("webdriver.gecko.driver", "C:/geckodriver/0.19.0/geckodriver.bat") System.setProperty("webdriver.chrome.driver", "C:/chromedriver/2.33/chromedriver.exe") driver = { // FirefoxOptions firefoxOptions = new FirefoxOptions() // firefoxOptions.setHeadless(true) // new FirefoxDriver(firefoxOptions) ChromeOptions chromeOptions = new ChromeOptions() chromeOptions.setHeadless(true) new ChromeDriver(chromeOptions) }
Firefox の時と同様に Run '入力画面1~3→確認画面→完了画面の...()'
をクリックすると、テストは実行されましたが今度は失敗しました。入力項目に値がセットできていないようです。
ChromeDrive の Downloads ページ を見ると 2.40 がリリースされていましたので入れ替えます。Supports Chrome v66-68
のようにサポートしている Chrome のバージョンが記載されており、2.33 だと Supports Chrome v60-62
で使用している Chrome とバージョンが合っていませんでした(現時点の Chrome のバージョンは 67)。
ChromeDriver 2.40 のリンクをクリックして、その先にある chromedriver_win32.zip をダウンロードします。ダウンロード後、解凍して作成された chromedriver.exe を C:\chromedriver\2.40 の下に配置します。
GebConfig.groovy の chromedriver.exe のパスを変更してから、
System.setProperty("webdriver.gecko.driver", "C:/geckodriver/0.19.0/geckodriver.bat") System.setProperty("webdriver.chrome.driver", "C:/chromedriver/2.40/chromedriver.exe")
テストを実行すると今度は成功しました。
全ての Geb のテストを実行してみる
今度は Geb の全てのテストを実行してみます。Gradle Tool Window から firefoxTest タスクを実行します。
半数以上失敗しましたね。。。 失敗した原因を確認したところ、以下の内容でした。
- InquiryInput01Page クラスの maxLengthValueList に全ての項目が記述されていないので、値がセットされない入力項目がある。
- InquiryInput01Page クラスの maxLengthValueList で
"#lastkana"
、"#firstkana"
にカナの値が設定されていなかったので、入力チェックエラーが発生していた。
src/test/groovy/geb/page/inquiry/InquiryInput01Page.groovy の maxLengthValueList を以下のように変更します。
static maxLengthValueList = [ "#lastname" : "田" * 20, "#firstname" : "太" * 20, "#lastkana" : "あ" * 20, "#firstkana" : "い" * 20, "input[name='sex']": SexValues.MALE.value, "#age" : "9" * 3, "#job" : JobValues.EMPLOYEE.value, ]
また maxLengthValueList で全ての値をセットするように変更したので、src/test/groovy/geb/gebspec/inquiry/InquiryTestSpec.groovy から以下の記述の行を全て取り除きます。
form.setValue("input[name='sex']", "1")
$("#inquiryInput01Form").sex == "1"
再度 firefoxTest タスクを実行すると今度は全て成功しました。
次に chromeTest タスクを実行してみると、こちらも全て成功しました。
最後に gebTest タスクを実行して全て成功することを確認します。
履歴
2018/07/22
初版発行。
2018/07/22
* Geb のテストのために Spring Boot のアプリを起動しているのは develop profile で unittest profile でないことに気づいたのと、unittest profile でも H2 TCP サーバを起動させると一部のテストが失敗するようになったので、「H2DatabaseConfig クラスを変更し、unittest profile でも H2 TCPサーバを起動させる」を削除しました。