🖥️

簡単で便利なE2Eテスト自動化を夢見て(2)

に公開

FEConf2024で発表された〈簡単で便利なE2Eテスト自動化を夢見て〉をまとめた記事です。発表内容を2回に分けて公開します。第1回ではE2Eテスト、そのテストを支援するツール、そして保守コストを下げつつ効率的にテストコードを蓄積する方法を学びます。第2回ではテストコードの再利用とモジュール化、さらにPlaywrightを改善した内容を取り上げます。本文に挿入された画像の出典はすべて同じタイトルの発表資料であり、個別の出典表記はしていません。

〈簡単で便利なE2Eテスト自動化を夢見て〉
ペク・ブソク Stibee CTO

  • 簡単で便利なE2Eテスト自動化を夢見て (1)
  • 簡単で便利なE2Eテスト自動化を夢見て (2)

前回の記事では、E2Eテストとそれを支援するテストツールについて解説しました。また、認証フローを通過しながら効率的にテストコードを作成する方法も紹介しました。今回は、E2Eテストの重要な最終段階であるモジュール化による再利用、さらにPlaywrightを改善した内容についてお話しします。

モジュール化と再利用

テストコードにおけるモジュール化とは何を意味するのでしょうか?

たとえばログインのテストコードを作成した場合、このコードは多くのテストケースで繰り返し使われるはずです。しかし実際には、開発者がコードを手直ししてモジュール化し、他の場所に持って行って使わなければなりません。テストケースの仕様上やむを得ないとはいえ、これは完全な自動化とは言えないと感じました。

img17.png

自作テスト自動化ツール

完全自動化を目指してさまざまなツールを探しましたが、最適なライブラリは見つかりませんでした。そこでElectronでテスト自動化ツールを自作することにしました(下図参照)。

img18.png

このツールの左側にはテストケースのリストがあります。ここでテストケースを作成し、Playwrightへ連携できます。録画ボタンを押して普段通り操作を録画すると、その操作を基にテストコードが生成されます。一次加工を行うと、右側に変数が生成されます。

img19.png

ユーザーが入力した値をすべて抽出して変数化し、この生成されたテストケース自体をモジュールとして扱えば、開発者の追加作業は不要です。ログインモジュールをどのテストでも再利用できます。

この機能を実装する際、AST(Abstract Syntax Tree)技術を活用しました。ASTはJavaScriptなどのコードをツリー構造に抽象化したものです。ツールではコードを操作してユーザー入力を抽出するために利用しました。

モジュール化したログインテストはどう使うのでしょうか。新しいテストケースを作成する際、既存のログインモジュールを選んでシナリオの先頭に配置するだけです。これによりログイン用の入力値を含むテスト全体を再利用できます。

このようにあらかじめテストケースをモジュール化し、画面上でドラッグ&ドロップして複数のテストモジュールを接続すれば、開発者の手間を最小限に抑えて簡単にテストコードを生成できます。

img20.png

持続可能なテストコード

前回「持続可能な環境でテストを行う方法」について触れましたが、固定入力値を使うと2回目以降の実行でテストが失敗し、持続可能とは言えません。

たとえばアドレス帳作成のテストで「FEConf 2024 アドレス帳」という固定値を使うと、最初は成功しても次回以降はキー重複で失敗します。この失敗を防ぐには、コードやDBの値を修正する必要があり、保守コストが発生します。

この問題を解決するため、Fakerを使って入力値をランダム化し、毎回異なるアドレス帳名を生成することでテスト失敗を防ぎました。

img21.png

通常、テストツールはテストの独立性を保つため外部変数の受け渡しを禁止します。しかし私は、問題が起きない範囲でデータを共有・再利用できるように実装しました。

たとえばアドレス帳作成テストで生成されたIDをブラウザに保存し、ローカルDBにも格納して次のテストで利用できるようにしました。Aテストで生成した変数をBテストへ受け渡し、両テストを連結しても正常に動作する仕組みです。

img22.png

Playwrightを改善する

モジュール化ツールでテストコードを作成しても、約1割は手作業の修正が必要でした。そこで、SeleniumやPuppeteerをカスタマイズした経験を生かし、Playwrightも改良しました。

