Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
フロントエンドの書くべきだったテスト、書かなくてよかったテスト
Search
Takepepe
November 16, 2023
Programming
39
16k
フロントエンドの書くべきだったテスト、書かなくてよかったテスト
https://offers.connpass.com/event/299909/
登壇資料
Takepepe
November 16, 2023
Tweet
Share
More Decks by Takepepe
See All by Takepepe
ServerAction で Progressive Enhancement はどこまで頑張れるか? / progressive-enhancement-with-server-action
takefumiyoshii
7
990
App Router への移行は「改善」となり得るのか?/ Can migration to App Router be an improvement
takefumiyoshii
8
3.4k
Webフロントエンドのための実践「テスト」手法 CodeZine Night #1
takefumiyoshii
24
8.7k
Next.js でリアーキテクトした話 / story-of-re-architect-with-nextjs
takefumiyoshii
12
8.8k
より速い WEB を目指す Next.js / nextjs-make-the-web-faster
takefumiyoshii
54
20k
フロントエンドの複雑さに耐えるため実践したこと / readyfor-nextjs-first
takefumiyoshii
25
11k
Redux の利点を振り返る
takefumiyoshii
26
8.7k
Type-only Migrate by AST
takefumiyoshii
1
670
- Regular expression & Type - Naming Rule Linter
takefumiyoshii
1
420
Other Decks in Programming
See All in Programming
PRレビューのお供にDanger
stoticdev
1
250
責務と認知負荷を整える! 抽象レベルを意識した関心の分離
yahiru
9
1.6k
たのしいSocketのしくみ / Socket Under a Microscope
coe401_
8
1.5k
Djangoにおける複数ユーザー種別認証の設計アプローチ@DjangoCongress JP 2025
delhi09
PRO
4
520
AIレビュー導入によるCIツールとの共存と最適化
kamo26sima
1
1.2k
1年目の私に伝えたい!テストコードを怖がらなくなるためのヒント/Tips for not being afraid of test code
push_gawa
1
670
DevNexus - Create AI Infused Java Apps with LangChain4j
kdubois
0
150
Modern Angular with Signals and Signal StoreNew Rules for Your Architecture @bastacon 2025 in Frankfurt
manfredsteyer
PRO
0
150
読まないコードリーディング術
hisaju
1
140
もう少しテストを書きたいんじゃ〜 #phpstudy
o0h
PRO
21
4.4k
高セキュリティ・高耐障害性・サブシステム化。そして2億円
tasukulab280
2
380
Boost Your Web Performance with Hyperdrive
chimame
1
150
Featured
See All Featured
Designing Experiences People Love
moore
140
23k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
30
2.3k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
7
660
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
Raft: Consensus for Rubyists
vanstee
137
6.8k
The Cult of Friendly URLs
andyhume
78
6.2k
Product Roadmaps are Hard
iamctodd
PRO
51
11k
Why You Should Never Use an ORM
jnunemaker
PRO
55
9.2k
A better future with KSS
kneath
238
17k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
129
19k
The World Runs on Bad Software
bkeepers
PRO
67
11k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
6
590
Transcript
Takepepe #Offers_フロントエンドテスト フロントエンドの 書くべきだったテスト 書かなくてよかったテスト
自己紹介 ▪ Takepepe(吉井 健文) ▪ フロントエンドエンジニア ▪ 社内横断開発組織に所属 ▪ フロントエンド開発の横断サポート
フロントエンド開発のためのテスト入門 ▪ 2023.4/24 翔泳社より刊行 ▪ フロントエンド開発におけるテスト手法を紹介 ▪ 単体テストからE2Eテストまでを体系的に ▪ 自動テストがはじめてという方にも
Agenda ▪ 【1】フロントエンドテストの目的 ▪ 【2】書くべきだったテスト ▪ 【3】書かなくてよかったテスト 実体験をまじえ、フロントエンドテストの考察をしていきます
【1】フロントエンドテストの目的
【1】フロントエンドテストの目的 フロントエンドのテスト、書いていますか? よく相談される疑問点 ▪ どの程度書けば良いか? ▪ どのように書けば良いか? ▪ どういった観点で書けばよいか?
【1】フロントエンドテストの目的 フロントエンドのテスト、書いていますか? ▪ 自信をもって書けている方 ▪ 自信はないが書けている方 ▪ これから着手しようとしている方
【1】フロントエンドテストの目的 フロントエンドのテスト、書いていますか? そもそも、なぜ「フロントエンド」のテストが必要か議論ができていますか? ▪ 自信をもって書けている方 ▪ 自信はないが書けている方 ▪ これから着手しようとしている方
【1】フロントエンドテストの目的 テストを書き始めたころ ▪ テストの書き方がわかった! ▪ テストの概要が理解できた! ▪ テストを書くのは楽しい!!
【1】フロントエンドテストの目的 テストが充実してきたころ ▪ 書きすぎているのでは? ▪ 効果があまりないのでは? ▪ 私たちにとって適切??
【1】フロントエンドテストの目的 テストが充実してきたころ 「作るもの」と同様「自動テスト」にも、それぞれ解が異なる ▪ 書きすぎているのでは? ▪ 効果があまりないのでは? ▪ 私たちにとって適切??
【1】フロントエンドテストの目的 テストに期待すること ▪ バグを未然に防ぎたい ▪ インシデントを未然に防ぎたい ▪ 品質を向上したい
【1】フロントエンドテストの目的 テストに期待すること ▪ バグを未然に防ぎたい(どんなバグが起こりそうですか?) ▪ インシデントを未然に防ぎたい(どんなインシデントですか?) ▪ 品質を向上したい(品質の高いコードはどのようなものですか?)
【1】フロントエンドテストの目的 テストに求められる「解像度」 ▪ このようにバグを防げる ▪ このようなインシデントを防ぎたい ▪ このような品質のコードを書きたい
【1】フロントエンドテストの目的 テストに求められる「解像度」 ▪ このようにバグを防げる ▪ このようなインシデントを防ぎたい ▪ このような品質のコードを書きたい 根拠のある自動テストは、自信と安心につながる
【1】フロントエンドテストの目的 テストに求められる「解像度」 ▪ このようにバグを防げる ▪ このようなインシデントを防ぎたい ▪ このような品質のコードを書きたい 具体例をあげ、目的の「解像度」を上げていきましょう
【2】書くべきだったテスト
【2】書くべきだったテスト Router に関連するテスト観点 1 ▪ SPA フレームワーク や Web App フレームワーク(ex:
Next.js) ▪ Routing に関する処理はフロントエンドの範囲 ▪ <Link /> コンポーネントの遷移先 ▪ Router に関する処理
【2】書くべきだったテスト Router に関連するテスト観点 1 ▪ SPA フレームワーク や Web App フレームワーク(ex:
Next.js) ▪ Routing に関する処理はフロントエンドの範囲 ▪ <Link /> コンポーネントの遷移先 ▪ Router に関する処理 テストを厚めに書きたいポイント
【2】書くべきだったテスト Router に関連するテスト観点 1 ▪ searchParams の参照 ・ query.foo の型推論は string |
string[] | undefined である ・ 通常 UI 操作では ?foo=bar(string)にしかならない前提
【2】書くべきだったテスト Router に関連するテスト観点 1 ▪ searchParams の参照 ・ query.foo の型推論は string |
string[] | undefined である ・ 通常 UI 操作では ?foo=bar(string)にしかならない前提 ・ URL バーには ?foo=bar&foo=baz が入力できてしまう ・query.foo の期待値は “bar”(string) ・query.foo は実際は [“bar”, “baz”] (string[])をとりうる
【2】書くべきだったテスト Router に関連するテスト観点 1 as string で握りつぶしていませんか? ▪ searchParams の参照 ・ query.foo
の型推論は string | string[] | undefined である ・ 通常 UI 操作では ?foo=bar(string)にしかならない前提 ・ URL バーには ?foo=bar&foo=baz が入力できてしまう ・query.foo の期待値は “bar”(string) ・query.foo は実際は [“bar”, “baz”] (string[])をとりうる
【2】書くべきだったテスト Router に関連するテスト観点 1 テストを書いていると、稀なケースに注意が向く ▪ string[] のリクエストを、どのように処理すべき? ❌ as string で握りつぶしているのでランタイムエラーに
…
【2】書くべきだったテスト Router に関連するテスト観点 1 どれを選んでも正解。どうあって欲しいかをテストコードで表明 ▪ string[] のリクエストを、どのように処理すべき? ❌ as string で握りつぶしているのでランタイムエラーに
… (案A) 配列先頭の値を参照すること (案B) 不正なリクエストとしてエラー画面を表示すること (案C) 不正なリクエストなので何も処理を行わないこと
【2】書くべきだったテスト Router に関連するテスト観点 1 A, B ,C どれが正しいか?要件定義に明記されていない -> 確認
-> テストを書く ▪ string[] のリクエストを、どのように処理すべき? ❌ as string で握りつぶしているのでランタイムエラーに … (案A) 配列先頭の値を参照すること ✅ (案B) 不正なリクエストとしてエラー画面を表示すること (案C) 不正なリクエストなので何も処理を行わないこと
【2】書くべきだったテスト Router に関連するテスト観点 1 要件定義と実装の精度があがる ▪ string[] のリクエストを、どのように処理すべき? ❌ as string で握りつぶしているのでランタイムエラーに
… (案A) 配列先頭の値を参照すること ✅ (案B) 不正なリクエストとしてエラー画面を表示すること (案C) 不正なリクエストなので何も処理を行わないこと
【2】書くべきだったテスト Router に関連するテスト観点 2 searchParams をどう扱うかは、フロントエンドの責務 ▪ /?foo=barという Route の画面における仕様 ✅「操作
A」があった場合 ?foo=bar は維持して /?foo=bar&baz=A に遷移 ✅「操作 B」があった場合 ?foo=bar は除外して /?baz=B に遷移
【2】書くべきだったテスト Router に関連するテスト観点 2 「操作C」を追加した際に「操作 A」にリグレッションが発生 ▪ /?foo=barという Route の画面における仕様 ❌「操作
A」があった場合 ?foo=bar は除外して /?baz=A に遷移 ✅「操作 B」があった場合 ?foo=bar は除外して /?baz=B に遷移 ✅「操作 C」があった場合 ?foo=bar は除外して /?baz=C に遷移
【2】書くべきだったテスト Router に関連するテスト観点 2 「操作A」の自動テストで、リグレッションに気づけた ▪ /?foo=barという Route の画面における仕様 ❌「操作 A」があった場合
?foo=bar は除外して /?baz=A に遷移 ✅「操作 B」があった場合 ?foo=bar は除外して /?baz=B に遷移 ✅「操作 C」があった場合 ?foo=bar は除外して /?baz=C に遷移
【2】書くべきだったテスト 要件が複雑な機能のテスト観点 ▪ 要件項目が多数あり複雑な機能 ✅「関数 A」が期待通りに動く
【2】書くべきだったテスト 要件が複雑な機能のテスト観点 ▪ 要件項目が多数あり複雑な機能 ✅「関数 A」が期待通りに動く ✅「関数 B」は「関数 A」を使用、期待通りに動く ✅「関数 C」は「関数
A」を使用、期待通りに動く
【2】書くべきだったテスト 要件が複雑な機能のテスト観点 ▪ 要件項目が多数あり複雑な機能 ✅「関数 A」が期待通りに動く ✅「関数 B」は「関数 A」を使用、期待通りに動く ✅「関数 C」は「関数
A」を使用、期待通りに動く ✅「コンポーネント D」は「関数 B」を使用、期待通りに動く 実装が完了し、リリースを待つ
【2】書くべきだったテスト 要件が複雑な機能のテスト観点 ▪ 要件項目が多数あり複雑な機能 ✅「関数 A」の修正が必要 ✅「関数 B」は「関数 A」を使用、修正が必要 ✅「関数 C」は「関数
A」を使用、期待通りに動く ✅「コンポーネント D」は「関数 B」を使用、修正が必要 コンポーネント D の仕様変更が発生。関数 B のために、関数 A に修正を加える
【2】書くべきだったテスト 要件が複雑な機能のテスト観点 ▪ 要件項目が多数あり複雑な機能 ✅「関数 A」が期待通りに動く ✅「関数 B」は「関数 A」を使用、期待通りに動く ❌「関数 C」は「関数
A」を使用、期待通りに動かない ✅「コンポーネント D」は「関数 B」を使用、期待通りに動く コンポーネント D の仕様変更には対応できたが、関数 C がリグレッション
【2】書くべきだったテスト 要件が複雑な機能のテスト観点 ▪ 要件項目が多数あり複雑な機能 ✅「関数 A」が期待通りに動く ✅「関数 B」は「関数 A」を使用、期待通りに動く ✅「関数 C」は「関数
A」を使用、期待通りに動く ✅「コンポーネント D」は「関数 B」を使用、期待通りに動く テストを書きながら開発すると「速度があがる」理由
【2】書くべきだったテスト 要件が複雑な機能のテスト観点 ▪ 要件項目が多数あり複雑な機能 ✅「関数 A」が期待通りに動く ✅「関数 B」は「関数 A」を使用、期待通りに動く ✅「関数 C」は「関数
A」を使用、期待通りに動く ✅「コンポーネント D」は「関数 B」を使用、期待通りに動く 後任開発者は、安心して機能追加や変更ができる
【2】書くべきだったテスト コンポーネントの肥大化が防止できた ▪ 「コンポーネントテストが書きづらくて …」という相談 どこに何が書かれているか一目で理解できない 機能追加までのリードタイムが長い
【2】書くべきだったテスト コンポーネントの肥大化が防止できた ▪ 「コンポーネントテストが書きづらくて …」という相談 コンポーネントを分割 ロジックを抽出 ✅ ロジックに対して単体テストを書く ✅ コンポーネントのテストは薄めに リリース前にモジュール分割。適所に自動テストを追加
【2】書くべきだったテスト コンポーネントの肥大化が防止できた 「テストが書きづらい」という気づきが、よい設計のきっかけに ▪ 「コンポーネントテストが書きづらくて …」という相談 コンポーネントを分割 ロジックを抽出 ✅ ロジックに対して単体テストを書く ✅ コンポーネントのテストは薄めに
【2】書くべきだったテスト セマンティクスの不備に気づけた ▪ 「getByRole で要素を特定できなくて…」という相談 ・ label 要素を使用すべき箇所を見落とした ・ `heading` role で取得できない、p 要素の見出し
・ `link` role で取得できない、a 要素
【2】書くべきだったテスト セマンティクスの不備に気づけた 普段からテストを書く事で気づける ▪ 「getByRole で要素を特定できなくて…」という相談 ・ label 要素を使用すべき箇所を見落とした ・ `heading` role で取得できない、p
要素の見出し ・ `link` role で取得できない、a 要素
【2】書くべきだったテスト キーボード操作の不備に気づけた ▪ 「キーボードで操作できなくて…」という相談 ・ フォーカスの当たらない、div 要素で作られたボタン ・ スペースキーを押下しても開かない、ドロップダウンメニュー
【2】書くべきだったテスト キーボード操作の不備に気づけた 要件定義になかったので、実装観点になかった ▪ 「キーボードで操作できなくて…」という相談 ・ フォーカスの当たらない、div 要素で作られたボタン ・ スペースキーを押下しても開かない、ドロップダウンメニュー
【2】書くべきだったテスト 共通 UI コンポーネントのテスト観点 ▪ デザインシステム整備前の手動テスト (目視による) ✅「画面 A」がデザイン通りに実装されている ✅「画面 B」がデザイン通りに実装されている
✅「画面 C」がデザイン通りに実装されている デザインシステムの適用で、画面が崩れないか?
【2】書くべきだったテスト 共通 UI コンポーネントのテスト観点 ▪ デザインシステム整備が完了、各画面で使用するように ✅「画面 A」がデザイン通りに実装されている? ✅「画面 B」がデザイン通りに実装されている? ✅「画面
C」がデザイン通りに実装されている? 見た目に関するリグレッションは VRT を活用
【2】書くべきだったテスト 共通 UI コンポーネントのテスト観点 ▪ デザインシステム整備が完了、各画面で使用するように ✅「画面 A」がデザイン通りに実装されている ✅「画面 B」がデザイン通りに実装されている ✅「画面
C」がデザイン通りに実装されている リファクタリングが積極的に行えた
第3章 書かなくてよかったテスト
【3】書かなくてよかったテスト 不適切なテストサイズ ▪ 「ブラウザの自動テストが Flaky で…」という相談 ・ ブラウザの自動テストは Flaky になりがち ・ 他のテスト手法で担保できるテスト観点 ・ 各テスト手法の、得手不得手を把握しておく必要がある
【3】書かなくてよかったテスト 不適切なテストサイズ ▪ 「ブラウザの自動テストが Flaky で…」という相談 ・ ブラウザの自動テストは Flaky になりがち ・ 他のテスト手法で担保できるテスト観点 ・ 各テスト手法の、得手不得手を把握しておく必要がある
安定性 X 忠実性 = 信頼できるテスト
【3】書かなくてよかったテスト 書かれることが目的になってしまったテスト ▪ テストをたくさん書いたけれど… ・ テスト観点がない ・ モックばかりで意義を感じられない ・ 他のテストコードと同程度の量を何となく書いた
【3】書かなくてよかったテスト 書かれることが目的になってしまったテスト ▪ テストをたくさん書いたけれど… ・ テスト観点がない ・ モックばかりで意義を感じられない ・ 他のテストコードと同程度の量を何となく書いた 目的がないのであれば「書かなくてもよい」
【3】書かなくてよかったテスト 無理に aria 属性を付け足したテスト ▪ 「getByRole で取得できなかったのでつい…」 ・ テストのための符号として aria 属性を付与している ・ role="foo-button"と書かれているボタン(体験談)
【3】書かなくてよかったテスト 無理に aria 属性を付け足したテスト ▪ 「getByRole で取得できなかったのでつい…」 ・ テストのための符号として aria 属性を付与している ・ role="foo-button"と書かれているボタン(体験談)
No ARIA is better than Bad ARIA
【3】書かなくてよかったテスト 無理に aria 属性を付け足したテスト ▪ 「getByRole で取得できなかったのでつい…」 ・ テストのための符号として aria 属性を付与している ・ role="foo-button"と書かれているボタン(体験談)
正しくない aria 属性を付与するよりも、付与されない方がまだマシ
【3】書かなくてよかったテスト 過剰な VRT ▪ 「CI が遅くて…」という相談 ・ 全コンポーネントの Storybook を対象に VRT を実施
・ CI が通るまでに数十分かかる ・ ビジュアルリグレッションが発生するケースを想定できているか?
【3】書かなくてよかったテスト 過剰な VRT ▪ 「CI が遅くて…」という相談 ・ 全コンポーネントの Storybook を対象に VRT を実施
・ CI が通るまでに数十分かかる ・ ビジュアルリグレッションが発生するケースを想定できているか? 他のテストタイプでカバーできているならば、数は減らせる
まとめ
まとめ 「こういう理由で必要」と言い切れるのは、良いテストだと思います ▪ 「書くべきだった」テスト ・ 仕様とコードの解像度をあげてくれるテスト ・ 安心してリファクタできるテスト ・ 自信を与えてくれるテスト
まとめ テストの要不要を議論したり、目的を見直す機会に ▪ 「書かなくてよかった」テスト ・ 書く事が目的になってしまったテスト ・ よくない方向に誘導してしまったテスト ・ 考慮なく作業的に追加されたテスト
ご清聴ありがとうございました