2022.01.20
STAFF BLOG
スタッフブログ
TECHNICAL
テクログ
前提
以下の状況/課題を踏まえた上で、フロントエンドのテスト戦略について考察していく。
- 新規プロジェクトである
- 中~大規模プロジェクトである
- 実装規模に見合わない納期である
- 様々な条件から優先度を決定し、テストを実施するスコープを決める必要がある
- テストコードの保守/運用コストを意識し、保守/運用方法についても決定する必要がある
- プロジェクトにアサインするメンバーがテストに慣れていない(テスト経験が豊富な開発者が存在しない)
- テストの学習コストを測る必要がある
- 開発チームの人数が10人以下
- 外部API連携を行う必要がある
- 決済系
- フロントエンドに採用する技術
- Next.js
- ISR/SSR/CSR/GraphQL(Apollo Client)/REST API(SWR)/NextAuth
- React
- Functional Component/React Hook Form
- TypeScript
- CSSModule
- Next.js
注:このプロジェクトはフィクションです。
なぜテストを行うのか
- バグを防ぐ
- バグが起きるとサイト自体あるいはサイトの重要な機能が停止し、サイトのユーザーおよびサイトの運営会社に損失を与えることになる
- リグレッションを防ぐ
- これもバグと同じで、サイト自体あるいはサイトの重要な機能が停止し、サイトのユーザーおよびサイトの運営会社に損失を与える可能性がある
つまりサイトのユーザーおよびサイトの運営会社に損失を与える
前に、それを起こす要因を潰しておくことが重要なミッションである。
そのためにテストを行い、その要因を検知する必要があると考える。
テストを行うことによるメリット/デメリット
テストを行う必要性が分かったところで、次にプロジェクトにテストを入れるメリットとデメリットについて整理をしてみる。
メリット
- 事前に重大なバグを検知できる確率が上がる
- リグレッションテストが同じ精度で行える
- テストをパスしているコードについては、その結果についての信頼性を証明できる
デメリット
- (テストの書き方を理解していない場合)テストを書くための学習コストがかかる
- テストを書く分の工数が増えるので、プロジェクトの進捗に影響する
- テストコードのメンテナンスを継続的に行っていく必要がある
何にでもメリットとデメリットは存在する。
これらを考慮した上で、何をテストするのか、どうやってテストをするのか、どこまでテストをするのかを選択していく。
何をテストするのか
ReactのメジャーなテスティングライブラリであるReact Testing Library
の思想からヒントを得てみる。
まずはテストを避けるべき対象について以下のように述べている。
テスティングライブラリでは、テストするコンポーネントの内部など、実装の詳細をテストしないことを推奨しています(それでも可能ではありますが)。このライブラリの指針は、ウェブページがユーザーによってどのように操作されるかに酷似したテストに重点を置くことを強調しています。
ユーザーが実際に何を操作してどのような結果になるかを重要視している。
つまり、実際のwebサービスの使われ方にできる限り近づけたテストを書くことが必要である。
また、基本の思想として以下のように述べている。
テストがソフトウェアの使用方法に似ていればいるほど、より高い信頼性を得ることができます。
なので、テストをする対象としては以下で良さそうである。
- ユーザーの操作
- ユーザー操作による状態変化の結果
どうやってテストをするのか
何をテストするのかは決まったので、次にどうやってテストをするかを考えていく。
その前に、フロントエンドのテストにはどのような種類があるのかを整理していく。
フロントエンドテストの種類
React Testing Libraryの開発者であるKent C. Dodds神が提唱しているThe Testing Trophy
を参考にする。
The Testing Trophyに倣うと、フロントエンドのテストは4種類に分類できる。
- End to End
- いわゆるE2Eテスト。ユーザーのように振る舞い、アプリをクリックし、正しく機能するかどうかを検証するテスト
- Intergration
- 複数のユニットが調和して動作することを確認するテスト
- Unit
- 分離された個々の部品が期待通りに動作することを確認するテスト
- Static
- コードを書きながら、誤字・脱字をキャッチするテスト
- ユーザーの操作
- ユーザー操作による状態変化の結果
このテスト方針に沿うと、優先度はEnd to End > Intergration > Unit > Static
で良さそうである。
各テストを何を使ってテストするかについては、以下のような感じにすれば良さそうである。
- End to End > Cypress
- Intergration > React Testing Library
- Unit > React Testing Library
- Static > ESLint,TypeScript
どうやってテストをするかについては、大枠のイメージがついた。
次にどこまでテストをするのかを考えていく。
どこまでテストをするのか
ここで言うどこまで
は各4つのテスト手法でテスト対象とする範囲である。
ここで前提をもう一度思い出す。
- 実装規模に見合わない納期である
- 様々な条件から優先度を決定し、テストを実施するスコープを決める必要がある
- テストコードの保守/運用コストを意識し、保守/運用方法についても決定する必要がある
- プロジェクトにアサインするメンバーがテストに慣れていない(テスト経験が豊富な開発者が存在しない)
- テストの学習コストを測る必要がある
頭が痛くなるが、上記を踏まえた上で、まず簡単に決められるものから決めていく。
- Static
- ESLint,TypeScriptを使用して
コーディング
に対してテストを行いたい。- 範囲はコミットされるts/tsxファイルすべてで問題なさそうである。
husky+lint-staged
を使用すれば、初回の設定以外はコストがほぼかからなくなる。
- 範囲はコミットされるts/tsxファイルすべてで問題なさそうである。
- ESLint,TypeScriptを使用して
- End to End
- 4つの手法の中で最もテスト方針に近いものである。最重要であるがゆえに最も多くのテストを書くことになると思われる
- 範囲は全てのユーザー操作で問題ない。と言いたいところだが実装時間は無慈悲にも有限である。ここはプロジェクトによって変わってくるが、
その操作に失敗したら即座にサイトの機能が落ちる
またはその機能が落ちるとあらゆるページで連鎖的にバグがでる
この2つを念頭において対象となる操作を絞り込むのが現実的なラインだろうか。
- 範囲は全てのユーザー操作で問題ない。と言いたいところだが実装時間は無慈悲にも有限である。ここはプロジェクトによって変わってくるが、
- 4つの手法の中で最もテスト方針に近いものである。最重要であるがゆえに最も多くのテストを書くことになると思われる
- Unit
- 機能(ロジック)単体をテストしたい。
- 優先度では下から2つ目なので、多くのテストは必要ない。コンポーネントからロジックのみをカスタムHooksとして切り出し、その中でも
その操作に失敗したら即座にサイトの機能が落ちる
またはその機能が落ちるとあらゆるページで連鎖的にバグがでる
を念頭に置いて対象とするロジックを選択することが望ましい。
- 優先度では下から2つ目なので、多くのテストは必要ない。コンポーネントからロジックのみをカスタムHooksとして切り出し、その中でも
- 機能(ロジック)単体をテストしたい。
- Intergration
- 個人的に最も悩みそうなテストである。
- こちらも、
その操作に失敗したら即座にサイトの機能が落ちる
またはその機能が落ちるとあらゆるページで連鎖的にバグがでる
を念頭に置いて対象とする結合ロジックを選択することが望ましい。
- こちらも、
- 個人的に最も悩みそうなテストである。
結論
- テスト優先度は
End to End > Intergration > Unit > Static
- テストコードが多すぎるとメンテナンスコストが肥大していくので、プロジェクトの初期段階では
落ちたらビビる
もの考え抜いてから、スモールスタートでやっていくのが良い。 - テストは大事。だがプロジェクトを納期までにリリースすることはもっと大事。
納期伸びて
おわりに
完璧を目指すよりまず終わらせろ
“Done is better than perfect”
-マーク・ザッカーバーグ
参考文献
- Testing JavaScript with Kent C. Dodds
- How to know what to test
- Common mistakes with React Testing Library
- How to test custom React hooks
- Static vs Unit vs Integration vs E2E Testing for Frontend Apps
- Should I write a test or fix a bug?
- UI Testing Myths
- Why you’ve been bad about testing
- Why your team needs TestingJavaScript.com