freeeの開発情報ポータルサイト

権限管理基盤チームのCIの仕組みと課題

こんにちは。権限管理基盤チームでQAをしているyukkyです。

freee QA Advent Calendar2024 20日目です。

所属してるチームで運用しているCIの仕組みと課題について書こうと思います。

CI作成の背景

権限管理基盤チームでは、権限制御を担うマイクロサービスを開発しています。

このプロダクトはUIが少なく、APIテストを中心にしたテストを行っています。

機能追加のたびにテストシナリオを追加し、蓄積したテストシナリオは、リグレッションテストとして再利用しています。

以前の開発フローでは、PR単位でローカル環境にてリグレッションテストを実行していましたが、

シナリオ数の増加により、ローカル環境でのテスト実行が長時間になり、テスト実行中はローカル環境が占有され開発ができないという課題がありました。

これを解決するため、現在はPR作成時にGitHub Actionsを利用してテスト環境を構築し、

CIで実行する仕組みを導入することで、以前より効率的にテストを実施できる仕組みを整えました。

CI実行の仕組み

早速ですが以下のようなイメージのフローで運用しています。

PRの段階でlabel選択をトリガーにGitHub Actionsが実行され環境構築/テスト実行が行われるフローイメージ図
CIによるリグレッションテストのフローイメージ

依存サービスのセットアップ

テスト実行に必要なサービスが多く存在します。

セットアップに時間がかかるサービスは事前に準備(GitHub Actions①)しておきます。

1.テストで利用する依存サービスをGitHub Actions上であらかじめセットアップする

2.セットアップして用意できたDBをdumpする

3.DBdumpしたファイルをAmazon S3にアップロードする

EngがPR作成してからの動き

1.EngがGitHub上でPRを出す

2.PRにあるlabelsにテスト対象の機能ごとに用意された選択肢から選ぶ

3.labelsの選択がトリガーとなり、GitHub Actions②が開始する

4.GitHub Actions上で、作成されたPRに基づいて、権限管理基盤サービスをDocker Composeで起動し、テスト環境を構築する

(このとき、あらかじめAmazon S3に用意した依存サービスのDBをdumpしたファイルをダウンロードしてリストアする)

5.権限管理基盤サービスを対象に、テスト実行環境からAPI実行ツールを用いてテスト実行する

(API実行ツールとしてrunnというOSSを使用しています。追加したシナリオはyamlファイルベースで蓄積することができ、リグレッションテストとして再利用しています。)

工夫している点

並列実行させる

シナリオ数が多いため、並列実行させることで時間を短縮しています。

単にテスト実行を並列化すると、シナリオ同士のデータベースに登録する内容が影響しあってしまい、テストが失敗する原因になるため、

テスト実行のみを並列にしているのではなく、テスト環境もそれぞれに並列で用意しテストを実行しています。

依存サービスのDBセットアップをCIが行われる前までに用意しておく

依存サービスではありますが、テスト実施時に常に最新である必要はないため、

CI実行時に依存サービスのセットアップで時間がとられないように、テストを実施するCIとは別で事前に依存サービスのセットアップを実行しています。

テスト対象の機能ごとにlabelを用意し、対象機能のみのテストを流せるようにする

APIによるe2eテストにはrunnというAPIテストツールを利用しています。

このツールはYAMLで記述可能で、チェーン形式でAPIを呼ぶことができます。

github.com

runnにはlabels機能があります。(GitHubのlabelsとは別物です)

https://github.com/k1LoW/runn?tab=readme-ov-file#labels

desc: Login
runners:
  req: https://example.com/api/v1
labels:
  - auth
  - regression
steps:
[...]

上記のようにlabelを付与しておくと、実行時にlabelオプションをつけ、指定したlabelのあるシナリオのみ実行することができます。

runn run scenario/*_testcase.yaml --label 'auth and regression'

GitHubのPRで選択されたlabelを元に、runnで用意したlabelのついたシナリオのみ実行されるように紐づけています。

このようにすることで、明らかに影響範囲が限定的な開発に対してをすべてのリグレッションテストを実施することなく、必要な機能のテストシナリオのみ実施することが可能です。

また、labelで新規機能開発で用意されたシナリオなのか、リグレッションテストに含めたいシナリオなのかを区別して実行することもでき、大変便利です。

毎朝定期実行する

CIと同じ環境でリグレッションテストを毎朝実行しています。(毎朝GitHub Actions②が実行され、結果がslack通知されます。)

CI実行前の状態でAPIによるe2eテストに問題がないことを確認することで、

EngがいざCIで実行しようとした時に、できるだけ本質ではない部分でトラブルが発生しないようにしています。

現在の課題

適切なlabel設計

PR上で選択されるlabelの多くが、「すべてのシナリオを実行する」意味をもつlabelです。

Engにとって必要な粒度で機能を切り分けられているか検討が必要だなと感じます。

また、runn側で持たせているlabelも複雑化してきており、管理のしやすい設計に見直す必要があります。

リグレッションテストの適正量

並列実行が可能になったものの、シナリオ数は増加し続けています。

APIによるe2eテストでどの観点をカバーすべきかを明確にするため、integration testやunit testなど他のテストレベルとの役割分担を議論しています。

テストレベルを明確化することで、APIによるe2eテストの適正な範囲と量を見極めていきたいと考えています。

さいごに

課題はまだまだ山積みですが、開発効率を損なわず、必要十分な品質を保つ仕組みを模索し、

改善を重ねながら、チーム全体でより良い開発体験を目指していきたいです。

ちなみに私はこれらをメンテしているだけで、環境構築してくれたのは、自動テストの運用・改善や基盤開発などを行っているSEQチーム (Software Engineering in Quality) です。頼れる素敵軍団です。

SEQチームメンバーもfreee QA Advent Calendar2024に記事を掲載しているので、ぜひご覧ください。

  • zakiさん:

E2Eテスト分析基盤としてReportPortalを導入しました - freee Developers Hub

  • nakamuさん:

ページオブジェクトモデルを採用しているE2Eテスト基盤の実装Tips - freee Developers Hub

明日はfreee人事労務のkairi - sanが「QAがUIのスナップショットテストを書いてみた話」について書いてくれます。お楽しみに!

それでは、良い品質を〜