かんがるーさんの日記

最近自分が興味をもったものを調べた時の手順等を書いています。今は Spring Boot をいじっています。

Spring Boot + npm + Geb で入力フォームを作ってテストする ( その64 )( 入力画面3を作成する6、@SpringBootTest のテストは Spock+Groovy より JUnit4+Groovy の方が速い? )

概要

記事一覧はこちらです。

Spring Boot + npm + Geb で入力フォームを作ってテストする ( その63 )( MockMvc#perform 呼び出し時に .with(csrf()) を付けていなくてもテストが成功していた理由とは? ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • InquiryInputControllerTest で1件だけ確認画面の実装待ちで未実装だったテストを実装します。
    • @SpringBootTest がクラスに付加されているテストは Spock+Groovy で書くより JUnit4+Groovy で書いた方が速いように見えたので、その検証をしてみます。

参照したサイト・書籍

目次

  1. InquiryInputControllerTest クラスで未実装のテストを実装する
  2. @SpringBootTest を付けるテストの場合 Spock+Groovy より JUnit4+Groovy の構成の方がテストの実行は速いのか?
  3. 次回は。。。

手順

InquiryInputControllerTest クラスで未実装のテストを実装する

src/test/groovy/ksbysample/webapp/bootnpmgeb/web/inquiry/InquiryInputControllerTest.groovy を以下のように変更します。

        @Test
        void "項目全てに入力して前の画面へ戻るボタンをクリックすると入力画面2へ戻り、次へ戻るボタンを押して入力画面3へ戻ると以前入力したデータがセットされて表示される"() {
            ..........
        }

        @Test
        void "項目全てに入力して次へボタンをクリックすると確認画面へ遷移し、修正するボタンを押して入力画面3へ戻ると以前入力したデータがセットされて表示される"() {
            // JUit4+Groovy でテストを必ず失敗させるには以下のように書く
            // expect:
            // assert false, "確認画面を実装してからテストを作成する"

            when: "入力画面1で項目全てに入力して「次へ」ボタンをクリックする"
            MvcResult result = mockMvc.perform(
                    TestHelper.postForm("/inquiry/input/01?move=next", inquiryInput01Form_001).with(csrf()))
                    .andExpect(status().isFound())
                    .andExpect(redirectedUrlPattern("**/inquiry/input/02"))
                    .andReturn()
            MockHttpSession session = result.getRequest().getSession()

            and: "入力画面2で項目全てに入力して「次へ」ボタンをクリックする"
            mockMvc.perform(TestHelper.postForm("/inquiry/input/02?move=next", inquiryInput02Form_001).with(csrf()).session(session))
                    .andExpect(status().isFound())
                    .andExpect(redirectedUrlPattern("**/inquiry/input/03"))

            and: "入力画面3で項目全てに入力して「次へ」ボタンをクリックする"
            mockMvc.perform(TestHelper.postForm("/inquiry/input/03?move=next", inquiryInput03Form_001).with(csrf()).session(session))
                    .andExpect(status().isFound())
                    .andExpect(redirectedUrlPattern("**/inquiry/confirm"))

            then: "確認画面で「修正する」ボタンをクリックすると、入力画面3に戻り以前入力したデータがセットされて表示される"
            mockMvc.perform(get("/inquiry/input/03").session(session))
                    .andExpect(status().isOk())
                    .andExpect(html("select[name='type1'] option[selected]").val(inquiryInput03Form_001.type1))
                    .andExpect(html("input[name='type2'][checked='checked']").count(3))
                    .andExpect(html("#inquiry").val(inquiryInput03Form_001.inquiry))
                    .andExpect(html("input[name='survey'][checked='checked']").count(8))
        }

        @Test
        void "入力チェックエラーのあるデータで「次へ」ボタンをクリックするとIllegalArgumentExceptionが発生する"() {
            ..........
        }
  • void "項目全てに入力して次へボタンをクリックすると確認画面へ遷移し、修正するボタンを押して入力画面3へ戻ると以前入力したデータがセットされて表示される"() { ... } のテストを実装します。

InquiryInputControllerTest クラスのテストを全て実行して成功することを確認します。

f:id:ksby:20180711073035p:plain

InquiryConfirmControllerTest クラスと比較するとテストの実行が速かったです。比較してみます。

InquiryInputControllerTest クラスのテストを3回実行すると以下の結果ですが、

回数 かかった時間
1回目 3s 991ms
2回目 4s 500ms
3回目 4s 142ms

InquiryConfirmControllerTest クラスのテストを3回実行すると以下の結果でした。

回数 かかった時間
1回目 23s 558ms
2回目 23s 543ms
3回目 23s 649ms

JUnit4+Groovy の方が速そうですね。

@SpringBootTest を付けるテストの場合 Spock+Groovy より JUnit4+Groovy の構成の方がテストの実行は速いのか?

SurveyOptionsHelperTest クラスのテストで検証してみます。SurveyOptionsHelperTest クラスのテストは、

  • Spock+Groovy で書いている。
  • @SpringBootTest が付いている。

という内容で、3回実行してみると以下の結果でした。

回数 かかった時間
1回目 20s 117ms
2回目 18s 941ms
3回目 19s 423ms

SurveyOptionsHelperTest クラスを JUnit4+Groovy で書き直します。

package ksbysample.webapp.bootnpmgeb.helper.db

import ksbysample.webapp.bootnpmgeb.entity.SurveyOptions
import org.junit.Test
import org.junit.runner.RunWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.junit4.SpringRunner

import static org.assertj.core.api.Assertions.catchThrowable

@RunWith(SpringRunner)
@SpringBootTest
class SurveyOptionsHelperTest {

    @Autowired
    private SurveyOptionsHelper soh

    @Test
    void "登録されているグループ名を指定してselectItemListメソッドを呼ぶとリストが取得できる"() {
        setup:
        List<SurveyOptions> surveyOptionsList = soh.selectItemList("survey")

        expect:
        assert surveyOptionsList.size() == 8
        assert surveyOptionsList[0].itemValue == "1"
        assert surveyOptionsList[0].itemName == "選択肢1だけ長くしてみる"
        assert surveyOptionsList[7].itemValue == "8"
        assert surveyOptionsList[7].itemName == "8"
    }

    @Test
    void "登録されていないグループ名を指定してselectItemListメソッドを呼ぶとIllegalArgumentExceptionがthrowされる"() {
        setup:
        Throwable thrown = catchThrowable({
            List<SurveyOptions> surveyOptionsList = soh.selectItemList("notexists")
        })

        expect:
        assert thrown instanceof IllegalArgumentException
        assert thrown.message == "指定されたグループ名のデータは登録されていません"
    }

}
  • クラスに @RunWith(SpringRunner) アノテーションを付加します。
  • extends Specification を削除します。
  • 各テストメソッドに @Test アノテーションを付加し、defvoid に変更します。
  • expect: の下で結果を検証している処理に assert を付けます。
  • void "登録されていないグループ名を指定してselectItemListメソッドを呼ぶとIllegalArgumentExceptionがthrowされる"() { ... } テストメソッド内で soh.selectItemList("notexists") を呼び出している部分を Throwable thrown = catchThrowable({ ... }) で囲みます。結果の検証方法も groovy の形式に書き直します。

変更後に3回実行してみると以下の結果でした。やっぱり速いですね。

回数 かかった時間
1回目 458ms
2回目 475ms
3回目 504ms

今度は Spock+Groovy に戻してから、@SpringBootTest は外して適宜 Stub を使う方法で書き直してみます。

package ksbysample.webapp.bootnpmgeb.helper.db

import ksbysample.webapp.bootnpmgeb.dao.SurveyOptionsDao
import ksbysample.webapp.bootnpmgeb.entity.SurveyOptions
import spock.lang.Specification

class SurveyOptionsHelperTest extends Specification {

    SurveyOptionsDao surveyOptionsDao

    SurveyOptionsHelper soh

    def setup() {
        surveyOptionsDao = Stub(SurveyOptionsDao) {
            selectByGroupName("survey") >> [
                    [groupName: "survey", itemValue: "1", itemName: "選択肢1だけ長くしてみる", itemOrder: 1],
                    [groupName: "survey", itemValue: "2", itemName: "選択肢2", itemOrder: 2],
                    [groupName: "survey", itemValue: "3", itemName: "選択肢3", itemOrder: 3],
                    [groupName: "survey", itemValue: "4", itemName: "選択肢4", itemOrder: 4],
                    [groupName: "survey", itemValue: "5", itemName: "選択肢5が少し長い", itemOrder: 5],
                    [groupName: "survey", itemValue: "6", itemName: "選択肢6", itemOrder: 6],
                    [groupName: "survey", itemValue: "7", itemName: "選択肢7", itemOrder: 7],
                    [groupName: "survey", itemValue: "8", itemName: "8", itemOrder: 8]
            ]
            selectByGroupName("notexists") >> []
        }
        soh = new SurveyOptionsHelper(surveyOptionsDao)
    }

    def "登録されているグループ名を指定してselectItemListメソッドを呼ぶとリストが取得できる"() {
        setup:
        List<SurveyOptions> surveyOptionsList = soh.selectItemList("survey")

        expect:
        surveyOptionsList.size() == 8
        surveyOptionsList[0].itemValue == "1"
        surveyOptionsList[0].itemName == "選択肢1だけ長くしてみる"
        surveyOptionsList[7].itemValue == "8"
        surveyOptionsList[7].itemName == "8"
    }

    def "登録されていないグループ名を指定してselectItemListメソッドを呼ぶとIllegalArgumentExceptionがthrowされる"() {
        when:
        List<SurveyOptions> surveyOptionsList = soh.selectItemList("notexists")

        then:
        def e = thrown(IllegalArgumentException)
        e.getMessage() == "指定されたグループ名のデータは登録されていません"
    }

}
  • クラスに付けている @SpringBootTest、及びフィールドに付けている @Autowired を削除します。
  • SurveyOptionsDao surveyOptionsDao を追加します。
  • def setup() { ... } を追加し、surveyOptionsDao の Stub を生成してから soh のインスタンスを生成する処理を記述します。

変更後に3回実行してみると以下の結果でした。JUnit4+Groovy より時間がかかっているように表示されましたが、実際にテストが終了する速度はこちらの方が速いです。IntelliJ IDEA は何の時間を表示しているのだろうという疑問が。。。

回数 かかった時間
1回目 768ms
2回目 840ms
3回目 970ms

次回は。。。

利用しているライブラリを一通りバージョンアップしてから Geb を利用したテストを作成します。

履歴

2018/07/11
初版発行。