新闻详情

新闻详情

首页 / 资讯中心 / 详情

React 测试进阶实战:用 Mock 测试回调处理器与子组件

发布时间:2026/9/15 11:48:45来源:尧图网络
React 测试进阶实战:用 Mock 测试回调处理器与子组件
React 测试进阶实战用 Mock 测试回调处理器与子组件【免费下载链接】curriculumThe open curriculum for learning web development项目地址: https://gitcode.com/GitHub_Trending/cu/curriculum导读React 组件测试的入门课程解决了如何用 Testing Library 渲染组件、查询元素、模拟用户交互的问题而本篇进阶指南聚焦于测试中最核心的隔离手段——Mock模拟当组件依赖外部传入的回调函数、或组件树深处挂载着我们并不关心的子组件时如何用 Jest 的jest.fn()与jest.mock()将依赖替换为可控的替身从而只验证被测组件自身的行为。文章将用FavoriteInput输入组件演示回调 Mock 的完整写法再以 The Odin Project 官网真实存在的SubmissionsList组件及其测试为例剖析真实项目中如何划分测试套件、Mock 子组件并遵循 Arrange-Act-Assert 模式组织用例。读完后你将能独立为依赖外部回调、含子组件树的 React 组件写出高质量、可维护的单元测试。本文基于本仓库课程文档 react_testing_part_two.mdReact Testing 系列第二部分展开并对照仓库内同系列课程React Testing 第一部分、新版 Mocking 课程与 Jest 测试基础、Mocking 概念课 进行纵深讲解。回顾React 测试工具链的四个包在进入 Mock 之前先快速回顾第一部分课程 react_testing_part_one.md 中确立的测试环境——Mock 测试依然建立在同一套工具之上import React from react; import { ... } from testing-library/react; import testing-library/jest-dom; // 可选 import userEvent from testing-library/user-event; import TestComponent from path-to-test-component;testing-library/react提供render等核心 API把组件渲染进内存中的 DOMtesting-library/jest-dom提供toBeInTheDocument等自定义匹配器非必需Jest 自带大量匹配器testing-library/user-event提供userEventAPI模拟真实的用户交互其异步用法见后文实践中应优先于fireEventjest无需显式导入它会自动发现*.test.js/*.test.jsx测试文件。新版课程 introduction_to_react_testing.md 补充了一个关键背景render并非真的打开浏览器而是由jsdom在内存中模拟 DOM含事件系统这让我们无需真实浏览器即可解析组件内容、运行测试。值得一提的是仓库中并存着两代课程旧版archive/javascript/react_js/以Jest为测试框架新版react/react_testing/mocking_callbacks_and_components.md则切换到Vitestvi.fn()/vi.mock()对应 Jest 的jest.fn()/jest.mock()。本文按关联文档以 Jest 为主但在关键处会给出 Vitest 对照两者概念完全互通。什么是 Mock隔离被测单元的替身函数Mock模拟概念在本课程前序的 more_testing.md 中已有铺垫当代码存在紧耦合问题、依赖难以解耦时与其费力搭出完整环境不如写一个总是表现得完全符合预期的假函数——这就是 Mock。例如测试一个从 DOM 输入框取值的函数时不必真的搭建网页并插入内容只需用 Mock 函数固定返回某个值即可。在 React 测试中Mock 的意义在于我们只关心被测组件是否调用了依赖以及以什么参数调用而不关心依赖内部做了什么。这正是组件级单元测试的隔离原则——jest.fn()创建的空函数替身会记录每次调用的次数与参数供断言使用。你甚至已在之前的实战中接触过它在 Battleship 项目 中游戏逻辑的单元测试需要把 UI/DOM 操作排除在外——这正是依赖隔离与 Mock 思维的一次预演。现在让我们把 Mock 正式引入 React 组件测试。测试回调处理器以 FavoriteInput 为例回调Callback无处不在每一次用户交互都可能触发回调有时回调作为 props 传入组件用于更新父组件状态。以课程中的FavoriteInput组件为例源码示例// FavoriteInput.js import React from react; const FavoriteInput ({ onChange: onInputChange, id }) { const inputHandler (event) onInputChange(event.target.value); return ( label htmlFor{id} What is your favorite wild animal? input id{id} onChange{inputHandler} / /label ); }; export default FavoriteInput;这个组件本身平平无奇接收onChange与id两个 props在输入框内容变化时把event.target.value交给onChange。测试的难点在于我们对onChange函数一无所知——不知道它做什么、会影响应用的哪部分。唯一能确定的事实是当用户在输入框中输入时它必须被调用。这就是 Mock 的用武之地。完整测试代码课程给出了完整的测试文件FavoriteInput.test.js// FavoriteInput.test.js import React from react; import { render, screen } from testing-library/react; import testing-library/jest-dom; import userEvent from testing-library/user-event; import FavoriteInput from ./FavoriteInput; describe(Favorite Input, () { it(calls onChange correct number of times, async () { const onChangeMock jest.fn(); const user userEvent.setup(); render(FavoriteInput onChange{onChangeMock} /); const input screen.getByRole(textbox); await user.type(input, Lion); expect(onChangeMock).toHaveBeenCalledTimes(4); }); it(calls onChange with correct argument(s) on each input, async () { const onChangeMock jest.fn(); const user userEvent.setup(); render(FavoriteInput onChange{onChangeMock} /); const input screen.getByRole(textbox); await user.type(input, Ox); expect(onChangeMock).toHaveBeenNthCalledWith(1, O); expect(onChangeMock).toHaveBeenNthCalledWith(2, Ox); }); it(input has correct values, async () { const onChangeMock jest.fn(); const user userEvent.setup(); render(FavoriteInput onChange{onChangeMock} /); const input screen.getByRole(textbox); await user.type(input, Whale); expect(input).toHaveValue(Whale); }); });三个用例各司其职下面逐条拆解。用例一断言调用次数const onChangeMock jest.fn(); render(FavoriteInput onChange{onChangeMock} /); await user.type(input, Lion); expect(onChangeMock).toHaveBeenCalledTimes(4);jest.fn()创建一个录音机式的 Mock 函数。user.type(input, Lion)会逐个字符地模拟输入触发 4 次change事件因此断言onChangeMock恰好被调用 4 次toHaveBeenCalledTimes。这里体现了 user-event 的一个重要特性type模拟的是逐键输入而非一次性赋值——这正是它能触发多次回调的原因。用例二断言调用参数await user.type(input, Ox); expect(onChangeMock).toHaveBeenNthCalledWith(1, O); expect(onChangeMock).toHaveBeenNthCalledWith(2, Ox);toHaveBeenNthCalledWith(n, ...args)断言第 n 次调用时的实参。输入 Ox 时第 1 次回调收到O第 2 次收到Ox——这精确验证了组件把event.target.value完整当前值而非单个字符传给onChange的契约。该用例比用例一更能捕捉参数拼接逻辑类回归。用例三从 DOM 侧反向验证await user.type(input, Whale); expect(input).toHaveValue(Whale);课程明确说明这个用例其实多余redundant它存在的意义是展示另一种验证思路——不通过 Mock 函数而是直接断言 DOM 节点状态toHaveValue来自testing-library/jest-dom。你可以把三种写法看作同一行为的三面镜子调用次数、调用参数、DOM 结果。小练习花点时间判断上述代码中每个函数分别来自哪个包——render/screen来自testing-library/reacttoHaveBeenCalledTimes/toHaveBeenNthCalledWith来自 JesttoHaveValue来自testing-library/jest-domuser.type来自testing-library/user-event。实践建议mock 放测试内而非 beforeEach课程特别讨论了 Mock 的放置位置原文讨论默认在每个测试用例内部完成全部 setup包括jest.fn()与render。这样读任意一个用例都不需要翻遍整个文件找上下文后续 review 改动更轻松也降低了状态泄漏污染整个测试套件的风险只有当测试文件极长、且每个用例的准备代码多达数十行时才考虑用beforeEach抽公共部分推荐在渲染组件之前调用userEvent.setup()并不鼓励在测试外部例如beforeEach里调用render和 userEvent 函数若多个用例存在重复代码官方推荐的瘦身方式是编写 setup 辅助函数而不是塞进beforeEach。这一建议与第一部分课程 react_testing_part_one.md 的提醒一脉相承Testing Library 会在每个测试结束后自动卸载已渲染组件因此每个用例都需要重新render同时 user-event 从 v14 起 API 变为异步userEvent.setup()await user.click(...)用例回调需声明为async。Mocking 子组件砍掉组件树里的枝杈第二个 Mock 场景是子组件 Mock课程说明。当组件树变得很大时——尤其是位于树高层的组件——测试会越来越混乱渲染一个上层组件意味着连带渲染它下面整棵子树而子树中的真实逻辑、网络请求、上下文依赖都会干扰测试。解决办法是把子组件替换为最小化的假实现。这是模块 Mockmodule mocking思想在 React 中的体现jest.mock()拦截模块导入让被测组件拿到一个空壳子组件。课程也提醒这不是每天都会用到的技巧但理解其原理能让你在真正需要时例如第三方组件库行为不可控时从容应对。真实世界案例SubmissionsList 组件测试课程用 The Odin Project 官网真实存在的项目提交列表组件SubmissionsList作为真实世界测试的标本课程原文——这是本仓库所服务课程的实际产物也是理解文档知识如何落地到生产项目的最佳样板。下面还原其测试思路。第一步通读组件找出可测点submissions-list.jsx是一个普通的 React 组件顶部导入一堆依赖含个别陌生工具props 中有若干函数推测为事件处理器。通读渲染逻辑可提炼出三个要点若存在userSubmission渲染Submission组件若hasSubmissions为真对 submissions 排序后用Submission渲染否则渲染标题 No Submissions yet, be the first!若allSubmissionsPath为真渲染一个p标签。这正是设计测试前的关键动作先过一遍代码、列出可测点再据此规划用例。在继续阅读之前不妨花几秒自己列出针对SubmissionsList可能需要的测试有哪些提示三个分支条件 × 真假两种取值即可构成若干组合。第二步Mock 子组件与外部依赖测试文件中有两个需要处理的子组件一个来自第三方包react-flip-move外部代码直接 Mock另一个是本项目的Submission组件。课程展示了核心的 Mock 写法代码示例jest.mock(../submission, () ({ submission, isDashboardView }) ( div contenteditable="false">【免费下载链接】curriculumThe open curriculum for learning web development项目地址: https://gitcode.com/GitHub_Trending/cu/curriculum创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

