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
15k
フロントエンドの書くべきだったテスト、書かなくてよかったテスト
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
850
App Router への移行は「改善」となり得るのか?/ Can migration to App Router be an improvement
takefumiyoshii
8
3.1k
Webフロントエンドのための実践「テスト」手法 CodeZine Night #1
takefumiyoshii
24
8.4k
Next.js でリアーキテクトした話 / story-of-re-architect-with-nextjs
takefumiyoshii
12
8.7k
より速い WEB を目指す Next.js / nextjs-make-the-web-faster
takefumiyoshii
54
20k
フロントエンドの複雑さに耐えるため実践したこと / readyfor-nextjs-first
takefumiyoshii
25
11k
Redux の利点を振り返る
takefumiyoshii
26
8.6k
Type-only Migrate by AST
takefumiyoshii
1
630
- Regular expression & Type - Naming Rule Linter
takefumiyoshii
1
370
Other Decks in Programming
See All in Programming
アジャイルを支えるテストアーキテクチャ設計/Test Architecting for Agile
goyoki
9
3.3k
Ethereum_.pdf
nekomatu
0
460
ふかぼれ!CSSセレクターモジュール / Fukabore! CSS Selectors Module
petamoriken
0
150
Enabling DevOps and Team Topologies Through Architecture: Architecting for Fast Flow
cer
PRO
0
310
Arm移行タイムアタック
qnighy
0
300
エンジニアとして関わる要件と仕様(公開用)
murabayashi
0
280
ピラミッド、アイスクリームコーン、SMURF: 自動テストの最適バランスを求めて / Pyramid Ice-Cream-Cone and SMURF
twada
PRO
10
1.3k
Less waste, more joy, and a lot more green: How Quarkus makes Java better
hollycummins
0
100
型付き API リクエストを実現するいくつかの手法とその選択 / Typed API Request
euxn23
8
2.2k
AWS Lambdaから始まった Serverlessの「熱」とキャリアパス / It started with AWS Lambda Serverless “fever” and career path
seike460
PRO
1
250
Contemporary Test Cases
maaretp
0
130
「今のプロジェクトいろいろ大変なんですよ、app/services とかもあって……」/After Kaigi on Rails 2024 LT Night
junk0612
5
2.1k
Featured
See All Featured
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
26
2.1k
Happy Clients
brianwarren
98
6.7k
Raft: Consensus for Rubyists
vanstee
136
6.6k
Mobile First: as difficult as doing things right
swwweet
222
8.9k
Docker and Python
trallard
40
3.1k
Building an army of robots
kneath
302
43k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
229
52k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
44
6.8k
Thoughts on Productivity
jonyablonski
67
4.3k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
131
33k
BBQ
matthewcrist
85
9.3k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
8
800
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 が通るまでに数十分かかる ・ ビジュアルリグレッションが発生するケースを想定できているか? 他のテストタイプでカバーできているならば、数は減らせる
まとめ
まとめ 「こういう理由で必要」と言い切れるのは、良いテストだと思います ▪ 「書くべきだった」テスト ・ 仕様とコードの解像度をあげてくれるテスト ・ 安心してリファクタできるテスト ・ 自信を与えてくれるテスト
まとめ テストの要不要を議論したり、目的を見直す機会に ▪ 「書かなくてよかった」テスト ・ 書く事が目的になってしまったテスト ・ よくない方向に誘導してしまったテスト ・ 考慮なく作業的に追加されたテスト
ご清聴ありがとうございました