javascript如何编写可测试的代码_有哪些原则和工具【教程】
技术百科
狼影
发布时间:2026-01-27
浏览: 次 JavaScript代码可测试性的核心在于函数纯度、显式依赖和副作用隔离:纯函数需避免隐式状态依赖,依赖应通过参数注入而非闭包或顶层模块引用,副作用如时间、I/O等需抽象为可替换输入,测试时优先真实渲染而非过度mock,并正确处理异步逻辑。
JavaScript 代码可测试性的核心不在于用什么框架,而在于函数是否纯、依赖是否显式、副作用是否隔离。
函数要尽量纯,避免隐式状态依赖
纯函数指相同输入永远返回相同输出,且不修改外部变量或触发 I/O。这类函数天然容易单元测试,因为不需要 mock 环境。
常见破坏纯度的操作:new Date()、Math.random()、读取 localStorage、直接调用 fetch()、修改传入对象的属性。
实操建议:
- 把时间、随机数等“外部输入”作为参数传入,比如
formatDate(date = new Date())改为formatDate(date),测试时传入固定new Date('2025-01-01') - 避免在函数内部直接调用
console.log或alert;如需日志,接受一个logger函数作为参数 - 对象操作优先用解构 + 扩展符生成新对象,而不是
obj.name = 'x'
依赖要显式注入,别藏在闭包或模块顶层
如果一个函数内部直接引用了全局 API_CLIENT 或通过 import { api } from './api' 引入模块,它就和具体实现强耦合,测试时无法替换为 mock 版本。
实操建议:
- 用依赖注入方式传递关键服务:比如
functio,测试时传入
n uploadFile(file, uploader)
{ upload: jest.fn().mockResolvedValue({ id: 1 }) } - 避免在模块顶层执行初始化逻辑(如
const client = createClient(...)),改用工厂函数createApiClient(config),测试时可传入不同 config 或 mock 实现 - ESM 中慎用命名导入做“单例式依赖”,更推荐默认导出工厂函数或类
用 Jest + Vitest 做隔离测试,但别过度 mock
Jest 是目前最成熟的 JS 测试工具,Vitest 则更轻量、与 Vite 生态集成更好,两者 API 高度兼容。它们都支持 jest.mock() 和 vi.mock() 来拦截模块依赖。
容易踩的坑:
-
jest.mock()必须在文件顶部调用(不是在beforeEach里),否则可能 mock 失败 - mock 深层依赖(如
axios.get)时,确保路径准确:是jest.mock('axios'),不是jest.mock('./utils/api') - 过度 mock 会让测试失去意义——比如 mock 掉整个 UI 组件树后,只测了个空壳,不如少 mock、多用真实渲染(
@testing-library/react)
异步逻辑必须明确处理完成信号
忘记 await、漏掉 done() 回调、或没正确处理 Promise rejection,都会导致测试“假通过”或超时失败。
典型错误现象:Timeout - Async callback was not invoked within the 5000ms timeout specified 或测试跳过断言直接结束。
实操建议:
- 所有返回 Promise 的函数,测试中必须
await它,或用return expect(...).resolves.toEqual(...) - 测试错误路径时,用
await expect(fn()).rejects.toThrow(...),不要写try/catch+expect - 避免在测试中使用
setTimeout等手动等待;优先用库提供的异步工具,如waitFor(@testing-library)或vi.advanceTimersByTime()(Vitest)
真正难的不是写 test(),而是让业务逻辑不和 DOM、网络、时间、本地存储这些“不可控因素”搅在一起。越早把边界划清楚,后续加测试、改逻辑、换技术栈就越轻松。
# ai
# 工具
# js
# javascript
# java
# 栈
# try
# catch
# 闭包
# ios
# const
# date
# react
# axios
# vite
# math
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- 如何在 Go 中比较自定义的数组类型(如 [20]
- php怎么下载安装后无法解析php文件_服务器配置
- php8.4新语法match怎么用_php8.4m
- Linux如何挂载新硬盘_Linux磁盘分区格式化
- Windows10怎么备份注册表_Windows1
- Linux怎么实现内网穿透_Linux安装Frp客
- c# 在高并发下使用反射发射(Reflection
- 如何在Golang中编写异步函数测试_Golang
- Win11如何隐藏桌面图标 Win11一键隐藏/显
- Windows10如何查看保存的WiFi密码_Wi
- 如何在 Go 应用中实现自动错误恢复与进程重启机制
- Windows蓝屏错误0x00000023怎么修复
- mac怎么右键_MAC鼠标右键设置与触控板手势技巧
- c++中如何使用虚函数实现多态_c++多态性实现原
- Python包结构设计_大型项目组织解析【指导】
- Windows如何查看和管理已安装的字体?(字体文
- php会话怎么开启_session_start函数
- Win11怎么恢复误删照片_Win11数据恢复工具
- Windows10系统怎么查看显卡驱动_Win10
- Mac怎么设置鼠标滚动速度_Mac鼠标设置详细参数
- Win11怎么设置默认浏览器Chrome_Wind
- Mac上的iMovie如何剪辑视频?(新手入门教程
- php订单日志怎么记录评价_php记录订单评价日志
- c++怎么使用std::tuple存储多元组数据_
- 如何使用Golang安装API文档生成工具_快速生
- Win10怎样设置闹钟贪睡时间 Win10闹钟贪睡
- Windows10如何更改开机密码_Win10登录
- Django 测试数据库表缺失与字段未创建问题的完
- Win11怎么查看已连接wifi密码 Win11查
- Win11怎么设置声音输出设备_Windows11
- Win10如何更改网络连接_Windows10以太
- Windows Defender扫描失败怎么办_安
- Python安全爬虫设计_IP代理池与验证码识别策
- 如何使用Golang指针与结构体结合_修改结构体内
- C++中的Pimpl idiom是什么,有什么好处
- php和redis连接超时怎么办_phpredis
- XAMPP 启动失败(Apache 突然停止)的终
- Mac如何调整Dock栏大小和位置_Mac程序坞个
- c++怎么处理多线程死锁_c++ lock_gua
- php怎么下载安装后设置错误日志_phpini l
- Win11怎么开启移动热点_Windows11共享
- Windows10如何更改任务栏高度_Win10解
- Python如何创建带属性的XML节点
- Mac如何创建和管理多个桌面空间_Mac高效多任务
- php增删改查报错1054怎么办_字段名错误排查修
- Win10怎样清理C盘阿里旺旺缓存_Win10清理
- Python项目维护经验_长期演进说明【指导】
- php485读数据时阻塞怎么办_php485非阻塞
- 如何使用Golang构建简易投票统计功能_Gola
- Win11怎么设置夜间模式_Windows11显示


QQ客服