Playwrightは優れたセレクター機能を持っていますが、これを希望する優先順に選択できるよう変更しました。また、結果レポートを簡単に共有し、チェックポイントから再開できる仕組みも実装しました。

img23.png

結果レポート

テスト後に生成されるレポートは通常ローカルPCに保存されるため、共有が面倒です。誰がどの操作で失敗したのか、どの状況で問題が起きたのかをレポートに記録し、そのリンクだけで簡単に共有できるようにしました。

セレクターエンジンのカスタマイズ

Playwrightはバージョンによって自動生成されるセレクターが異なります。かつてはplaceholderを優先するバージョンもありました。

たとえば「メールアドレス」というテキストがコード内に含まれていると、名称が変わればテストが失敗します。最近のバージョンはname属性に入力値を保存するため、この問題が解決しました。

img24.png

そこで、すべての要素にname属性があれば最優先でセレクターを生成するようPlaywrightのコードを改修しました。セレクター優先順位を制御する部分を特定し、条件に応じてname属性を使用するように変更しました。

用語集

この方法を使うには、すべての要素にname属性を付与するよう開発者に依頼する必要があります。しかし当該サービスでは、テキストは「キー:値」ペアでGoogle Driveに保存され、キーは固定で値だけ変わる仕組みです。キーが変わらないため、すべてのテストケースを再利用できます。

デザイナーやプランナーがテキストを修正する際、通常はFigma→コード修正→デプロイ→確認という非効率なフローになります。これを改善するため、スプレッドシートのキーと値を読み込んで画面に反映する仕組みを導入しました。これにより、スプレッドシート上の値を変更するだけでリアルタイムに画面を確認できます。

img25.png

テストケースのチェックポイント

テスト失敗時に最初からやり直すのは手間です。そこでPlaywrightのSession Storage APIを利用し、特定のチェックポイントから再開できる機能を実装しました。

img26.png

テストが失敗した箇所をクリックすると、失敗直前の状態をSession Storageに保存しておき、その時点から再開できます。

テストスクリーンショットの比較

スクリーンショット比較には動的要素が障害になります。たとえばKubernetesモニタリングツールの画面では、CPU使用率に応じて背景がアニメーションで変化します。

img27.png

このようなアニメーションを含むと比較が難しいため、スクリーンショット撮影前にCSSアニメーションを停止するコードを追加しました(Playwrightには標準機能があります)。

広告など動的に変わる要素も比較を妨げます。これらは非表示にするか除外して比較対象から外します。

ユーザーフローの生成

レポートには多くの情報が含まれます。保存されたスクリーンショットを活用し、ログイン画面からダッシュボードへ移動した流れや、どのボタンを押してどのページへ遷移したかをユーザーフロー図として自動生成する機能も実装しました。

img28.png

課題と今後の改良点

ツールを作ったものの、まだ課題や改良点が多く残っています。

  • VS Code拡張として提供
    独立アプリではなくVS Codeプラグインとして実装すれば、さらに使いやすかったのではという反省があります。
    img29.png

  • カスタムレポートの活用
    レポートに含まれる情報から、まだ多くの応用が可能だと考えています。

  • ネットワーク関連機能
    KubernetesのMoonなどを利用してリモート環境で大量のテストを実行する仕組みを検討中です。
    img30.png

  • フロントとAPIの関連付け
    画面で使用されたAPIとその影響範囲を可視化し、分析できる仕組みを追加したいと考えています。
    img31.png

まとめ

私のテストツールはまだ未完成で、第三者が使うには不十分な点も多いと感じます。今後は不足部分を改善し、必要な機能を追加して、より完成度の高いテスト自動化ツールを目指します。

ただし、本記事で紹介した考え方を応用すれば、専用ツールがなくてもある程度はE2Eテストを効率的かつ簡単に進められます。皆さんもぜひ参考にして、E2Eテストをより便利に実践してみてください。

  • 簡単で便利なE2Eテスト自動化を夢見て (1)
  • 簡単で便利なE2Eテスト自動化を夢見て (2)

Discussion