Slide 1

Slide 1 text

STORES 株式会社 STORES ネットショップのCIとかテストに ついて話します 2023-11-08 @hogelog CTO室技術基盤グループマネージャ 小室 直 2023年11月

Slide 2

Slide 2 text

自己紹介 技術基盤グループ マネージャ @hogelog ウェブ企業でサービス開発エンジニア、基盤領域エンジニアやマ ネージャーを経由して、現在はまたエンジニアマネージャに。 サーバサイドとインフラの間や組織と組織の間に落ちているボー ルを拾うのが割と好きです。

Slide 3

Slide 3 text

CIとは 3 - CI = Continuous Integration(継続的インテグレーション) - CIでは色々なものを動かします - テスト - Lint - ……

Slide 4

Slide 4 text

STORES ネットショップのテスト 4 - STORES ネットショップのRailsアプリケーションのテストに関し てあれこれ雑多に紹介します

Slide 5

Slide 5 text

STORES ネットショップのテスト行数推移 5 - 2023年11月現在: 22万6185行 - `find spec -type file -name '*.rb' | xargs wc -l`

Slide 6

Slide 6 text

CI実行環境と実行時間 6 - CI実行環境: CircleCI - 10m+ もしばしば☔

Slide 7

Slide 7 text

ある程度以上規模のRailsアプリケーションテストの問題 7 - 問題 - 結果が不安定 - 時間がかかる - お金がかかる - なんとかする - 不安定なテストの改善 - テストの高速化 (      )≒ 時間がかかる

Slide 8

Slide 8 text

不安定なテストの安定化

Slide 9

Slide 9 text

テスト安定化: タイミング問題で落ちるテストの修正 9 - 複数データが同一秒に作成されると落ちるテスト - 複数データが同一秒に作成されないと落ちるテスト - 他

Slide 10

Slide 10 text

テスト安定化: 不安定なテストの改善(レスポンスのブラウザキャッシュ) 10 - feature specでブラウザがレスポンスをキャッシュしてしまい実 行順によっては失敗する場合があった - 現在はテスト実行時は `expires_in` を無効化している - 後日ブログで再現コードや他の解決方法について解説します module DisableBrowserCacheDuringTest def expires_in(seconds, options = {}) if seconds == 0 super end end end ActionController::ConditionalGet.prepend(DisableBrowserCacheDuringTest)

Slide 11

Slide 11 text

テスト安定化: 不安定なテストの改善(遅い回線のエミュレート) 11 - CIでネットワークが詰まった時に不安定になるテストを見つけるた めの遅い回線のエミュレート if ENV["CAPYBARA_EMULATE_SLOW_NETWORK"] emulate_network_config = { latency: 100, # 100ms download_throughput: 64 * 1024 / 8, # 64Kbps upload_throughput: 64 * 1024 / 8, # 64Kbps } elsif ENV["CAPYBARA_EMULATE_NETWORK_CONFIG"] emulate_network_config = JSON.parse(ENV["CAPYBARA_EMULATE_NETWORK_CONFIG"], symbolize_names: true) end if emulate_network_config Capybara.current_session.driver.browser.devtools.network.emulate_network_conditions(offline: false, **emulate_network_config) end

Slide 12

Slide 12 text

テスト安定化: 不安定なテストの改善(集計と継続的取り組み) 12 - 不安定なテストをスプレッドシートに集計、可視化し改善に日々取 り組み

Slide 13

Slide 13 text

テスト安定化: rspec --only-failures 13 - 実行に失敗したテストのみ再実行するフラグ - 不安定なテスト失敗時、テストを全て実行しなおす時間をスキップ できる

Slide 14

Slide 14 text

テスト安定化: rspec-retry 14 - 実行に失敗したテストのみ再実行するgem - 同一rspec実行プロセスの中で再実行されるので--only-failuresよ りも速いことが期待できる

Slide 15

Slide 15 text

テスト再実行系ソリューションの注意点 15 - 不安定なテストが気づかぬうちに増えていく - 不安定なテストが増えると実行時間も伸びる - 継続的な改善活動に取り組んでいない場合、必ず不安定なテストは 増えていきます - CircleCIならばCircleCI Insightsなどを見るのもオススメ - そもそも再実行系ソリューションは可能な限り導入を避けたい

Slide 16

Slide 16 text

テストの高速化

Slide 17

Slide 17 text

テスト高速化: Capybara.default_max_wait_time の調整 17 - feature specの失敗時、Capybara.default_max_wait_time時間 待つ場合があるので、長すぎない程度の適切な時間を設定 - 現在の設定: `default_max_wait_time = 10`

Slide 18

Slide 18 text

テスト高速化: 大量に作られるテストデータの削減 18 - 検証したい条件に関連しない無駄なテストデータ作成を削減 - かなり地道 - 101.times { |i| Fabricate.create(...) } + Fabricate.create(...)

Slide 19

Slide 19 text

テスト高速化: テスト分割と並列実行(CircleCI) 19 - 現在の設定: `parallelism: 16` - 💰

Slide 20

Slide 20 text

テスト高速化: テスト分割と並列実行(parallel_rspec) 20 - CircleCIのparallelismはマシンリソースを使いきれないので parallel_rspecで並列度を更に向上📈 - 複雑度も向上📈、悩ましい

Slide 21

Slide 21 text

テスト高速化: テスト分割と並列実行(parallel_rspec不安定テストの再実行) 21 - rspec-retry + 失敗したspecの再実行 - rspec-retryでは救いきれないパターンを再実行でカバー - parallel_rspec x rspec --only-failures がうまく動かないので自 前スクリプトで before_result = File.read("tmp/test_results/failing_specs.log") failed_output = (before_result =~ /Failed examples:[\r\n]+(.+)/m && $1) failing_examples = failed_output.lines.map do |line| $1 if line =~ %r[rspec ('.+'|./spec/.+:\d+)] end.compact puts "Rerun #{failing_examples.size} examples" command = "bundle exec rspec --no-fail-fast -- #{failing_examples.join(" ")}" puts command exec command

Slide 22

Slide 22 text

テスト(CI)高速化: CircleCI workspaceの省サイズ化 22 - ジョブ間のデータ共有に用いるworkspaceの省サイズ化`rm -rf .git/ ...`

Slide 23

Slide 23 text

テスト(CI)高速化: 細かい改善 23 - テスト失敗あるときのみ `rspec --only-failures` 実行 - 無駄なapt-get installの削減 - 他

Slide 24

Slide 24 text

テスト(CI)高速化: 遅いテストを観測し改善する継続的な取り組み 24 - 基本は rspec --profile - 集計しavg, p95など可視化すると効果的 - CircleCI Insightsなども有用

Slide 25

Slide 25 text

テスト安定化・高速化 25 - しばらくテスト安定化・高速化の取り組みがない、アクティブに開 発されているRailsアプリケーションは必ずテストが不安定になり 遅くなっています - CIの結果や設定ファイルをじっと見ると改善できる場所が必ず浮か んでくる - できるまでやればできる

Slide 26

Slide 26 text

今後のテストについて 26 - CircleCI -> GitHub Actions, CodeBuild, Jenkins, …? - 不安定なテスト、遅いテストがまた蓄積しつつある - To be continued...