Rista Tech Blog

株式会社リスタの技術?ブログ

だれも参考にならないと思うけどJOBLISTのrspecを14分から4分に短縮したから褒めて

Ristaの4人目エンジニアを募集中! iOS Android Rails

こんにちはこんにちは。

セブンにある蒙古タンメン北極のカップラーメンににんにくのチューブたくさん入れて食べたらお腹がいたくなった辻@dim0627です。

今回はちまちま直してたrspecの話をします。

CIマジで遅い問題

これほんとQOL下がる。そいえば最近は開発時の体験をDXとか言うらしいですね。

この問題は以前僕が居たときからあって、なんでかなーなんでかなーとあんまり真面目に調査せずに唸ってたんですが、今回もう堪忍袋の緒が切れたので遅いテスト全部ぶっ○してやる!!!というつよいきもちで対応しました。

やったこと

というわけでやったことをまとめるけど、タイトルにある通りたぶんよくあるパターンじゃないです。

suiteがどうとかexampleがどうとかそういうテクニカルな話は1個もでないよ!!

まずは何が遅いのかを知ろう

まあrspecが遅いのはわかってたんだけど一応みてみましょう。

f:id:dim0627:20180712101128p:plain

CIの設定は悪くないですね。完全にlintとtestが遅いですね。

じゃあrspecはどれくらいかと言うと、

f:id:dim0627:20180712101201p:plain

ほとんどこいつやんけ!

じゃあrspecが遅いのはわかったしバシバシ直していきます。

とりあえず遅いテストを探そう

うーん、まあ確かに遅いっちゃ遅いのもあるんだけど、ずば抜けて遅いのがあるわけじゃないし、なんか全体的に遅そう・・・。

f:id:dim0627:20180712101313p:plain

これは特定の遅いテストがあるのではなく、なんかやり方がおかしくて全体的に積み上げで遅いだけなのでは〜?

200を見るだけのfeature specをrequest specに

200を見るだけならfeatureじゃなくてrequestでよくない?という話になりまずこれを置き換えました。

個人的にこれ結構はやくなるんじゃないかな〜!と思ってたんですがもう何も変わらず。無風。

でもわかりやすさ的に画面いじったりしないならrequestでいいよねということでこれはこれで全部やりました。大変だったよ。

DatabaseCleaner、truncationじゃなくてtransactionでよくない?

もうね、結論からいうとこれ。

はやくなんねーなーと思ってspec_helper.rbrails_helper.rbを眺めてたらなんか全部truncationでやってた 😨

これだけで10分短縮された。まさかここだとは思わなかった〜!

f:id:dim0627:20180712104200p:plain

DatabaseCleanerは3つのクリーニング方法があって、truncate、transaction、deletionなんだけど、まあtransactionが使えるならそれが一番はやいよとは公式にも書いてある。

DatabaseCleaner/database_cleaner: Strategies for cleaning databases in Ruby. Can be used to ensure a clean state for testing.

この辺とりあえずコピペで使っちゃってたから調べる機会ができてラッキー!

rspecよくわからないマンなんだけど、transactionとtruncationを切り替えながらテストを書くのが普通なんですか?

Capybaraと併用するときはtransactionだとコネクションが違うから、未コミットのレコードが読めなくて困るらしいです。

公式からコピペ。

  config.before(:each, type: :feature) do
    # :rack_test driver's Rack app under test shares database connection
    # with the specs, so continue to use transaction strategy for speed.
    driver_shares_db_connection_with_specs = Capybara.current_driver == :rack_test

    unless driver_shares_db_connection_with_specs
      # Driver is probably for an external browser with an app
      # under test that does *not* share a database connection with the
      # specs, so use truncation strategy.
      DatabaseCleaner.strategy = :truncation
    end
  end

でもなんか弊社は平気だったな。弊社のテストだいじょうぶか?(これ絶対ダメなので別記事にします)

transactionにしたらここで躓いたよ

transactionにしたら速くなったしグリーンだしハッピー!ってわけじゃなかったのでそこだけメモっときます!

IDがインクリメントされていくのを考慮する

なんかファクトリで作ったレコードのIDを憶測して1とか2で見てるテストがあって、それはダメだでした。

transactionだとロールバックされた分のオートインクリメントは残るぽくて、そういうべた書きはやめてファクトリで作ったレコードのIDをちゃんと使うように変えました。

テストがランダムに落ちる

これ解決してないので僕の今日の仕事です。

あとたぶんまだまだはやくできるので、そしたらまた次の記事をかくぞ!