フロントエンドのテストを網羅する〜『フロントエンド開発のためのテスト入門』を読んで〜
はじめに
暑い日が続きますね。日中外に出るイベントを避けがちななべくらです。
エンジニアとして今の会社に入るまでテストを書いたことがなく、テストに対して若干の苦手意識があったのですが、先日読んだ「フロントエンド開発のためのテスト入門 今からでも知っておきたい自動テスト戦略の必須知識」がを読んだところ少しその苦手意識が和らいだので、今日はその共有させていただきます。🙋♀️
突然ですが、フロントエンドのテストに対して苦手意識がありませんか?なんとなくテストを書けと言われたから書いているけど、モックの概念が不安だったり、プロジェクトに入っているテストだけで十分なのか疑問に感じたりすることがあるかもしれません。
この本は、そんなテストフロントエンドのテストに不慣れだったり、プロジェクトにどのテストを導入するか検討しているエンジニアに役立ちます。
目次
本の目次は以下のようになっています。
1章、2章でフロントエンドで使われるテスト全体の解説をして、続く3章〜10章で各テストの詳細について書かれています。
この本で学ぶことのできた知識をざっくり網羅
テストを書く目的と各テスト手法、戦略について
テストを書く目的は様々ですが主に、事業の信頼、健全なコードの維持、品質に対する自信、リグレッション(後戻り)を防ぐため等にが挙げられます。
フロントエンドのテスト手法は以下のようなものになります。
静的解析…コードを実行せずに行なう検証のことです。フロントエンドだとTypeScriptによる静的型付けによるエラーの検出や、ESLintによるチェックがが当てはまります。範囲としてはモジュール間連携の不整合をチェックしてくれます。
単体テスト…最も基本的なテストです。ある入力値から期待される出力値をテストします。モジュール単体の機能に着目していて、範囲としてはロジックを担う関数やUIに関わる関数を独立でテストすることできます。
結合テスト…複数モジュールが連動して働く機能に着目したテストです。パターンが複雑になりすぎる場合は単体テストを行った方が効果的なこともあります。範囲としては各関数〜WebAPIクライアントまでのいくつかのモジュールを繋げた部分となります。
E2Eテスト…UIテストに加え、外部ストレージや連携するサブシステムを含むテストをE2E(End to End)テストと呼びます。画面を跨いだ機能はもちろん、外部連携の正常な機能のチェックまで行うことができます。範囲としては関数〜DBサーバまでで、最も広い結合テストと考えられます。
ビジュアルリグレッションテスト…最終的にブラウザに表示されたスタイルに対してテストを行います。見た目を持つUIコンポーネントの開発を行うフロント特有のテストです。
本書では、有名なテスト戦略モデルとしていくつかの型が挙げられていますが、ここではテスティングトロフィー型を紹介します。これは結合テストの割合を一番大きくするというもので、単体で動くUIはほぼ無く、ユーザー操作に近いテストが多くなるため、フロントエンドのテストに合ったテスト戦略だと考えられています。
単体テストとモック
単体テストでは、ロジックやUI表示の関わる関数に対して、ある入力値から期待される出力値が返されるかどうかをテストします。フロントエンドでは主にJestというMeta社開発のテスティングフレームワーク兼テストランナーを使用します。
Jestには様々なルールがありますが、主に以下のようなものが挙げられます。
テストの定義はtest関数を使い、第一引数にテストの説明文になるテキスト、第二引数にアサーションを渡す
アサーション…検証値が期待値通りであるという検証を行う文。expect関数+マッチャーで構成される
マッチャー…期待値。Jestから提供されるtoBeやtoMatchObjectといった関数で定義できる。
describe関数を使ってテストをグルーピングすることができる
test関数はネストできないが、describe関数はネストできる
また、テストを作成するにあたりモックが必要になることがあります。モックとは、APIなどモジュールの外部から取得するべき値の代用品として使用するオブジェクトのことです。
モックには目的別にスタブとスパイと呼ばれるものがあり、スタブは『代用』を、スパイは『記録』を行うことを目的としています。例えばあるAPIの代わりとして値を設定したいだけの場合はスタブを使いますが、そのAPIが何度呼ばれたかテストしたい場合はスパイを使用します。
UIコンポーネントテスト
UIコンポーネントとはユーザーの操作する部品のことを示し、昨今のフロントエンドの開発対象の大部分を占めています。UIコンポーネントが必要なデータを表示できているか、操作が正しくまわっているかをチェックするにはUIコンポーネントのテストを行う必要があります。Jestの基本実行環境に追加して、Jestの実行環境にないDOM APIを用意するためのjsdomや、UIコンポーネントレンダリングのためのTEsting Libraryを導入するなどの用意が必要になります。記法も基本はJestのままですが、UIコンポーネントレンダリングのためにrender関数を使う必要があるなど、一部異なる部分があります。
カバレッジレポート
カバレッジレポートとは、対象コードをどれくらいテストで網羅できているかを表すレポートのことです。Jestの機能を使って簡単に確認することができます。分岐網羅率、関数網羅率など、様々な値からテストのカバー率を確認することができます。
結合テスト
結合テストとは複数モジュールが連動して働く機能に着目したテストです。本書ではReactを使って解説しています。結合テストも単体テストと同じくJestで実装しています。そこから、モジュール結合されたもののインタラクションを確認したり、モジュールを合わせた表示確認を行うことでテストを実行する。また、複数ある操作を見やすくするためにテスト内にインタラクション関数を設定することもある。
UIコンポーネントエクスプローラー
UIコンポーネントエクスプローラーとはUIコンポーネントを独立して表示、検証できるコラボレーションツールのことで、この本では、一般的にUIコンポーネントエクスプローラーとして広く知られているStorybookについて書かれています。StorybookにはUIコンポーネントテストが実装されており、Jestなどの単体結合テストとブラウザを使用したE2Eテストのちょうど間の性質を持っています。
Storybookの基本的な使い方は、Storybookをプロジェクトに導入して、各Storyを登録する流れになります。Storyとはコンポーネントが受け取ることができる異なるプロパティ、状態、またはコンテキストに基づいてコンポーネントをビジュアルに示した一つの単位のことです。
StorybookのPlay functionという機能を使うとインタラクションテストを追加できます。これは、ある操作をした場合にどのような表示になるかを設定し、テストすることができる機能です。
また、アドオンの@storybook/addon-a11yを使うことで、アクセシビリティテストをすることもできます。アクセシビリティテストはすべてのユーザーにとって利用しやすいかどうかを評価、チェックしてくれるもので、問題があるとStorybook上で指摘してくれます。
ビジュアルリグレッションテスト
ビジュアルリグレッションテストとは、CSSのスタイル定義の変更により、コードからはわからないスタイルの変化をチェックすることができるテストのことです。実際にブラウザにレンダリングして実際の画面のキャプチャをとって比較することで、差分をピクセル単位で確認することができます。E2Eテストに同胞されていることがほとんどですが、ページ上部で差分があると、その下全てが差分として表示されてしまうなど、精度がイマイチのため、この本ではUIコンポーネントごとのビジュアルリグレッションテストとしてStorybookを拡張して見ていくことが勧められています。
E2Eテスト
E2Eテストはブラウザを使うので、本物のアプリケーションに近いテストが可能です。その特性からブラウザ固有の機能を含むUIのテスト(フィーチャーテスト)とDBやサブシステムを含むE2Eテストの2つの区別をせずにE2Eテストと呼ばれます。
本書ではDocker ComposeとPlaywrightというE2Eテストフレームワークを使ってE2Eテストを行なっていきます。
まずテストごとにブラウザを開いて指定のURLに訪れることから始まります。アサーション(検証値が期待値通りであるという検証を行う文)は明示的にexpectをimportして記述していきます。Dockerコンテナ一式を起動しつつ、E2Eテストを実行し、その時のコメントやレポート等で結果を確認します。
E2Eテストは複雑な分安定して動かすことが難しく、稀に失敗するテスト(Flakyテスト)になりやすいです。そうならないように、DBを毎度リセットしたり、テストユーザーをテストごとに作成するなど、それぞれのテストが競合してしまわないように注意してテストを作成する必要があります
学んだことの具体的な適用
業務では単体テストしか書いたことがなく、フロントエンドのテストだけでもこんなに種類があるのかと驚きました。それぞれのテストについては、サラリと触れられているだけなので、実際に使うとなったらまだ再度調べる必要があると思いますが、それでも全体像として、どういったテストがあり、どういった時に有効なのかが網羅的にわかり、今後のプロジェクトへの新たなテスト導入時や、新しいプロジェクトのテストコードの理解の助けになると感じました。
フロントエンドエンジニアだったら一度読んでおいて損はないと思います。
結論
『フロントエンド開発のためのテスト入門』は、テストフロントエンドのテストに不慣れだったり、プロジェクトにどのテストを導入するか検討しているエンジニアにとって必須の良書でした。
また、読んだ本や学んだ内容について記事を書いていきたいと思います。ではまた次回🙋♀️