React Speed Coding 测试完全指南:Enzyme + Mocha + Chai 编写 React 组件 BDD 测试的 8 个技巧
【免费下载链接】reactspeedcoding:rocket: Learn React with 30 reusable components, 15 chapters, and 3 single page apps. Fast start project with JavaScript ES6. React Hot Loading. React Router. Redux. PostCSS, FlexBox styling. Firebase database. Webpack packaging. Enzyme, Mocha, Chai BDD testing. ESLint and StyleLint. Browsersync.项目地址: https://gitcode.com/gh_mirrors/re/reactspeedcoding
React Speed Coding 是一个包含 30 个可复用组件、15 个章节和 3 个单页应用的 React 学习项目,其测试体系基于Enzyme + Mocha + Chai这套经典的 React 组件 BDD 测试组合。本文将结合项目中的真实测试代码,拆解 8 个核心技巧,带你从"不会写测试"到能独立完成 React 组件行为测试。
💡 动手前建议先获取代码:
git clone https://gitcode.com/gh_mirrors/re/reactspeedcoding
测试工具栈一览:测试、Lint 与自动刷新如何协作
上图展示了项目质量保障的完整链路:Mocha 测试 + ESLint / StyleLint 代码检查 + Browsersync 浏览器自动刷新,三者共同保证代码又快又稳。
| 工具 | 角色 | 在项目中 |
|---|---|---|
| Mocha | BDD 测试运行器 | test/**.spec.js用例执行 |
| Chai(expect 风格) | 断言库 | expect(...).to.equal(...) |
| Enzyme | React 组件测试工具 | shallow/render/mount三层渲染 |
| jsdom | 模拟浏览器环境 | browser.js |
| sinon | 行为验证(spy/stub) | 01_workflow.spec.js |
| babel-istanbul | 测试覆盖率 | npm run cover |
技巧 1:一条命令跑完测试与静态检查
项目的 package.json 把测试流程编排成了几条 npm 脚本,这是新手最容易忽略但最实用的技巧——先约定命令,再谈测试本身:
npm test # ESLint + StyleLint + Mocha 三步走 npm run test:mocha # 只跑 Mocha 组件测试 npm run cover # 生成测试覆盖率报告其中 test:mocha 的关键点在于把 test/helpers/browser.js 作为第一个参数传给 Mocha——它会在任何测试用例执行前先搭建好模拟浏览器环境(见技巧 2)。
技巧 2:用 jsdom 为 React 测试搭建浏览器环境
React 组件依赖document、window、navigator这些浏览器对象,而 Mocha 跑在 Node 里,所以测试前必须先"伪造"一个浏览器。项目的做法非常干净:
global.document = jsdom(''); global.window = document.defaultView; global.navigator = { userAgent: 'node.js' };完整实现见 browser.js。记住这个模式:Node 环境 + jsdom 注入全局对象 = React 测试可用的 DOM。
技巧 3:用 Mocha 的 describe/it 组织 BDD 测试
BDD(行为驱动开发)的核心是让测试读起来像需求描述。项目约定用<组件名 />作为describe标题,用should ...描述预期行为,例如 02_mocha_chai.spec.js 就演示了三层嵌套结构:
describe('Mocha Chai Demo', () => { describe('Array operations', () => { describe('#indexOf()', () => { it('should return -1 when the value is not present', () => { expect([1, 2, 3].indexOf(5)).to.equal(-1); }); }); }); });另外,项目还特意放了一个 Mocha 超时示例,教你用this.timeout(500)调整超时时间——异步测试经常因此误报失败,提前知道这个开关能省不少排查时间。
技巧 4:Chai expect 断言要"说人话"
Chai 的 expect 风格支持链式调用,项目里高频出现的断言模式有四种:
| 断言写法 | 含义 | 项目示例 |
|---|---|---|
to.equal(值) | 精确相等 | 01_workflow.spec.js 校验stepsIndex为 1 |
to.have.length(n) | 数量校验 | 02_card.spec.js 校验.card只有 1 个 |
to.be.defined | 属性存在 | 01_workflow.spec.js 校验stepsprop 已定义 |
to.be.above(n) | 数量下限 | 03_roadmap.spec.js 校验组件数量大于 2 |
小技巧:用数量断言代替全量快照,列表类组件(如 Roadmap)数据经常变化,length.above(2)比逐条比对更抗变化。
技巧 5:Enzyme 三层渲染,按需选择测试深度
这是整篇文章最值钱的技巧。Enzyme 提供三种渲染方式,测试强度逐级递增:
上图就是项目中的 Roadmap 应用(React 组件测试的实战对象),它的 测试文件 同时用到了三种渲染方式:
shallow(浅渲染):只渲染被测组件一层,最快,适合单元测试。如 02_card.spec.js 用wrapper.is('.card')校验根节点类名;render(静态 HTML):输出真实 DOM,适合校验整棵子树的最终结构。如 03_roadmap.spec.js 校验.search-filter存在;mount(完整挂载):带状态、带事件的全量渲染,适合测试交互行为(见技巧 6、7)。
经验法则:先 shallow,不够再 mount,能跑快的测试跑得越快,整个套件就越稳。
技巧 6:simulate 模拟用户点击,测试交互状态
静态渲染只能证明"组件画出来了",真正的行为测试要模拟用户操作。Workflow 组件测试 展示了标准套路——渲染 → 触发事件 → 断言状态变化:
const wrapper = mount(<Workflow />); wrapper.find('button.default').simulate('click'); expect(wrapper.state('stepsIndex')).to.equal(1);被测试的 Workflow 组件 点击按钮后应把stepsIndex从 0 递增到 1,测试精确验证了这一点。还有一招wrapper.setState({ stepsIndex: 1 })可以先手动设置初始状态再触发,用于测试"第 N 次点击"这类依赖前置状态的场景。
技巧 7:用 sinon.spy 验证"方法被调用了"
有时你不关心方法内部逻辑(那些逻辑另有单元测试),只关心它是否被触发。项目用 sinon 做了教科书式的演示,见 01_workflow.spec.js:
sinon.spy(Workflow.prototype, 'cycleScenario'); const wrapper = mount(<Workflow />); expect(Workflow.prototype.cycleScenario.calledOnce).to.equal(false); // 点击前:没调用 wrapper.find('button.primary').simulate('click'); expect(Workflow.prototype.cycleScenario.calledOnce).to.equal(true); // 点击后:调用了"调用前断言一次、调用后再断言一次"——这种前后对照写法能彻底排除假阳性,是行为验证的推荐姿势。
技巧 8:测试 Redux Store,用空测试当 TODO 清单
Roadmap 是项目里最复杂的 Redux 单页应用,测试分两部分:
① 组件测试需要 Provider 包裹。React Redux 组件必须拿到 store 才能渲染,项目用 roadmapHydrate 预填充数据后,再用<Provider store={store}>包住组件(见 03_roadmap.spec.js)。
② 独立测试状态树。不渲染任何组件,直接dispatchaction 验证 state 变化,如 setCategoryFilter 与 setSearchText 测试。
③ 留白即 TODO。Mocha 允许只写it('...')不写函数体,测试会以"待办"状态列出。项目大量使用这一招,例如 03_roadmap.spec.js:
it('should execute onChange() when user presses key in search box'); it('should update state tree after onChange() is called in search field');这让测试文件同时成为验收清单,新接手的人一眼就知道还欠哪些测试。
8 个技巧速查清单
| # | 技巧 | 关键命令/写法 | 参考文件 |
|---|---|---|---|
| 1 | 一键跑测试+Lint | npm test | package.json |
| 2 | jsdom 模拟浏览器 | global.document = jsdom('') | browser.js |
| 3 | BDD 结构组织 | describe/it/this.timeout | 02_mocha_chai.spec.js |
| 4 | expect 断言模式 | equal/length/defined/above | 01_workflow.spec.js |
| 5 | Enzyme 三层渲染 | shallow→render→mount | 03_roadmap.spec.js |
| 6 | 模拟交互 | simulate('click')+state()断言 | 01_workflow.spec.js |
| 7 | 行为验证 | sinon.spy+calledOnce前后对照 | 01_workflow.spec.js |
| 8 | Redux 测试与 TODO | <Provider>包裹 + 空it占位 | 03_roadmap.spec.js |
🎯 总结:React 组件测试的黄金路径就是jsdom 铺路 → shallow 快测 → mount 测交互 → sinon 验行为 → 空 it 记 TODO。照着这 8 个技巧,你就能为任何 React 组件写出既快又可维护的 BDD 测试。
【免费下载链接】reactspeedcoding:rocket: Learn React with 30 reusable components, 15 chapters, and 3 single page apps. Fast start project with JavaScript ES6. React Hot Loading. React Router. Redux. PostCSS, FlexBox styling. Firebase database. Webpack packaging. Enzyme, Mocha, Chai BDD testing. ESLint and StyleLint. Browsersync.项目地址: https://gitcode.com/gh_mirrors/re/reactspeedcoding
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考