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
40
17k
フロントエンドの書くべきだったテスト、書かなくてよかったテスト
https://offers.connpass.com/event/299909/
登壇資料
Takepepe
November 16, 2023
Tweet
Share
More Decks by Takepepe
See All by Takepepe
どの様にAIエージェントと 協業すべきだったのか?
takefumiyoshii
2
910
ServerAction で Progressive Enhancement はどこまで頑張れるか? / progressive-enhancement-with-server-action
takefumiyoshii
7
1.2k
App Router への移行は「改善」となり得るのか?/ Can migration to App Router be an improvement
takefumiyoshii
8
3.7k
Webフロントエンドのための実践「テスト」手法 CodeZine Night #1
takefumiyoshii
24
9.4k
Next.js でリアーキテクトした話 / story-of-re-architect-with-nextjs
takefumiyoshii
12
9.1k
より速い WEB を目指す Next.js / nextjs-make-the-web-faster
takefumiyoshii
54
21k
フロントエンドの複雑さに耐えるため実践したこと / readyfor-nextjs-first
takefumiyoshii
25
11k
Redux の利点を振り返る
takefumiyoshii
26
9k
Type-only Migrate by AST
takefumiyoshii
1
720
Other Decks in Programming
See All in Programming
Python札幌 LT資料
t3tra
7
1.1k
Claude Codeの「Compacting Conversation」を体感50%減! CLAUDE.md + 8 Skills で挑むコンテキスト管理術
kmurahama
1
720
インターン生でもAuth0で認証基盤刷新が出来るのか
taku271
0
130
ELYZA_Findy AI Engineering Summit登壇資料_AIコーディング時代に「ちゃんと」やること_toB LLMプロダクト開発舞台裏_20251216
elyza
2
1k
実は歴史的なアップデートだと思う AWS Interconnect - multicloud
maroon1st
0
310
DevFest Android in Korea 2025 - 개발자 커뮤니티를 통해 얻는 가치
wisemuji
0
180
AIエージェントの設計で注意するべきポイント6選
har1101
6
3k
PC-6001でPSG曲を鳴らすまでを全部NetBSD上の Makefile に押し込んでみた / osc2025hiroshima
tsutsui
0
210
Findy AI+の開発、運用におけるMCP活用事例
starfish719
0
2.1k
LLMで複雑な検索条件アセットから脱却する!! 生成的検索インタフェースの設計論
po3rin
4
1.1k
Graviton と Nitro と私
maroon1st
0
160
組み合わせ爆発にのまれない - 責務分割 x テスト
halhorn
1
180
Featured
See All Featured
Ethics towards AI in product and experience design
skipperchong
1
170
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
27k
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
46
Code Review Best Practice
trishagee
74
19k
Into the Great Unknown - MozCon
thekraken
40
2.2k
More Than Pixels: Becoming A User Experience Designer
marktimemedia
2
280
SEO for Brand Visibility & Recognition
aleyda
0
4.2k
We Are The Robots
honzajavorek
0
130
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
22k
We Have a Design System, Now What?
morganepeng
54
8k
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
1
50
16th Malabo Montpellier Forum Presentation
akademiya2063
PRO
0
39
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 が通るまでに数十分かかる ・ ビジュアルリグレッションが発生するケースを想定できているか? 他のテストタイプでカバーできているならば、数は減らせる
まとめ
まとめ 「こういう理由で必要」と言い切れるのは、良いテストだと思います ▪ 「書くべきだった」テスト ・ 仕様とコードの解像度をあげてくれるテスト ・ 安心してリファクタできるテスト ・ 自信を与えてくれるテスト
まとめ テストの要不要を議論したり、目的を見直す機会に ▪ 「書かなくてよかった」テスト ・ 書く事が目的になってしまったテスト ・ よくない方向に誘導してしまったテスト ・ 考慮なく作業的に追加されたテスト
ご清聴ありがとうございました