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
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Tasuku Watanabe
March 13, 2026
Programming
530
3
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
モックわからないマン卒業記 ~振る舞いを起点に見直した、フロントエンドテストにおけるモックの使いどころ~
Tasuku Watanabe
March 13, 2026
More Decks by Tasuku Watanabe
See All by Tasuku Watanabe
useImperativeHandleで理解する クロージャと評価タイミング
tasukuwatanabe
1
97
axiosで作る:ファイルアップロード体験を改善する「Progress Toast」
tasukuwatanabe
0
590
Other Decks in Programming
See All in Programming
Signal Forms: Details & Live Coding @enterJS 2026 in Mannheim
manfredsteyer
PRO
0
210
AI 輔助遺留系統現代化的經驗分享
jame2408
1
1.1k
AI時代のUIはどこへ行く?その2!
yusukebe
22
7.7k
symfony/aiとlaravel/boost
77web
0
110
Honoでのサプライチェーン侵害対策 〜 3つのライブラリに学ぶ
yusukebe
7
1.7k
Vite+ Unified Toolchain for the Web
naokihaba
0
410
これからAgentCoreを触る方へトレンドはGatewayです
har1101
6
450
Lessons from Spec-Driven Development
simas
PRO
0
240
Language Server 使ってる? 〜VSCode と Zed の場合〜 / Are you using a Language Server? ~For VS Code and Zed~
handlename
0
820
そのテスト、説明できますか?~LWテスト戦略FW~のご紹介
nakahara
0
190
気圧・高度・GPSを記録&可視化するアプリ「Koudo」を作った話
hjmkth
1
330
キャリア迷子上等 ─ "ない道"は自分で作ればいい
16bitidol
3
2.7k
Featured
See All Featured
Evolving SEO for Evolving Search Engines
ryanjones
0
230
Claude Code のすすめ
schroneko
67
230k
Gemini Prompt Engineering: Practical Techniques for Tangible AI Outcomes
mfonobong
2
450
Bioeconomy Workshop: Dr. Julius Ecuru, Opportunities for a Bioeconomy in West Africa
akademiya2063
PRO
1
170
How to Grow Your eCommerce with AI & Automation
katarinadahlin
PRO
1
220
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
2
340
Darren the Foodie - Storyboard
khoart
PRO
3
3.4k
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
11
960
From Legacy to Launchpad: Building Startup-Ready Communities
dugsong
0
240
Joys of Absence: A Defence of Solitary Play
codingconduct
1
410
How to audit for AI Accessibility on your Front & Back End
davetheseo
0
460
How to Ace a Technical Interview
jacobian
281
24k
Transcript
モックわからないマン卒業記 振る舞いを起点に見直した、フロントエンドテストにおけるモックの使いどころ HRBrain 渡邉佑 2026-03-13 React Tokyo #14
自己紹介 渡邉 佑 ・HRBrain ・新潟県佐渡島出身 ・新卒で航海士→エンジニア ・PlaywrightでE2Eテスト実装中 ・X: @tasuku_web 2
フロントでテストを書く デグレを発生させず安心して機能開発したい AIでたくさんリファクタリングしたい。 → Vitest + React Testing Library でテストを書いている。
import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { Counter } from "./Counter"; test("ボタンをクリックするとカウントが増える", async () => { render(<Counter />); await userEvent.click(screen.getByRole("button", { name: "増やす" })); expect(screen.getByText("1")).toBeInTheDocument(); }); 3
モックという概念が登場 テストを書こうとすると、コンポーネント内部に外部の依存が潜んでいる。 function UserGreeting() { // propsや引数ではなく、コンポーネントが内部で直接参照している外部の値(= 外部依存) const {
data } = useFetchUser(); // API通信 const now = useCurrentTime(); // 現在時刻 const { userId } = useAuth(); // 認証状態 } 4
モックを使わないと何が起きるか テスト対象のコンポーネント APIを内部で呼び出しているコンポーネント export function UserGreeting() { // API通信が内部で走る const
{ data } = useFetchUser(); if (!data) return <p>読み込み中...</p>; return <p>こんにちは、{data.name} さん</p>; } モックなし:テストが書けない ・ネットワーク環境に依存する ・テストが遅い・不安定 ・エラー系など特定ケースの再現が難しい test("ユーザー名が表示される", async () => { render(<UserGreeting />); // 実際のAPIが走る → ネットワーク環境がなければ失敗する expect(await screen.findByText("こんにちは、Alice さん") }); 5
モックで依存を差し替えてテスト可能 ・ネットワーク不要・高速 ・テストしたいケースを自由に再現できる ・外部サービスの状態に左右されない import * as hooks from "./useFetchUser";
test("ユーザー名が表示される", async () => { vi.spyOn(hooks, "useFetchUser").mockReturnValue({ data: { name: "田中" }, }); render(<UserGreeting />); expect(screen.getByText("こんにちは、田中 さん")).toBeInTheDocument(); }); 6
実際のテストファイルではこうなりがち // ① モジュールモック vi.mock("./useRouter"); vi.mock("./useAuth"); // ② HTTPモック(MSW) const
server = setupServer( http.get("/api/users", () => HttpResponse.json([{ name: "田中" }])), ); beforeAll(() => server.listen()); afterAll(() => server.close()); beforeEach(() => { vi.useFakeTimers(); // ③ タイマーモック vi.setSystemTime(new Date("2026-01-01")); vi.mocked(useRouter).mockReturnValue({ push: vi.fn() }); vi.mocked(useAuth).mockReturnValue({ userId: "u1" }); }); test("ユーザー一覧が表示される", async () => { const onSelect = vi.fn(); // ④ モック関数 render(<UserListPage onSelect={onSelect} />); expect(await screen.findByText("田中")).toBeInTheDocument(); }); 7
「APIが呼ばれたこと」を検証するのはNG ❌ よくある検証 import { fetchUsers } from "./api"; vi.mock("./api");
test("ユーザー一覧を取得する", () => { render(<UserListPage />); // APIが呼ばれたことを確認 expect(fetchUsers).toHaveBeenCalledWith("/api/users"); }); なぜNGか ・URLが /api/v2/users に変わるだけで壊れる ・画面が正しく表示されていてもテストが失敗する = リファクタリングのたびにテストも壊れる 8
だから、振る舞いをテストする
「振る舞いをテストする」という考え方 確認すべきは「何が呼ばれたか」より「画面がどう振る舞うか」 // 実装を見る(useStateの更新を直接確認) expect(setCount).toHaveBeenCalledWith(1); // 振る舞いを見る(画面がどう変わるかを確認) expect(screen.getByText("1")).toBeInTheDocument(); ・内部実装を変えても壊れにくい( setCount
→ useReducer に変えてもテストはパスする) ・ユーザーの視点でテストを書ける(ユーザーが気にするのは画面の動作であり、内部実装ではない) ・テストが仕様書になる( 「この操作をするとこう表示される」という意図が明確になる) 10
「振る舞いをテストする」という考え方 API通信: 「fetchが呼ばれたか」より「結果が表示されるか」 // 実装を見る(fetchの呼び出しを直接確認) expect(mockFetch).toHaveBeenCalledWith("/api/users"); // 振る舞いを見る(取得したデータが画面に表示されるかを確認) expect(screen.getByText("田中太郎")).toBeInTheDocument(); ・
実装依存: fetch の呼び出し先URL が変わるだけでテストが壊れる。コンポーネントの「結果」 は正しくても失敗する ・ 振る舞いベース:URLが変わっても、別のライブラリに乗り換えても、画面に結果が出ればテスト はパスする 11
「振る舞いをテストする」という考え方 ルーティング: 「router.pushが呼ばれたか」より「画面が遷移したか」 // 実装を見る(router.pushの呼び出しを直接確認) expect(mockPush).toHaveBeenCalledWith("/dashboard"); // 振る舞いを見る(遷移後のページが表示されるかを確認) expect( screen.getByRole("heading",
{ name: "ダッシュボード" }), ).toBeInTheDocument(); 12
まとめ モックで外部依存を差し替える → テストが書けるようになる API通信・認証・時刻などを固定してテスト可能に でも多用すると、リファクタリング耐性が下がる 実装詳細(関数名・モジュール構造)に依存し、テストが壊れやすくなる だから、振る舞い(画面の動作)をテストする 「何が呼ばれたか」より「画面がどう変わるか」を確認する 13
ご清聴ありがとうございました