DatabaseCleanerを使ったテストを倍速にした設定の見直し

はじめに

テストのデータベースクリーニングをする gem としては、DatabaseCleaner と DatabaseRewinder がメジャーどころとしてあります。

github.com

github.com

今回は DatabaseCleaner の話です。

クリーニング戦略を切り替えて計測する

DatabaseCleaner では transaction, deletion, truncation といったデータベースのクリーニング戦略があり、E2E での非同期 UI 系のテストでは transaction 以外を選択することになると思います。

早速結論ですが、非同期 UI 系のスローテストについて truncation から deletion に変えたところ 60 分の CI が 30 分になりました。

     if example.metadata[:javascript]
-      DatabaseCleaner.strategy = :truncation, {except: MASTERS}
+      DatabaseCleaner.strategy = :deletion, {except: MASTERS}
     else
       DatabaseCleaner.strategy = :transaction
     end

RDBMS によると思うのですが、truncation は (deletion に比して) 概ね固定された実行効率であることに対して、deletion はデータ量に依存したり変動要素が多いようです。 そしてこれらは、どちらが優れているというものではなくコンテキストによって選択されることになります。

詳しくは DatabaseCleaner から参照されている Stack Overflow の記事を参照してください。

stackoverflow.com

テスト時では閾値とを INSERT するデータ量を小さくするなどの定石があったりするため、テストの作りや RDBMS によって deletion の方が速いことがあるというのはなるほどというものでした。長年開発を続けてスキーマやデータが変遷しているようなアプリケーションは一度計測し直してみて良いかもしれません。

まとめ

実際のところ、どちらが速いというよりはコンテキストによるようなので、テストが遅いなあと思ったら、戦略を切り替えてみるとテストが速くなることがあるかもしれません (し遅くなるかもしれません) 。CI の結果を計測してみましょう。

マジかというものですが、事実のみを示す数字によるとデータベースクリーニングで 30 分くらい余計にかかっていたわけでした。

最後に過去発表した関連スライドのページをのせておきます。

www.slideshare.net

今日はここまでです。ハックを続けましょう。