深入 SymPy 级数展开模块:Gruntz 极限算法、series 展开、Order 阶项与留数计算 2026/9/15 12:36:51

深入 SymPy 级数展开模块:Gruntz 极限算法、series 展开、Order 阶项与留数计算

深入 SymPy 级数展开模块:Gruntz 极限算法、series 展开、Order 阶项与留数计算 【免费下载链接】sympy A computer algebra system written in pure Python 项目地址: https://gitcode.com/GitHub_Trending/sy/sympy SymPy 的 sympy.series 模块是纯 Python…

阅读更多 →
KITTI数据集预处理全流程:从点云到BEV训练样本生成指南 2026/9/15 12:36:51

KITTI数据集预处理全流程:从点云到BEV训练样本生成指南

说实话,被Complex-YOLO训练篇第一课卡住的人,十有八九不是倒在模型结构上,而是倒在KITTI数据集的预处理上。点云数据怎么读、标签怎么解析、BEV鸟瞰图怎么生成、标签和点云怎么对齐,这一连串问题如果没搞透彻,后面网络…

阅读更多 →
Unity Android打包签名报错:Unable to sign the application 详解 2026/9/15 12:36:51

Unity Android打包签名报错:Unable to sign the application 详解

1. 问题现象:打包时突然蹦出来的签名报错先说结论:这个报错Unable to sign the application; please provide passwords!,我这边最早是在用Unity打包Android版本的时候遇到的,后来帮同事排查,发现iOS、乃至部分场景下的…

