読者です 読者をやめる 読者になる 読者になる

スローテスト刑事 (DatabaseCleaner.strategy 編)

Rails アプリケーションのテストが遅い要因はほぼ Feature Spec いうことで、こんな作業なんかもしてたりした。

まとめると、DatabaseCleaner.strategy:truncation の実行は遅いので、必要がなければ :transaction を使いたいという取り締まり作戦。

最初の確認点として、Feature Spec なんかを書いているアプリケーションの spec_helper.rb か rails_helper.rb に以下のような感じのロジックがあるかを見てみる。あれば example.metadata で指定しているメタデータ名が取っ掛かりになる。ここでの容疑名は :javascript としよう。

config.before(:each) do |example|
  if example.metadata[:javascript]
    DatabaseCleaner.strategy = :truncation, {except: MASTERS}
  else
    DatabaseCleaner.strategy = :transaction
  end
end

スローテスト容疑の取っ掛かりの名前 (ここでは :javascript) から、DatabaseCleaner.strategy:transaction で済むところを :truncation を実行されるようになっているところを調査する。

ここでの容疑の調査でいうとこんな感じで、grep の引数に与える。

grep -ro @javascript spec

あとは grep の一覧に出てきた対象のファイルを対象に、盲目的に フィーチャ@javascript が付いているようなところを、必要な シナリオ だけ @javascript としていく。

-@javascript
 フィーチャ: 遅いフィーチャ
   シナリオ: JavaScirptを使わないシナリオ1
   ...

+  @javascript
   シナリオ: JavaScriptを使うシナリオ
   ...

   シナリオ: JavaScirptを使わないシナリオ2
   ...

もっと雑にいうと消すことのできる @javascript はがっつりと消す。がっつり消せると埋蔵金ゲットだぜ感高い。

-@javascript
 フィーチャ: 遅いフィーチャ
   シナリオ: このフィーチャにあるシナリオどれもJavaScirptを使わない
   ...

大きめの効果が出たところでざっくりと、

Finished in 50.63 seconds (files took 7.32 seconds to load)
10 examples, 0 failures

から

Finished in 31.74 seconds (files took 6.31 seconds to load)
10 examples, 0 failures

とか

Finished in 51.63 seconds (files took 7.36 seconds to load)
16 examples, 0 failures

から

Finished in 33.91 seconds (files took 7.21 seconds to load)
16 examples, 0 failures

といった感じが期待できる (かもしれない) 。

ポイントとしては、上記のように10秒台単位でじわじわとではあるけど着実に減らせたりする点と、容疑の絞り込みが割と簡単という点。テスト並列化のあとくらいに考えてみると良いと思う。