こんにちは、基盤本部マーケティングプラットフォーム部の横山です。 今回は現在私が所属するグループで開発・運用中の自動GUIテストシステムについてご紹介します。
テストコードのメンテナンスコストを下げる画像回帰テスト
ソフトウェア開発における自動テストには、関数やAPIの動作を確認するJUnitによる単体テストから、ユーザーの操作をシミュレートするSeleniumによるエンド・ツー・エンドテストまで、様々な種類があります。そして、どの自動テストでも問題になるのはテストコードのメンテナンスです。
私のグループは画面の開発を担当していますが、画面は改修の頻度が多く、テストコードのメンテナンスに莫大な工数がかかってしまうことが問題でした。
できるだけテストコードのメンテナンスをしなくても実現できる自動テストがないか検討した結果、今回ご紹介する自動GUIテストシステムの形にたどり着きました。いわゆる画像回帰テスト(Visual Regression Testing)ツールです。
スクリーンショットを比較し、差異を検出する
私たちが開発・運用中の自動テストシステムでは、スクリーンショットを比較することによってアプリケーションをテストします。
例えば、アプリケーションを改修した場合、その改修をデプロイする前に撮ったスクリーンショットと、デプロイした後に撮ったスクリーンショットの差異を自動的に検知して
- 変わるべきところが変わっていること
- 変わるべきでないところが変わっていないこと
を視覚的に確認できるように表現します。
具体的な仕組みとしては、テスト対象ページのURLを指定してテストを実行すると、そのページのスクリーンショットを取得します。そのスクリーンショットが残っている状態で再度同じURLを指定して実行すると、同じようにスクリーンショットを取得して前回撮ったスクリーンショットと比較し、差異を検出します。
実際にBIGLOBE個人会員向けのマイページに対してテスト実行した結果が下図になります。
↓1回目の実行で取得したスクリーンショット(差異部分)
↓2回目の実行で取得したスクリーンショット(差異部分)
差異がある部分は赤くマークされ、一目で差分を確認できます。
上記の例で差異が検出された箇所は、実はページを表示するたびにランダムで変わる部分であり、差異が出るのは想定内でした。 こういった想定内の差異については比較対象外にしておかないと、本来検出すべき他の差異の通知が埋もれてしまうかもしれません。 そこで、要素を指定して比較対象外とするマスキング機能も開発しています。 マイページの例をマスキングして比較した結果が下図になります。
指定した要素が黒く塗りつぶされ、差異として検出されないことがわかるかと思います。
向いている使い方
この自動GUIテストシステムの最大の強みはタイトルにもある通り、テストコードを書く必要がほぼないことです。
行っているのは「指定のURLにアクセス→スクリーンショットを撮る→前回の結果と比較する」だけなので、動作がテスト対象の画面に依存しません。
POSTで遷移するページなど、URLを指定するだけではたどり着けないページについてはテストコードを追加で書く必要がありますが、遷移の操作のみの最小限のコードで済ますことができます。
そのためメンテナンス工数を大幅に削減できるほか、様々なアプリケーションに対し汎用的に使用できます。
よって下記のようなケースに向いています。
- 何度も細かい改修が入りその度に回帰テスト(別の箇所で不具合が発生していないかを確認)をするアプリケーション
- 影響範囲が広く、多数のページへの影響を確認する必要がある改修
- 定期的に実行し、予定外の変更やシステムダウンを検知する、監視目的としての使用
スクリーンショットを使うので、データベースやログなど、画面を対象としない(視覚的変化がない)テストには向いていません。画面以外のテストは別のツールで補います。
過去のシステム構成
この自動GUIテストシステムは様々なアプリケーションに対して汎用的に使用できることが利点であるため、開発環境に同居させてローカルで実行するのではなく、サーバー上でサービスとして実行することでより効果を発揮します。
そのため、最初は下記のようにJenkinsを使った構成で運用していました。
- Amazon EC2インスタンス上でJenkinsを動作
- 各テストケースはJenkinsのジョブで管理
- ジョブを手動で実行するか、定期実行することでテストを実施
- 差異が検出されたらメールとGoogle Chatへ通知
しかし、利用するアプリケーションが増えるにつれて
- 複数のジョブを並列実行すると性能不足でJenkinsが動かなくなってしまう
- テスト対象ページやブラウザが多くなると、テスト完了まで30分以上かかる
- ジョブの数が多くなり、それぞれで設定が異なったりなど、管理が難しい
といった性能面、運用面の問題があることがわかってきました。
性能面についてはEC2で実行しているので、性能の良いインスタンスタイプに変えるかオートスケーリングを使用すれば解決できたかもしれません。 ただ、そもそもストレージなども含めたインフラ面の管理をしたくなかったため、なんとか管理をしなくても済む構成を作れないか考えました。
サーバーレス構成への移行
Jenkinsで発生した問題を解決し、かつインフラ面の管理をしなくても済む構成を考えた結果、Amazon Web Services(AWS)のマネージドサービスを使ったサーバーレス構成を構築することにしました。
試行錯誤の結果、たどり着いた構成が下図になります。
使用したサービスは下記のとおりです。
AWS CodeBuild
- 自動テストシステムを実行するメインのサービスです。 テストを実施するブラウザとWebDriverをインストールし、ヘッドレス実行でテストします。 CodeBuildの実行環境はビルドごとにそれぞれ別の環境が構築されるため、他のテストに影響を与えることはなく実質無制限の同時実行が可能になりました。
Amazon S3
- テスト結果を格納するために使用しています。
テスト結果はバケットポリシーで社内向けに公開し、社内であればどこからでもテストレポートを確認できるようにしました。
- テスト結果を格納するために使用しています。
EC2 Image Builder
- CodeBuildで使用するDockerイメージを作成します。
自動テスト実行時、ブラウザに新しいバージョンがあった場合はイメージを自動で作り直すようにし、常に最新バージョンのブラウザでテストが実行されるようにしています。
- CodeBuildで使用するDockerイメージを作成します。
Amazon ECR
- Image Builderで作成したイメージを格納するために使用します。
Amazon SES
- 画面の差異が検出された際に、通知メールを送信します。
Amazon EventBridge
- テストを定期実行するために使用します。
AWS Systems Manager Parameter Store
- テストで使用する設定項目の管理に使用するほか、アプリケーションごとのテストケースを名前を付けて管理することで、Step Functions実行時にテストケース名を指定するだけで実施するテストを切り替えられるようにしました。
AWS Lambda
- 細かいテスト結果の取りまとめのほか、差異検出の通知をGoogle Chatにも飛ばすために使用しています。
AWS Step Functions
- それぞれのサービスを結合し、一連の流れとして実行するワークフローを構成するために使用しています。
AWS CloudFormation
- 上記構成を設定ファイルで管理するために使用しました。
工夫した点
Jenkinsからサーバーレス構成に移行するにあたって解決すべき課題として下記がありました。
- Jenkinsで発生した性能面、運用面の問題を解決できること
- インフラ管理の手間をできるだけ減らすこと
1.についてはCodeBuildでテストを実行することで解決できました。並列実行が可能になったことにより、マルチブラウザテストを並列で行えるようになり、テストにかかる時間も短縮できました。
2.についてもスケーリングの設定や評価も含めてAWSに丸投げすることができ、インフラ管理の手間をほぼ0にできました。
それ以外に工夫した点が2点あります。 1つはテストレポートに誰でもアクセスできるようにしたことです。 Jenkins構成の時はJenkinsの中に結果が出力されるため、閲覧するためにはJenkinsにログインする必要があり、不便で何とかしたいと思っていました。 S3に置くことで、バケットポリシーで許可されていればブラウザで簡単に閲覧できるようにしました。
もう1つはAWSサービス構成や各設定項目などを、CloudFormationテンプレートファイルで管理できるようにしたことです。 別途ドキュメントで管理してもいいのですが、ちゃんと継続してメンテナンスできるか不安でした。CloudFormationを使用すると、リソースを更新する時にはテンプレートファイルも更新が必要になります。その結果、意識しなくてもテンプレートファイルには必ず最新のリソース状態が反映されるようになります。更にGitでバージョンを管理できるようになりました。
おわりに
スクリーンショット比較テストはいろんなアプリケーションに対して応用が利き、なかなか可能性を秘めた自動テストシステムなのではと自分のグループのことながら思っています。
サーバーレス構成についても、いろんな課題をきれいに解決できてよかったと思います。個人的には直近で合格したAWS認定デベロッパーアソシエイトの知識を活かすことができて楽しかったです。
今回は実際の業務で開発・運用しているシステムについてご紹介しました。いろんなアプリケーションに汎用的に使える自動テストシステムですので、自グループに留まらず他グループでも利用できるよう、運用方法も含めてブラッシュアップしていきたいと思います。
※ 記載している団体、製品名、サービス名称は各社またはその関連会社の商標または登録商標です。