概要
テストが膨らんできて、それにともないCI待ちの時間が増えてきた。困ったのでいろいろ設定してたら1/3くらいに短縮できたのでメモ。
本記事はCircleCI、Ruby on Rails、RSpec、 それと parallel_tests の使用が前提になっている。
方針:
- テストサーバは precompile 前提で起動する
- CIのキャッシュをきちんと設定する
- parallel_tests の並行テストを実行時間で割り振る
テストサーバは precompile 前提で起動する
RSpec の --profile
オプションで遅いテストを調べると、 controller か e2e テストの1件目のみが異様に遅く、2件目の4倍〜10倍近くかかっていた。どうやら assets のコンパイルに時間がかかっているようなので、プリコンパイルを前提に起動することにした。これで極端に遅いテストがなくなった。
# precompile前提で起動
config.assets.debug = false
config.assets.digest = true
config.assets.compile = false
CIのキャッシュをきちんと設定する
遅いテストが無くなる代わりにプリコンパイルする時間がその分かかるようになったので、プリコンパイルした成果物をCIにキャッシュさせるようにした。こちらは以下の記事を参考に設定した。みんなのウェディング様、クラウドワークス様ありがとうございます。
- Ruby on Railsのスローテスト対策で効果があったものなかったもの - みんなのウェディングエンジニアリングブログ
- CircleCI 2.0に移行して新機能を活用したらCIの実行時間が半分になった話 - クラウドワークス エンジニアブログ
parallel_tests の並行テストを実行時間で割り振る
RSpec の実行に parallel_tests を使っていたのだが、割り振りが良くないようで、2並列のときに片方は3分でもう片方は7分みたいな偏りが出て4分が無駄になっていた。
parallel_tests のテストケースの割り振りはデフォルトだと「実行時間もしくはファイルサイズ」になっているが、実行時間を分析させるためには runtime log を用意する必要がある。
--group-by [TYPE] group tests by:
(中略)
default - runtime when runtime log is filled otherwise filesize
(parallel_test --help
の出力より)
runtime log を得るには専用のフォーマッタを指定してテストを実行する。以下のように .rspec_parallel
を設定してテストを実行。以下の例だと tmp/parallel_runtime_rspec.log
に runtime log が出力される。
--format ParallelTests::RSpec::RuntimeLogger
--out tmp/parallel_runtime_rspec.log
runtime log ができたら、以下で実行する。これで並行テストが効率的にできるようになった。
bundle exec bin/parallel_rspec
--runtime-log tmp/parallel_runtime_rspec.log
(parallel_tests のオプション指定方法でちょっとハマった。 直接指定するものと起動設定ファイルに書くものがあるっぽく、 --format
は直接指定して実行するとエラーになり、 --runtime-log
は .rspec_parallel
に書くとエラーになった)
CIでの実行
上記の例は公式ドキュメント通りだけど、良心的にgitを管理してると tmp
ディレクトリは .gitignore
で無視られてて忘れがちなので、CIでも runtime log が見れるようにgit管理下に含めておく。もしくはCIで持ち回れるようなキャッシュ設定を作る。