📑

【超基礎】RSpecの速度向上のために最低限知っておきたいこと

2022/06/07に公開

概要

今回、RSpecの速度を向上するPJでCI速度改善対応時に効果があった施策についてまとめていきたいと思います。
記載している内容はかなり基本的なものが多いですので、どちらかというとジュニアエンジニア向けの記事になります。
※何か誤り等がありましたらコメントの方をお願いいたします。🙇‍♂️

01. DBアクセスを減らす

レコードのcreate / updateは最小に留める

DBにデータを保存する過程で処理が遅くなってしまうため、レコード作成は最小限になるようにする。
また、レコードの作成(create)に限らず、レコードの更新(update)も極力ない方がいい。
SQLが追加で発行されてしまうため、テストを遅くする原因になりうる。
※ここでいう「レコード」はletlet!でテスト実行中に作成されるテストデータのこと。

createでもbuildでもテスト可能な場合はbuildを使用する

例: バリデーションのテスト・レコード保存前に呼び出すメソッドなど
レコードがDBに存在せずともインスタンスがあれば検証できるようなインスタンスメソッドであれば、 create ではなくbuildを使用する。
バリデーションのテストの場合、Rails準拠のバリデーションを使用しているのであれば shoulda-matchersを使用するのが無難だと思われます。
カスタムバリデーションの場合はbuildを使用するよう意識する必要がある。

02. itは最小に減らす

itの度にレコードが生成されるため実行速度が遅くなる。
※rspecでは、it毎に全てのlet!でテストデータを作り直す + beforeなども上から順に実行される。
1つにまとめられるなら1つにまとめた方がいい。
itが数だけlet!の処理が発生してDBアクセスが増えてしまう。

03. 検証時にループを極力使用しない・expectの数を減らす

# 例
let(:expected_keys) { %i[id name state] }
let(:user) { build(:user) } # attributes: id, name, state
subject { user.attributes.keys }

# bad
it '想定通りの属性をuserが有していること' do
  expected_keys.each do |key|
    is_expected.to include key
  end
end

# good
it { is_expected.to eq expected_keys }

04. Procオブジェクトを使用しない

Procオブジェクトはオブジェクトの領域確保で負荷がかかるのと、実行に時間がかかる
Procオブジェクトを使用しなければならない場合はRSpecではないはず

05. feature specでsleepは悪手

feature specでたまにsleepメソッドを使用している箇所を目にしますが、これはできるだけ避けるべき。
シンプルにテストが遅くなる + テストがガチャっぽくなるので、画面の描画を待つのであればsleepの代わりにhave_contentfindを使うようにするべし。

まとめ

今回は基本的なことばかりを取り上げましたが、随時必要に応じて項目を追加していこうと思っています。

Discussion