クラウドワークス エンジニアブログ

日本最大級のクラウドソーシング「クラウドワークス」の開発の裏側をお届けするエンジニアブログ

crowdworks.jpのCI事情とスローテスト調査内容の紹介

f:id:ryogift:20211217115247p:plain

この記事は クラウドワークス Advent Calendar 2021 の18日目の記事です。

こんにちは。crowdworks.jp で、市場投入までの時間短縮を目指して日々改善活動をしている @ryogift です。最近はCIのテスト実行時間改善に取り組んでいますので、その際に調査した内容を紹介します。

はじめに

CI(continuous integration)とは、自動でアプリケーションのビルドとテストを行うDevOpsソフトウェア開発の手法です。CIの目的は、バグを早期に発見して対処することやソフトウェアの品質を高めること、そしてソフトウェアの更新を検証してリリースするためにかかる時間を短縮することが挙げられます。

crowdworks.jpでは、CIツールにCircleCIのクラウド版を利用しており、テスティングフレームワークにはRSpecを利用しています。そのため、本記事ではCircleCIおよびRSpecの実行結果を基に調査した内容を紹介します。

背景

crowdworks.jpは、そこそこ巨大なモノリシックアーキテクチャで構成されたRailsアプリケーションです。CIのテスト実行時には全てのテストコードを実行しており、テストが完了するまでに16並列で実行して10分程度かかっています。基本的にテストコードは、機能改善や機能削除、抜本的なアーキテクチャの変更でも検討しない限りは増え続けていきますので、今後はさらに遅くなっていくことが予想できるでしょう。遅いテスト、つまりはスローテストを改善することは市場投入までの時間短縮につながります。スローテストの簡単な解決策といえば金の弾丸(お金)が候補としてありますが、無駄にマシンのリソースを利用することは昨今のSDGs的にも良くありませんので定期的にスローテストを改善することが望ましいと考えています。

現状の問題点

crowdworks.jpのテスト用CIには、複数のジョブが設定されています。どのジョブに時間が掛かっているかを確認するためにCircleCIのInsights機能を利用しました。

f:id:ryogift:20211217115420p:plain
テスト実行時の遅いジョブを抜粋

上記の画像では、テスト実行時のジョブごとに集計された30日間のデータを実行時間(95 パーセンタイル)の降順にした結果の一部を表示しています。画像のとおりに遅いジョブはRSpecのテスト実行ジョブであることが確認できます。

RSpecでスローテスト確認

RSpecdescribeというグループ内に複数のexample(it do ... end)を記述してテストしています。example単位で遅いテストを確認する方法として、RSpecでは--profileというコマンドラインオプションがあります。この機能を利用するとテスト実行後の出力結果に最も遅いテストの一覧を出力できます。

relishapp.com

例として、RSpecのオプション設定ファイル(.rspec)に以下のように記載するとRSpec実行時に最も遅いテストが30個出力できます。

--profile 30

CircleCI上で出力結果を確認してみると、以下の画像のように表示されます。

f:id:ryogift:20211217115412p:plain
CircleCI上でのRSpec出力結果

また、CircleCIのInsights機能を利用しても、直近のテストパフォーマンスを確認することができます。

circleci.com

f:id:ryogift:20211217115404p:plain
CircleCIのInsights機能のテストパフォーマンス例

RSpecexample単位で遅いテストを確認することが出来ましたので、遅いテストから個別にチューニングしていくと良さそうです。

FactoryBotのテストデータ投入時間確認

Railsのテストデータ生成にはFixture Patternのfixturesがデフォルトで組み込まれていますが、crowdworks.jpではFactory PatternのFactoryBotを利用しています。Factory Patternは動的にテストデータを生成するために、テストデータの組み合わせによって生成に時間がかかる場合があります。実際にFactoryBotでテストデータを投入している時間を計測して、テスト実行時間にどのくらい影響しているかを確認してみました。計測にはTestProfというライブラリを利用しています。

github.com

TestProfをGemfileに追加して、RSpec実行時に以下のように指定するとfactory.createした時の時間が計測できます。

# Gemfile
group :test do
  gem 'test-prof'
end
EVENT_PROF="factory.create" bundle exec rspec

下記の画像のように結果が出力されます。Total time:"factory.createしている時間" of "テストの実行時間"の形式で、factory.createの遅い順に5件出力されます。crowdworks.jpでは16並列ごとに確認した結果、factory.createに60%〜80%程度の時間がかかっていることが確認できました。テストデータ生成を最適化できれば、大幅にテスト実行時間を短縮できそうです。

f:id:ryogift:20211217115354p:plain
CircleCIでTestProfを利用したRSpecの出力結果

マシンのリソース確認

最近CircleCIのクラウド版にJob単位でマシンのリソースが確認できる機能が追加されました。下記はテスト用CIのRSpecジョブのリソースになります。

f:id:ryogift:20211217115351p:plain
CircleCIでRSpec実行時のリソース利用状況

CircleCIはジョブ実行時にマシンスペックを指定することができ、マシンスペックごとに利用料が異なりますので、最適なマシンスペックを選択するときに本機能が役立ちそうです。また、テスト実行時の処理性能が低い場合はマシンスペックを下げて並列数を増やすことで、利用料が変わらなくても全体のテスト実行時間を短縮することが出来るでしょう。

まとめ

以上が、crowdworks.jpのCI事情とスローテスト調査内容になります。スローテストの調査はツールやライブラリを利用することで簡単に見つけることができました。

テストコード作成時には、そこまでテスト実行時間を気にする機会は多くないと思いますが、スローテストは塵も積もれば山となるで全体のCI実行時間に影響しますし、さらに市場投入までの時間が遅くなっていきます。気づいたら手がつけられなくなる前に定期的に改善していくことが望ましいでしょう。

スローテストの改善は、これから行っていきますので改善した結果や改善内容は、また別の機会に記事にできたら掲載したいと思います。

それでは、明日の記事は @eiji_osakabe さんです。お楽しみに!

参考

CircleCIの消費クレジットとRSpecの実行時間を半減させるために行った9の手順

TestProf(2) Rubyテストの遅いfactoryを診断治療する(翻訳)

Introduce-my-gem-factory_strategist

We're hiring!

クラウドワークスでは、様々なポジションのエンジニアを募集しております。 ご興味のある方は、ぜひご連絡ください!

crowdworks.co.jp

© 2016 CrowdWorks, Inc., All rights reserved.