メルマガ登録
自社開発プロダクト「Rtoaster」をはじめとする製品群を扱うXaaSユニットの社員によるエンジニアブログです。今回は、反比例になりがちな「テストの拡充」と「開発効率」の両立に向けた課題を解決するため、CI/CD自動テストの高速化を実施した事例をご紹介します!
XaaSユニット プロダクトエンジニアリング所属の田中です。
ブレインパッドは、企業のデータ活用・DXやデジタルマーケティングを支援するデータビジネス・プラットフォームRtoaster(アールトースター)を開発・提供しています。
現在、「Rtoaster」では品質改善のため、テスト拡充に重点的に取り組んでいます。テストの拡充により、信頼性の高いプロダクトを開発することが可能となりますが、一方でテストケースの増加は開発効率や開発者体験に影響を及ぼします。今回この課題を解決するために、CI/CD自動テストの高速化を行いましたのでその事例を紹介します。
今回のCI/CD自動テスト高速化の対象は、フロントエンドで以下のような構成となっています。
フレームワーク:Nuxt2 (Vue2 , Composition-API)
言語:TypeScript
テストツール:jest, swc, vue-test-utils, vue-testing-library
CI:CircleCI
すでに高速化の取り組みとして、ts-jest(tsc) の代わりにswcの導入、Typescript4 から 5へのアップデートなどを行い、テストの速度を約20%向上しています。しかし日々増え続けるテストケースにより、CI/CDの実行が40分以上かかっている状況でした。
まずワークフロー、ジョブの見直しを行いました。ビルドとテストが結合されたジョブとなっていたため分解し、さらにテスト内のlint, prettier, unittest, integration test も細かく分解しました。これにより後述するテストの分割・並列処理実行時にリソースを効果的に利用することができるようになります。
そして各ジョブの前段にnpm moduleをキャッシュするジョブを追加し、後続ジョブでキャッシュを利用するようにしました。
ジョブを最適化し、1日1回CIを定期実行することで品質面は担保しつつ、デプロイ時は自動テストをスキップ出来る構成とし時間を短縮しました。
変更前、変更後のワークフローは以下になります。
次にテストの実行時間がボトルネックとなっていたため、テスト分割し並列実行を行いました。
分割方法はタイミングベースを利用することで、以前のテスト実行のタイミングデータを使って適切に均等となるように分割してくれます。
以下が設定例です。
unittest-frontend:
executor: frontend-base
parallelism: 4
resource_class: large
steps:
- run:
name: Test
command: |
TESTFILES=$(circleci tests glob "tests/*/.test.ts" | circleci tests split --split-by=timings)
npm run test -- $TESTFILES
この並列実行により、全体の実行時間を短縮することができました。
テスト分割・並列実行するデメリットとして、従来の方法では全体のカバレッジが取得できなくなってしまいます。これを解決するため、各ノードで生成されたカバレッジを結合し、全体のカバレッジが生成できるようにしました。
各ノードで実行されたカバレッジデータをpersist_to_workspace を使ってジョブ間で利用できるようにします。この時$CIRCLE_NODE_INDEX を利用しカバレッジデータの保存先がノード間で重複しないようにします。
run:
name: Test
command: |
TESTFILES=$(circleci tests glob "tests/*/.test.ts" | circleci tests split --split-by=timings)
npm run test -- $TESTFILES
mv target/coverage coverage_$CIRCLE_NODE_INDEX
persist_to_workspace:
root: /home/circleci/project
paths:
coverage_*/
combine_coverage というジョブでは以下の処理を行ってます。
combine_coverage:
executor: frontend-base
resource_class: medium+
steps:
- attach_workspace:
at: /home/circleci/project
- run:
name: Install module
command: npm install nyc istanbul-merge istanbul
- run:
name: Combine coverage report
command: |
cp -R hoge/coverage_* ./
npx istanbul-merge --out coverage/coverage.json coverage_*/coverage-final.json
npx istanbul report --include coverage/coverage.json --dir coverage html
- store_artifacts:
path: coverage
このようにして、並列に実行したテスト結果をCI上で一元的に確認できるようになりました。
これらの取り組みの結果、CIの実行時間は42分から18分に、デプロイの時間も42分から7分に短縮し、それぞれ2.3倍、6倍の高速化を実現することができました。
今後もプロダクトの品質を維持しつつ、開発効率、開発者体験を向上する取り組みを続けていきたいと思います。
ブレインパッドでは新卒採用・中途採用共にまだまだ仲間を募集しています。 ご興味のある方は、是非採用サイトをご覧ください!
https://www.brainpad.co.jp/recruit/recruit/graduate.php
https://www.brainpad.co.jp/recruit/recruit/career.php
あなたにオススメの記事
2023.12.01
生成AI(ジェネレーティブAI)とは?ChatGPTとの違いや仕組み・種類・活用事例
2023.09.21
DX(デジタルトランスフォーメーション)とは?今さら聞けない意味・定義を分かりやすく解説【2024年最新】
2023.11.24
【現役社員が解説】データサイエンティストとは?仕事内容やAI・DX時代に必要なスキル
2023.09.08
DX事例26選:6つの業界別に紹介~有名企業はどんなDXをやっている?~【2024年最新版】
2023.08.23
LLM(大規模言語モデル)とは?生成AIとの違いや活用事例・課題
2024.03.22
生成AIの評価指標・ベンチマークとそれらに関連する問題点や限界を解説