以下の2つのWebフロントエンドにおけるテストについての記事を読んだ。
- https://kentcdodds.com/blog/static-vs-unit-vs-integration-vs-e2e-tests
- https://kentcdodds.com/blog/write-tests
以下はメモと関連して考えたことなので、実際の内容についてはリンク先を読んだほうがいいと思う。
統合テストを重視すべき
ここで言う「統合テスト」はいくつかのユニットを一緒に動かしてテストすることを指していて、APIリクエストなどを除いてほとんどモックを使わないことを想定している。一方で、E2Eテストのようにバックエンドまで含めたテストは指していない。
伝統的なテストピラミッドではユニットテストが重視されてきたが、Webフロントエンドの文脈ではユニットテストは現実的なシナリオをテストできるわけではなく信頼性や有用性が低い。もちろん、ユニットテストを書くことで開発者が自信をもって開発を進められるという点においてその価値が損なわれることはないため、まったく書かないということはありえない。テストにかけるコストとメリットを見比べた場合、バックエンドほどの有用性がないということだろう。
例えば、あるコンポーネントを単独でテストするには、関連するコンポーネントをモックとして扱う必要があるが、そのようにして書かれたユニットテストは現実的なシナリオを再現しにくいため、意味のあるテストとはいいにくい。
そこで、関連する複数のコンポーネントをまとめて統合テストによって検証することが重要になってくる。統合テストであればモックは最小限に抑えられるため、現実的なシナリオに沿った信頼できるテストを書くことができるだろう。
壊れにくいテストのために
Webフロントエンドのテストは壊れやすい、というのがよく耳にする考え方だったと思う。いくら信頼性が高くても変更のたびに壊れてしまうようでは、コストとメリットが見合わなくなってくる。
そこで、壊れにくいテストを書くために必要なことを整理してみた。Webフロントエンドに限った話じゃないものもある。
1. ユーザー視点でテストを書く
DOMやクラス名などに依存するのではなく、ユーザーが目にするテキストやアクセシビリティ属性を利用することで、DOM構造やクラスの変更によってテストが壊れることを防ぐ。
2. 実装の詳細に依存しない
コンポーネント内部の状態を直接テストしたり、実装内部の呼び出しの有無をテストするのを避ける。そうすることでリファクタリングによってテストが壊れることを防ぐ。
3. 実際のユーザーのシナリオにフォーカスする
細かいデザインや表示をテストするよりも、主要なケースに絞ってテストすることでよりコストパフォーマンスの高いテストを維持できる。
4. 柔軟なアサーションを使う
完全な文字列一致ではなく正規表現や部分一致を使うことでテキストの変更によってテストが壊れるのを防ぐ。
5. 適切にモックを使う
バックエンドや外部サービスなど不安定な部分については適切にモックを利用することで、テストの安定性を高めることができる。
6. テストケースを疎結合に保つ
setUp
などで共通の処理を書くとテストケース間が暗黙的に密結合になりテストの変更により他のテストが壊れることがある。共通したセットアップ処理などは関数として抽出して都度テストケース内で呼び出すようにすることで、疎結合に保つことができる。