はじめに
テストのデータベースクリーニングをする gem としては、DatabaseCleaner と DatabaseRewinder がメジャーどころとしてあります。
今回は 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 の記事を参照してください。
テスト時では閾値とを INSERT するデータ量を小さくするなどの定石があったりするため、テストの作りや RDBMS によって deletion
の方が速いことがあるというのはなるほどというものでした。長年開発を続けてスキーマやデータが変遷しているようなアプリケーションは一度計測し直してみて良いかもしれません。
まとめ
実際のところ、どちらが速いというよりはコンテキストによるようなので、テストが遅いなあと思ったら、戦略を切り替えてみるとテストが速くなることがあるかもしれません (し遅くなるかもしれません) 。CI の結果を計測してみましょう。
マジかというものですが、事実のみを示す数字によるとデータベースクリーニングで 30 分くらい余計にかかっていたわけでした。
最後に過去発表した関連スライドのページをのせておきます。
今日はここまでです。ハックを続けましょう。