答案是聚焦三类典型单元测试场景并依FIRST原则优化:纯计算函数需覆盖边界值与浮点误差;带副作用函数须mock外部依赖并验证调用;状态管理逻辑应测试异常流程与状态迁移;再按快、独立、可重复、自验证、及时五项自查,结合覆盖率报告补盲区、删冗余、提精度。

直接从高频、易错、有代表性的案例入手,不堆概念,不空讲理论。重点不是“背题”,而是理解测试背后的意图和常见失衡点。
聚焦三类典型单元测试场景
多数 JS 单元测试问题集中在以下三类函数上,复盘时优先拿下:
-
纯计算函数(如工具方法):比如
sum(a, b)、debounce、deepClone。容易忽略边界值(null、undefined、NaN、循环引用)、类型误判(字符串数字相加)、浮点误差等。调优关键:用toBeCloseTo替代toBe处理小数;显式覆盖0、-0、Infinity等边缘输入。 -
带副作用的函数(如 API 调用、DOM 操作):比如
fetchUser(id)或renderList(items)。错误做法是让它真实发请求或操作真实 DOM。正确做法是用jest.mock模拟fetch,或用jest.fn()替换document.createElement等。复盘时检查:是否隔离了外部依赖?是否验证了 mock 被调用的次数和参数?是否覆盖了成功、失败、加载中三种状态? -
状态管理逻辑(如 React 组件逻辑、Redux reducer):比如购物车增删、表单校验、分页计算。常见问题是只测“正常流程”,漏掉并发更新、重复提交、非法状态迁移。调优建议:用
act包裹异步状态更新;对 reducer 测试,明确写出initialState → action → expectedState三元组;避免在测试里写太多渲染逻辑,专注行为契约。
对照 FIRST 原则逐条自查
每次写完或读完一个测试用例,快速过一遍这五条(不记全称,记要点):
-
F(快):单个测试是否在 50ms 内完成?如果有
setTimeout或真实网络等待,立刻改用jest.useFakeTimers()或 mock。 -
I(独立):这个测试删掉其他测试还能跑通吗?是否依赖全局变量、共享 state 或 localStorage?如有,加
beforeEach(() => {...})重置环境。 - R(可重复):连续运行 5 次结果是否完全一致?随机数、时间戳、Math.random() 都要 mock 掉。
-
S(自验证):断言是否明确、无歧义?比如不用
expect(result).toBeTruthy(),而用expect(result.status).toBe('success')。 - T(及时):测试是否在功能代码改动后立刻失败?如果改了逻辑但测试没红,说明它没真正约束行为——可能断言太弱,或根本没测到核心路径。
用覆盖率报告反向定位盲区
运行 npm test -- --coverage 后,打开生成的 coverage/lcov-report/index.html。重点关注:
- 哪些
if/else分支没被执行?补一个让条件为false的测试用例; - 哪些
catch块是红色的?手动抛错模拟异常路径; - 哪些函数参数没被传过
null或空数组?加上对应用例; - 别迷信 100% 行覆盖——有些行(如
console.log)不测也无妨,关键是业务逻辑分支是否全覆盖。
调优不是加更多测试,而是删冗余、补缺口、提精度
发现一个测试长期跳过(test.skip)或反复修改断言才能通过,说明它要么在测不该测的东西,要么暴露了设计缺陷。这时候停一下:这个函数职责是否太重?能不能拆?依赖是否该抽象成接口?往往一次重构,比写十个脆弱测试更有效。


















