Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
React でコンポーネントを利用したテストをゴリゴリ書く
Search
bom-shibuya
November 06, 2023
Programming
5.1k
3
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
React でコンポーネントを利用したテストをゴリゴリ書く
2023/11/06 ZOZO Tech Meetup - Webフロントエンド
bom-shibuya
November 06, 2023
Other Decks in Programming
See All in Programming
市販E-Readerを乗っ取れ 〜Embedded Swiftで電子ペーパーガジェットを制御する〜
trickart
0
130
Foundry Localでエージェント開発
seosoft
0
160
What We Talk About When We Talk About XP
m_seki
2
450
WebMCP Challenge に星空観察アプリで参加した話
okajun35
0
120
モバイル交通系ICへのチャージ実例から考える、クロスプラットフォーム開発におけるiOS実機テスト設計とCI運用
yusuga
1
210
go-spidermonkeyでAIエージェントのCode Modeを実装する
syumai
3
1.5k
自分的「カンファレンスの楽しみ方」
syumai
0
200
AIの中の人になってみる
htkym
0
170
巨大モノリシックアプリ モダン化大作戦
ktcryomm
0
330
Hono + Inertia + React で LP を構築した話
oukayuka
2
220
高専キャリア LT 発表内容
crysta1221
6
5.6k
不幸な GC
chencmd
0
890
Featured
See All Featured
What's in a price? How to price your products and services
michaelherold
247
13k
Designing Experiences People Love
moore
143
24k
Designing for humans not robots
tammielis
254
26k
DevOps and Value Stream Thinking: Enabling flow, efficiency and business value
helenjbeal
1
380
Utilizing Notion as your number one productivity tool
mfonobong
4
580
Facilitating Awesome Meetings
lara
57
7.1k
The innovator’s Mindset - Leading Through an Era of Exponential Change - McGill University 2025
jdejongh
PRO
1
320
Getting science done with accelerated Python computing platforms
jacobtomlinson
2
470
Joys of Absence: A Defence of Solitary Play
codingconduct
1
500
Mind Mapping
helmedeiros
1
350
The Invisible Side of Design
smashingmag
301
52k
A Modern Web Designer's Workflow
chriscoyier
698
190k
Transcript
React でコンポーネントを利用し たテストをゴリゴリ書く 株式会社ZOZO ZOZOTOWN開発1部 WEBフロントエンドブロック 渋谷 拓正 Copyright ©
ZOZO, Inc. 1
© ZOZO, Inc. 株式会社ZOZO ZOZOTOWN開発1部 WEBフロントエンドブロック 渋谷 拓正 Web 制作や
CRM サービスの Web アプリの開発に関 わった後、2023年4月に ZOZO に入社。 プロテインを朝晩摂取したり絵を描いたりしています。 子供と遊んで毎日過ごしています。 2
© ZOZO, Inc. https://zozo.jp/ 3 • ファッションEC • 1,500以上のショップ、8,900以上のブランドの取り扱い •
常時95万点以上の商品アイテム数と毎日平均2,900点以上の新着 商品を掲載(2023年6月末時点) • ブランド古着のファッションゾーン「ZOZOUSED」や コスメ専門モール「ZOZOCOSME」、靴の専門モール 「ZOZOSHOES」、ラグジュアリー&デザイナーズゾーン 「ZOZOVILLA」を展開 • 即日配送サービス • ギフトラッピングサービス • ツケ払い など
© ZOZO, Inc. 4 3 年前にコンポーネントではなく Hook 自体をテストしたいというモチベーションから「React Hooksで テストをゴリゴリ書きたい」という記事を書きました。
はじめに 記事URL: https://zenn.dev/bom_shibuya/articles/5c3ae7745c5e94
© ZOZO, Inc. 5 はじめに • 当時の考え ◦ hook やコンポーネントで使われる関数がそれぞれ正しく動いている
▪ コンポーネント内の実装はそれらを組み合わせている部分が大きい • ある程度正しいことが担保されているのでは? ◦ コンポーネントは JSX が書かれている ▪ DOM 構造と結びついているので壊れやすいのでは? • それから3年経って今どのようなことを考えているか ◦ => 今日のお話 🔥
© ZOZO, Inc. 6 今日話すこと • コンポーネントを利用したテストを書く • カスタムフックのテスト テストの具体的な書き方ではなく、どの様な考えでテストを書くかをお話しできればと思っています
🙌
© ZOZO, Inc. こんな経験はありませんか? 7
© ZOZO, Inc. 8 こんな経験はありませんか? • Hook のテストは書いたがコンポーネントにあるロジックはテストしていない • 修正のたびにテストも直す必要がある
◦ 毎回直さなければならないので、そもそもテストを書くのが面倒に感じる、、、 • 何度も同じようなテストコードを書いている気がする ◦ 別のテストファイルで同じようなテストを書いた気がする、、、
© ZOZO, Inc. コンポーネントを通してテストを書く 9
© ZOZO, Inc. 10 public なメソッドをテストする • 実装の詳細をテストしてしまっているのかも • private
なメソッドはテストを書かない ▪ private なメソッドは public なメソッドを通して必ず利用されているはず ▪ 参考: t-wada 「プライベートメソッドのテストは書かないもの?」 • React にとって public な関数とは? ◦ => コンポーネント ◦ ある機能を満たす形でディレクトリが切られそこから 1 つコンポーネントが export される ▪ 実際に外から使われるこのコンポーネントが public な関数 このコンポーネントをテストすることで内部で使れているコードがテストできるはず💡
© ZOZO, Inc. 11 コンポーネントを通してテストを書く 例えば以下のようなコンポーネント - Articles - index.ts
// Articlesをexport - Articles.tsx - CategorySelect.tsx - ArticleList.tsx - Article.tsx - useArticles.ts - convertDate.ts • 記事の一覧表示のコンポーネント ◦ SelectBox があり、カテゴリを選択すると記事の一覧を取得する ◦ useArticles は記事の取得などの処理が行われる ◦ convertDate は投稿日時を表示用の形式に変換する処理が記述されている
© ZOZO, Inc. 12 コンポーネントを通してテストを書く • export されているのは Articles コンポーネント
=> Articles.test.tsx のテストをかく ◦ これが public な関数 • Articles コンポーネントをテストすることで useArticles や convertDate の挙動も確認できる ◦ => useArticles.test.ts を別途書く必要はない test("初期表示時、reactの記事を取得するリクエストが送信されること", async () => { // ... }); test("投稿日時が意図した形式で表示されていること", async () => { // ... });
© ZOZO, Inc. 13 コンポーネントを通してテストを書くポイント • 小さめの機能ごとにテストを書いて下位のコンポーネントから動作を担保するイメージ ◦ 大きいコンポーネントは検証項目が多くなりテストが難しくなる ◦
小さい範囲では網羅的にテストできる ▪ 上位のコンポーネントではそこで担保すべきテストを書くといい • 下位のコンポーネントの内容を再度テストする必要はない • それぞれの責任範囲を意識する • 全ての状態を網羅するのが難しいとき ◦ もしかするとそのコンポーネントは責務を持ちすぎているかもしれない ◦ renderHook などを利用して個別にテストを書く ▪ この場合はコンポーネントを通したテストでは代表的なケースのみにするなどバランス をとる
© ZOZO, Inc. 14 Q: 同じようなテストを何回も書いている気がする A: どこで何を担保するのかを考えてテストを書くといいかも • 先述の
Atricles の例 ◦ もし convertDate が useArticles で使われている場合 ▪ 両方にテストを書くとかなり似てしまう • プロジェクトの規約的に fetch するコードは一箇所にまとめている ◦ fetch するコードのテストはそのディレクトリで書く ◦ Articles でも SelectBox を変更した時にリクエストを確認するようなテストを書く ▪ それぞれで書くテストはテストしたいことが違う ▪ => チームでテスト方針を相談できると良さそう
© ZOZO, Inc. 15 Q: コンポーネントは DOM 構造と結びついているのでテスト が壊れやすいのでは? A:
そんなことはなく、むしろ a11y への意識向上に繋がります • getByRole のような a11y 属性を利用して要素を取得する ◦ 実装(コンポーネント)の詳細を意識せずににコンポーネントを扱うことができる ▪ => DOM 構造の変更に影響を受けにくい • テストで状態を検証するために WAI-ARIA などを意識することが増える ◦ 例えば tab の切り替えを検証するために aria-selected を用いて状態を表現する ◦ ARIA属性を利用してテスタブルにする ▪ => a11y への意識が向上
© ZOZO, Inc. カスタムフックのテスト 16
© ZOZO, Inc. 17 共通で使われるカスタムフック • 各プロジェクトには共有の Hooks 置き場がある ◦
複数の箇所から使われるカスタムフック • こういう Hook もコンポーネントを通してテストする ◦ Hook は必ずコンポーネントで使われる ◦ 実際に使ってみることになるので、使い心地がわかる ▪ コンポーネントを通してテストすることで実際の使用方法の例示にもなる 次のページでサンプルコンポーネントを用意したのでみてみましょう
© ZOZO, Inc. 18 共通で使われるカスタムフック const Component = () =>
{ const { onCategoryChange, isLoading, error, articles } = useArticles({ initialCategory: CATEGORY.react }); const changeAngular = () => { onCategoryChange(CATEGORY.angular);}; return ( <div> <button type="button" data-testid="changeAngular" onClick={changeAngular} /> {isLoading && <div data-testid="loading" />} <ul> {articles.map((article) => (<li data-testid="article" key={article.id}>{article.title}</li>))} </ul> {error != null && <div data-testid="error" />} </div> ); }; • 動作確認に必要な最小限の機能のコンポーネント ◦ button なども data-testid で引っ張れる様にしている(getByRole は若干遅いらしい)
© ZOZO, Inc. 19 共通で使われるカスタムフック test("記事情報の取得中isLoadingはtrueになり、取得後はfalseになる", async () => {
const articles = generateMockArticles({ category: "react", length: 3 }); server.use( rest.get(buildEndpoint("react"), (req, res, ctx) => { return res(ctx.json(articles)); }) ); render(<Component />); expect(screen.getByTestId("loading")).toBeInTheDocument(); expect(await screen.findByTestId("loading")).not.toBeInTheDocument(); expect(screen.getAllByTestId("article").length).toBe(3); }); • getByTestId メインで利用して要素を掴んでいる • renderHook だと loading 状態のテストが難しいがコンポーネントだと書くことができる
© ZOZO, Inc. 20 Q: カスタムフックではない関数のテストもコンポーネント でテストするべき? A: 共通の関数などは普通に単体テストで良い •
コンポーネントと密接に結びついているのであればコンポーネントからテストできる ◦ そうでないなら普通にテストするでOK • 例えばどんな関数? ◦ getServerSideProps ◦ バリデーション関係 ◦ fetch のラッパー関数 ◦ などなど
© ZOZO, Inc. まとめ 21
© ZOZO, Inc. 22 まとめ • React のテストすべき public な関数はコンポーネント
◦ export されているコンポーネントを通してテストを書く ◦ 小さめの機能ごとにテストを書いて下位のコンポーネントから動作を担保 • コンポーネントを利用したテストで a11y への意識向上に繋がる • どこで何を担保するのかを考えてテストを書く • カスタムフックもコンポーネントを利用してテストを書く ◦ Hook は必ずコンポーネントで使用される ◦ 使用方法の例示になる
© ZOZO, Inc. 23 色々話してきましたが、 • どんなテストであってもテストがまったくないよりはあった方が良い ◦ 不要になれば捨てたら良い ▪
プロダクションコードには影響がない ◦ 書かないと掴めない部分もある ▪ RSC の登場で考え方が変わる可能性もある • テストは自分が書いたコードが意図通りに動いているかを確認するためのもの ◦ 将来の変更で意図しない変更がないことを担保するためのもの ◦ コードの仕様を把握しやすくするためのもの ▪ 「〇〇の時はxxになる」 最後に
© ZOZO, Inc. 楽しくテストを書いていきましょう🔥 24
None