Circle CIを速くしようと思ってみた
スタディスト開発部、伴です。エレベーターの閉じるボタンは基本連打します。
はじめに
この登壇にあるように当初はテストなんかほとんどありませんでした。
現在スタディストではUIリニューアルを進めているのですが、そちらのプロジェクトに関してはCircle CIのテストが終わるのに50分程度かかるようになってしまいました^^;
1年半前は、modelのテストが数行ある程度だったのですが、今では3万数千行のテストが走る様になったのです-_-b
そうすると、PRのapproveが通ってるのにテストが終わらずマージ出来ないとか、テスト待ちで生産性下がるなど現場から不満が多く出てくる様になりました。
そこでテストを早く出来ないかと色々試してみました。
試したこと1
まず最初に試したのが、pararell_testというgemです。parallel_testsは、マシンにあるCPUの数だけテストのプロセスを起動して並列実行するgemです。
CircleCIの1コンテナには、2CPU 4GBのメモリがある為、2並列でテストを流してみました。確かに5分程度早くなりました。
しかし、parallel_testsは他のテストの影響を受けないようにするために、複数のデータベース作る必要がある為、それらのマイグレーションで時間が掛かってしまい余り思ったほどの効果がありませんでした。
試したこと2
今度はCircle CIの機能を使いコンテナ毎にテストを分けて実行するようにしました。
- run:
name: RSpec tests
command: |
TESTFILES=$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=filesize)
bundle exec rspec -- $TESTFILES上記の様に、.circleci/config.yml を設定してコンテナ毎にテストを実行する様にしました。
そうするとテストがどんどんコケ出しました(´Д` )。
なぜコケたのか分からなかった為、ウンウン言いながら調べました。調べた結果、並列のテストの順番に依存した書いていたからということが分かりました、、、
テストをランダムに実行する設定を入れて、エラーになったテストを抽出しました。
rails_helperに以下設定を入れました。
config.order = 'random'そうすると、順番に依存したテストやDBの状態に依存したテストや不要なテストがあったのでそれらを修正するようにしました。
例で出しますと
修正前
before(:all) { @hoge = Hoge.create }修正後
let(:hoge) { FactoryBot.build :hoge }このようにDBの状態に依存するテストを修正しました。
そうして、2コンテナ並列でCircle CIを実行すると、50分→30分で終了する様になりました。
コンテナ数が少なくて実行待ち時間が長くなるとか、環境構築に時間がかかるなど多数問題がありましたが、そこらへんは弊社@valeraukoに次回のブログで話してもらえると思います。(※現在はcircle ciのテスト10分程度で終わる様になっています。)
終わりに
現在スタディストでは、マニュアル作成・共有プラットフォームTeachme Bizを一緒に開発していくエンジニアの仲間を募集しています。
テストのない環境で働いていてうんざりしている方、若しくは、テストを早くしたいエンジニア、環境を改善していくことに興味のあるエンジニアのかた是非ともお気軽にお声がけ下さい。
