発生した問題
私たちが扱うプロダクト内では、ユーザーの入力値に基づき表示が変化する動的なUIが存在します。
このフロントエンドのテストはRSpecを用いて行っていました。
しかし、このような動的UIの自動テストは、何回かに1回の確率で落ちてしまい、GREENになるかどうかがある意味「運次第」となる傾向がありました。
問題が発生することの課題
変更していない箇所に対してテストが落ち、CIツールの画面上で「Retry」をすることは開発スピードの足を引っ張ります。
そこで、落ちやすいテストに関して自動でリトライしてくれるgemを導入しました。
対象となるテスト
example '試算ができないこと' do
visit('/try/input')
fill_in('simulation_postcode_1', with: '100')
fill_in('simulation_postcode_2', with: '0102')
sleep(1)
expect(page).to have_content('申し訳ございません。お住まいの地域はシミュレーションに対応しておりません。')
fill_in('simulation_postcode_1', with: '100')
fill_in('simulation_postcode_2', with: '0601')
sleep(1)
expect(page).to have_content('申し訳ございません。お住まいの地域はシミュレーションに対応しておりません。')
end
郵便番号の上3桁と下4桁を入力し、その地域がサービスに対応しないことを確認するためのテストです
郵便番号を入力した後 sleep(1)
で1秒待ち、画面が変わってからexpect
でテストしています。
この箇所でテストが落ちやすく、sleep(10)
にしても効果が無いことを確認しました(なぜ?)。
rspec-retry gemとの違い
テストをリトライするgemといえばrspec-retry
gemですが、今回導入したのはrspec-retry_ex
gemです。
というのも、spec-retry
gemは、scenario単位でのリトライを行うgemです。
scenario内に複数のexpectがある場合、途中のexpectでコケるとscenarioを最初からやり直すため、時間がかかる可能性があります。
一方、rspec-retry_ex
gemはscenarioの中のexpect単位でリトライを行うため、小さな単位でのリトライができます。
これは、テストに要する時間を短縮することに繋がります。
機能の説明
GitHubに記載されていた例を用いて解説します。
rspec-retry_ex gem導入前
以下のテストに対し、リトライを追加します。
scenario "Some scenario" do
visit "/some_page"
fill_in "postcode", with: "1300012"
expect(page).to have_select("ward", selected: "Sumida")
end
この例ではexpect(page).to have_select("ward", selected: "Sumida")
が動的UIなので、これについてリトライを追加します。
基本形
リトライを3回するには、expectに対してretry_ex(count: 3)
ブロックで挟みます。
scenario "Some scenario" do
visit "/some_page"
fill_in "postcode", with: "1300012"
retry_ex(count: 3) do
expect(page).to have_select("ward", selected: "Sumida")
end
end
リトライ前に処理を追加
リトライ前に画面をリフレッシュさせ、イベントを再発火させるという狙いです。
scenario "Some scenario" do
visit "/some_page"
fill_in "postcode", with: "1300012"
# These codes are executed after the retry fails
after_retry = -> {
fill_in "postcode", with: "1000004"
fill_in "postcode", with: "1300012"
}
retry_ex(count: 3, after_retry: after_retry) do
expect(page).to have_select("ward", selected: "Sumida")
end
end
導入方法
- Gemfileに記載
group :test do
gem 'rspec-retry_ex'
end
- bundle install
$ bundle install
-
spec/rails_helper.rb
に追記
include RSpec::RetryEx
実装したテスト
先程紹介したように、リトライ前にイベントを再発火させるようにテストしました。
example '試算ができないこと' do
visit('/try/input')
fill_in('simulation_postcode_1', with: '100')
fill_in('simulation_postcode_2', with: '0102')
retry_ex(count: 5, after_retry: -> {
fill_in('simulation_postcode_1', with: '101')
fill_in('simulation_postcode_1', with: '100')
fill_in('simulation_postcode_2', with: '0102')
}) do
sleep(1)
expect(page).to have_content('申し訳ございません。お住まいの地域はシミュレーションに対応しておりません。')
end
fill_in('simulation_postcode_1', with: '100')
fill_in('simulation_postcode_2', with: '0601')
retry_ex(count: 5, after_retry: -> {
fill_in('simulation_postcode_1', with: '101')
fill_in('simulation_postcode_1', with: '100')
fill_in('simulation_postcode_2', with: '0601')
}) do
sleep(1)
expect(page).to have_content('申し訳ございません。お住まいの地域はシミュレーションに対応しておりません。')
end
end
結果
「運ゲー」化していたテストが確実に通るようになり、CIでの余計なリトライが不要になりました。
参考
https://tech.enechange.co.jp/entry/2019/02/22/083700
https://github.com/yuyasat/rspec-retry_ex/tree/master