Cypress + TestRail による Frontend E2E テストの効率化について
Merpay Advent Calendar 2020 の 8 日目は、メルペイフロントエンドチーム の @tanakaworld がお送りします。
2020 年後半からフロントエンドチームと QA チーム合同で、リグレッションテストの自動化に取り組んできました。E2E テストフレームワークである Cypress でマニュアルテストを自動化し、加えて TestRail を用いてテストケース管理も仕組み化することでワークフローの整備を進めています。本記事では、それらの取り組みについて紹介します。
リグレッションテストとは
実装を変更した結果、アプリケーション全体の振る舞いに予期せぬ影響がないかどうかを確認するテストです。メルペイではリリース前 QA の最終フェーズでリグレッションテストを実施しています。Web アプリケーションを End To End (E2E) でテストすることで、フロントエンドだけでなくバックエンド・インフラなども総合してテストすることができます。
2020 年前半までは、リグレッションテストの大半を QA エンジニアが手作業で行っていました。リリースの度に繰り返し実施されるので、自動化することで QA 負荷を軽減し、効率化・迅速化を図りたいと考えました。
Cypress
メルペイでは E2E テストのフレームワークに Cypress を採用しています。技術選定や基盤構築、初期の自動化はフロントエンドエンジニアを中心に進めました。
メルペイではプロダクト開発のエンジニアと QA エンジニアで役割分担をしています。プロダクト開発のエンジニアが単体テストやインテグレーションテストを書きます。それとは別に、リリース前のリグレッションテストは QA エンジニアが担当するという分担です。そのため、フロントエンドエンジニアだけでなく、我々が採用する技術を知悉 (ちしつ。知り尽くしていること) しているとは限らない QA エンジニアにも扱いやすくなることを重視しました。選定理由を次にまとめます。
- 動作が安定している
- フレームワーク起因でランダムにテストが落ちるということが少ない
- セットアップが容易である
- 複雑なセットアップが必要なく動作が安定している
- Puppeteer と比較して自前で設定すべてきことが少ない
- 半年ほど検証していたが自由度の低さで大きく困ったところはなかった
- デバッグが容易である
- GUI で実装結果を確認し、どこがおかしいかすぐわかる
- テストステップごとの変数や DOM の状態が記録され、追いかけて再生ができる
- ドキュメントが充実している
- トレードオフもあるが、自分たちのやりたいことの足かせにはならないと判断した
- ユーザー数が多い
- 機能改善やディスカッションが盛んで、開発スピードも速い GitHub
- Puppeteer と同じくらい多くの人に継続的に使われている (npm trends)
- コミュニティや公式の Plugin が充実しはじめている
テストコードの品質
コードカバレッジだけでなくテストコードの品質にも注意を払っています。テストが自動化されていても、メンテナンスしづらいテストコード・壊れやすいテストコードだと、後々自分たちを守る盾ではなく、足枷になってしまいます。そのため、いくつかルールを決めています。
- ベストプラクティスに則る
- プロダクトコードと同じ技術スタックを用いる (TypeScript, ESLint, Prettier など)
- コードレビューをする
その他、フロントエンドチームと QA チームで一緒に、ハンズオンやペアプログラミングを実施したり、Cypress の動向をシェアするなどをしています。
テストデータ作成
リグレッションテストはテスト環境に対して実施します。テスト環境は本番とほぼ同等の環境で、すべてのマイクロサービスがデプロイされた環境になります。
テストする内容によってあらかじめテストデータを用意するケースと、テスト実行時に動的にテストデータを作成するケースがあります。すべてのテストデータを都度作成していると、テスト実行時間が膨大になってしまいます。テストの実行中にデータが更新される場合は、データの使いまわしはせずにそのテスト専用のデータを都度作成する方針です。
- あらかじめテストデータを用意するケース
- 表示系のテスト(名前や登録日などが都度変わると困るため)
- 実行時にテストデータを作成するケース
- 更新系のテスト
- 削除系のテスト
Cypress Data Server
Cypress とテスト環境の間にテストデータ作成を中継する BFF を置いています。Node.js のサーバーで「 Cypress Data Server 」と呼んでいます(社内用語)。Cypress のテストコードはブラウザ上で実行されます。データ作成時に、ブラウザ上では動作させることのできない npm パッケージを用いた処理を実行したいニーズなどがあり、別サーバとして切り出しました。次がその構成イメージです。
Cypress 側は単に HTTP リクエストを送るシンプルな処理に留めています。テストデータ作成結果をレスポンスとして受け取り、テストコード上で扱うことができます。この構成は cypress-on-rails から着想を得ました。
beforeEach(() => {
cy.createUserData({ ••• }).then((user) => {
cy.wrap(user).as(‘user’);
});
});
現在は Postman と 社内ツールの user-tkool を用いたデータ作成をサポートしています。
Postman
QA チームは API のテストを Postman を使って実施していました。フロントエンドのテストを実行するときにその Postman のシナリオを用いてテストデータを作成できるようにしています。テストコードリポジトリ内で Postman のシナリオファイルを管理し、それを Cypress Data Server 経由で実行できます。
user-tkool
user-tkool は様々なメルカリ・メルペイのお客さまのデータを作成することのできるツールです。ある日 API 対応もなされ、シナリオに組み込めるようになりました。Cypress Data Server からその API を用いてデータ作成を行っています。
テストケースの管理
ここまで Cypress 導入の背景やテストデータ作成に関する取り組みを説明しましたが、テストケースの管理でも課題解決に取り組んでいます。
テストケースは Google Sheets で管理していました。自由度が高い反面、管理方法が属人化したり、手作業が増えていることに課題を感じていました。最終的に TestRail に移行することで課題解決を図りました。
Google Sheets 管理における課題
テストコードとテストケースの対応付けや、実施結果の確認などを人力で行っており、非効率さを感じていました。たとえば、次のような課題がありました。
- テストケースとテストコードの対応付けを、人間が正しくなるよう維持している
- テストを実施する度にシートを複製し利用するため、過去の履歴の把握が困難
- 自動テスト実施後、実行結果を目視してシートに手作業で結果を反映
- テストケース・テストコードの更新漏れによる検証漏れ
TestRail
TestRail はテストケース管理ができる SasS です。TestRail の概念と Cypress との連携方法を解説します。
Test Cases
Test Cases はテストケースのマスタです。TestRail の Web アプリケーション上でテストケースの新規作成・編集・削除ができます。ケースごとにユニークな ID が設定される他、自由にフィールドを追加することができます。フロントエンドチームでは Automation Status
というカスタムフィールドで、そのテストケースを自動化しているかどうかを定義しています。
- Manual: 手動でテストする (自動化できないケース)
- NotAutomated: 自動化できるが、まだ自動化していない
- Automated: 自動化済み
これらのフィールドを用いて、自動でカバレッジ計算を行っています。
Test Run
Test Run はテスト実施結果を記録します。テストケースのマスタである Test Cases をコピーする形で Test Run がつくられ、各ケースごとに結果を記録することができます。
Cypress の設定とテスト結果の連携
TestRail は API を提供しており、Web アプリケーション上でできることが API で実行できます。Cypress から TestRun の作成と、テスト実行結果の登録を実行しています。Cypress コミュニティの TestRail レポーター が存在しますが、社内のワークフローに合わせてレポートロジックを変更するなどしたかったため、Fork して拡張しています。
Test Case の ID をテストコードに設定し、次のフローで処理されます。
describe('未ログイン', () => {
it('[C123456] 〇〇が表示されること', () => {
cy.get('h2').contains('○○');
});
});
- Cypress 実行時に TestRun を作成
- Cypress のテスト実行ライフサイクルフックで ID を読み取り、実行結果を判定
- テスト結果を TestRun に登録
結果が連携されると、TestRail 上で次のような結果が閲覧できます。
自動化されていないテストケースは Status が Untested
となります。それらのケースは手動でテストをして、結果を反映します。
このように、自動化されているテストケースとそうでないテストケースを TestRail 上で一元管理することができるのも嬉しいポイントです。
ワークフロー
最後に、リリースするまでの実際のワークフローを紹介します。
-
テストケースの管理
- TestRail 上でテストケースを管理します
-
テストコード更新、コードレビュー
- ローカルで Cypress を実行しながらテストコードを書きます
- GitHub 上でコードレビューをします。コードが Push されると CircleCI 上で Cypress が実行されます
- このときは TestRail へのレポーティングはしません
-
テスト実行 + レポーティング
cypress run --reporter @merpay/cypress-testrail-reporter
とレポートオプションを指定して実行します- Cypress が実行されるのと同時に、TestRail の TestRun が作成され、テスト結果が自動連携されます
- Slack 上から実行できるようにする仕組みを検討中です
- 各自がラップトップに環境を構築することなく実行できるようになります
- また、テスト実行時はラップトップの処理が重くなります、CI 上では複数のテストを並列で実行することも容易です
- Slack からリグレッションテストのリポジトリ名とブランチを指定すると Bot が反応します
- Bot が CirclceCI の API Trigger を発行し CircleCI 上で Cypress を実行します
-
マニュアルテスト実施
- テストケースによっては、完全に自動化できないテストケースもあります
- 例:
- 非同期で定期処理されるバッチ処理: 1時間単位などで実行していて待てない
- メール送信処理: メール内容をテストコードから読み取る仕組みは今はない
- 例:
- 手動でテストを実施し、3. で作成された Test Run に結果を記録します
- すべてのテストが成功すればリリース可能な状態となります
- テストケースによっては、完全に自動化できないテストケースもあります
-
テスト結果の可視化
- TestRail の結果を集計して、テストコードのカバレッジを計算します
- CircleCI 上で定期的に実行され Google BigQuery 上にデータが登録されます
- 社内で様々な KPI を可視化するために Looker を用いています
- リグレッションテスト結果も同様に可視化して全員が見れるようにしています
まとめ・今後の展望
TestRail を用いてテストケース管理を仕組み化し、Cypress でマニュアルテストの大部分を自動化することができました。一方で新たな課題も見つかってきました。
- E2E テストが後回しになりがち
- 現在、自動化可能なテストの大半は自動化されています
- しかし、関連システムがすべて正常に動いていないとテストが進まない、一時的にマニュアルテストでも代替できてしまう、といったことが起こり自動化が後回しになりがちです
- 繰り返し実行されることがわかっているものであれば、はじめから自動化していきたいと思っています
- テスト実行に時間がかかる
- テストケースが増えてくると実行時間が増えてきます
- テストすべきものとそうでないもの、テストデータをどうつくるかなども重要になってきます
- 比較的、テストデータ作成に時間がかかっており、対応策を検討しています
- テスト結果が安定しない
- E2E でテストしているため関連するマイクロサービスのどれか一つでも不安定だとテストに失敗します
- それはテストデータ作成も同様です
などなど、今後も継続して改善に取り組んでいきたいと思います。
メルペイでは、プロダクト品質や Developer Experience の向上、テスト自動化に興味があるエンジニアを募集しています!
明日の Merpay Advent Calendar 2020 執筆担当は、Backend Engineer の sou さんです。引き続きお楽しみください。