📝

test-prof を使用した RSpec 改善について

に公開

普段は Rails・RSpec・FactoryBot 等を使って日々開発しています。最近テストの実行時間が少しずつ気になるようになってきました。テストが増えてくるとどうしても CI の時間が長くなり、ちょっとした修正でも気軽にプッシュできない感覚に陥ることがあります。

そんな中で目にしたのが、DHH さんのこちらの投稿です:

https://x.com/dhh/status/1919291397909233858

「実際のところ、RSpec を使っている自分のプロジェクトではどうなんだろう?」と気になり、改めてテストのパフォーマンスを計測してみることにしました。

現在のプロジェクトでは minitest は使っていませんが、実行時間の実態を知ることで改善の余地が見えるかもしれないと思いました。今回は test-prof を使ってテストのパフォーマンスをプロファイルし、実際にどう改善できたのかをまとめてみました。

Gemfile に

group :test do
  gem "test-prof"
end

を記述して、

bundle install

します。

ここまでできたら、実際に遅いspecを確認します。
以下のコマンドでTOP10の遅い、テスト・ファイルが分かります。

bundle exec rspec --profile 10

出力例

Top 10 slowest example groups:
  1 seconds ./spec/xxxx/xxxxx/xxxxx/xxxxxx/xxxxx_spec.rb:77

Top 10 slowest example groups:
  User
    0.43707 seconds average (5.68 seconds / 13 examples) ./spec/models/user_spec.rb:4

テストの改善

実際に遅いテストファイルがどこか分かりました。そこで遅いファイルを見てみると何度も同じインスタンスが作成されていたので、今回は let_it_be を用いて改善しようと思いました。

let_it_be とは

let を使った場合、毎回の it ブロックで create(:xxx) が実行されます。
一方で、let_it_be(test-prof が提供)は 1回だけ生成して、テスト実行間で再利用する仕組みです。

# let(毎回実行)
let(:user) { create(:user) }

# let_it_be(最初の1回だけ実行し、他のexampleでは再利用)
let_it_be(:user) { create(:user) }

実際に改善した例

一番遅い spec で、let から let_it_be に書き換えてみました。

- let(:user) { create(:user) }
+ let_it_be(:user) { create(:user) }

- let(:work) { create(:work, user:) }
+ let_it_be(:work) { create(:work, user:) }

効果:どのくらい速くなったのか?

改善前

time bundle exec rspec spec/models/xxxxx_spec.rb
13 examples, 0 failures
Finished in 8.54 seconds (files took 3.74 seconds to load)

改善後 (let_it_be 導入後)

time bundle exec rspec spec/models/xxxxx_spec.rb
13 examples, 0 failures
Finished in 5.99 seconds (files took 3.04 seconds to load)

改善前、後で多少バラツキはあるものの、平均すると1.5〜2.5秒早くなってそうでした。CI全体でもこのような重い spec が複数あると、効果は積み重なっていきます。

let_it_be を使う際のポイント

使いすぎに注意

すべての let を let_it_be にすればいいというわけではないと思います。
テストごとに異なる内容になるものは、あくまで let や before で定義すべきです。

データの汚染に注意

let_it_be で生成されたデータは immutable(変更すべきでない)という前提があります。
subject.name = "変更" のような操作は避けるべきです。

まとめ

テストは正しさを担保する重要な仕組みですが、遅くて不便になると品質にも影響が出てくると思います。

今回 test-prof を使って測定→ let_it_be を導入してみたことで、目に見えるパフォーマンス改善が得られました。CI・テストの実行時間に課題感がある方は、まずは --profile で状況を把握してみると良いと思います。

We are hiring!

TAIANでは、このような開発・技術・思想に向き合い、未来をつくる仲間を一人でも多く探しています。少しでも興味を持っていただいた方は弊社の紹介ページをご覧ください。

https://taian-inc.notion.site/Entrance-Book-for-Engineer-1829555d9582804cad9ff48ad6cc3605

TAIANテックブログ

Discussion