阅读更多 →
Spring Boot 3 升级必读,Hystrix 迁移到 Resilience4j 实战指南 2026/9/15 12:36:51

Spring Boot 3 升级必读,Hystrix 迁移到 Resilience4j 实战指南

Hystrix 时代的终结与 Spring Boot 3 的升级阵痛 如果你正在规划或执行 Spring Boot 3 的升级路线,那么有一个无法回避的事实必须摆在桌面上:Hystrix 已经彻底退出了历史舞台。自 Spring Cloud 2020.0(对应 Spring Boot 2.4)起&am…

阅读更多 →
Unity桌面捕获实战:Windows Graphics Capture与外部纹理渲染指南 2026/9/15 12:36:51

Unity桌面捕获实战:Windows Graphics Capture与外部纹理渲染指南

简介:这是一款面向Unity开发者的Windows桌面捕获插件,用于在Unity场景中实时展现并同步Windows桌面内容。借助它将桌面或指定窗口转换为Unity纹理,开发者可快速构建桌面预览、多屏协同、录屏展示等交互应用,适合工具型或演示型项目…

阅读更多 →
Mastra E2B Sandbox 集成指南:为 Workspace 与 Agent 搭建安全隔离的云端代码执行环境 2026/9/15 12:33:51

Mastra E2B Sandbox 集成指南:为 Workspace 与 Agent 搭建安全隔离的云端代码执行环境

Mastra E2B Sandbox 集成指南:为 Workspace 与 Agent 搭建安全隔离的云端代码执行环境 【免费下载链接】mastra Mastra is the modern TypeScript framework for AI-powered applications and agents. 项目地址: https://gitcode.com/GitHub_Trending/ma/mastra …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