ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

从 Jasmine 到 Jest:JavaScript 单元测试实战指南(curriculum 测试课程全解析)

2026/9/15 13:58:05 拓冰建站 浏览量
从 Jasmine 到 Jest:JavaScript 单元测试实战指南(curriculum 测试课程全解析) 从 Jasmine 到 JestJavaScript 单元测试实战指南curriculum 测试课程全解析【免费下载链接】curriculumThe open curriculum for learning web development项目地址: https://gitcode.com/GitHub_Trending/cu/curriculumJavaScript 正在成为 Web 世界的核心语言越来越多的业务逻辑从前端走向客户端Node.js 甚至让 JavaScript 进入服务端。逻辑越多代码就越容易在不经意间被破坏——而单元测试正是让开发者及时发现哪里坏了、什么时候坏的的最可靠手段。本文以本仓库 archive/old_lessons/javascript/js_testing.md 这一历史课程文档为骨架梳理 JavaScript 测试的核心价值、主流工具QUnit、Jasmine、Jest及其演进脉络并结合仓库中现役测试课程javascript/testing_javascript/testing_basics.md、javascript/testing_javascript/more_testing.md的源码级实践帮你完整掌握从为什么要测到怎么写测试、测什么的完整链路。为什么要为 JavaScript 编写测试没有测试你永远不知道代码何时被破坏原文档开篇即点明核心观点我们不会深入 JavaScript 测试的每一个细节但必须承认——测试所扮演的价值与 Ruby / Rails 世界中的 RSpec 完全对等。没有测试你就无法得知应用中的关键逻辑何时被破坏更无法定位它究竟是在哪一次改动中停止工作的。这一论断在仓库后续的课程中得到了进一步印证。javascript/testing_javascript/more_testing.md 明确指出测试失败时我们希望尽可能快地缩小失败原因的范围。如果一个测试依赖多个函数当它失败时很难判断究竟是哪个环节出了问题——这正是隔离isolation概念存在的意义一次只测一个方法且尽量不依赖外部函数的行为。测试的价值随代码复杂度持续放大react/react_testing/introduction_to_react_testing.md 从 UI 测试的角度补充了一个重要事实即使底层逻辑测试全部通过也不代表 UI 真正展示了预期内容。随着网站越来越复杂好的测试无论 UI 还是非 UI的价值只会不断增加——你不可能在每次改动后手动复查所有相关界面。测试工具的演进QUnit、Jasmine 与 Jest原课程时代的工具版图原文档的学习任务Assignment围绕两类当时主流的框架展开QUnit通过 Smashing Magazine 的《Introduction to Javascript Unit Testing》教程学习如何构建自己的测试并使用 QUnit 框架Jasmine通过 HTMLGoodies 与 TutsPlus 的教程了解 Jasmine 的高层概览与进阶用法并阅读其 GitHub 上的官方 READMETest-First JavaScript作为补充资源提供测试先行test-first方向的练习仓库。原文档特别强调这堂课的意义是为你提供一个起点head start让你能独立开始实验而不是面面俱到地讲授全部细节。现役课程的选择Jest 与语法趋同随着生态演进仓库现役测试课程javascript/testing_javascript/testing_basics.md明确将重心转向Jest并给出了一个重要判断JavaScript 领域存在众多测试运行器——Mocha、Jasmine、Tape、Jest——但它们的语法非常相似基本语法几乎一致。每个工具都有各自的特长但最终用哪个并不那么关键真正重要的是TDD 哲学知道为什么写测试、测什么而不是怎么写。这一演进脉络同样体现在仓库的其他模块中React 课程使用Vitest与 Vite 深度集成见 react/react_testing/introduction_to_react_testing.mdExpress 后端课程使用Jest SuperTest见 nodeJS/testing_express/testing_routes_and_controllers.md——工具随场景变化但测试的核心理念一脉相承。上手 Jest环境搭建与基础断言安装与 ESM 兼容配置仓库现役课程给出的最小可运行方案如下npm install --save-dev babel/preset-env^7并在项目根目录创建babel.config.jsexport default { presets: [[babel/preset-env, { targets: { node: current } }]], };这里有一个值得注意的前提与限制默认情况下当时的 Jest 版本不识别 ESM因此官方指南使用 CJS 语法module.exports。若要使用 ES6 的import/export需要上述 Babel 配置。Babel 会在内存中将 ESM 转换为 CJS 后再运行 Jest不会覆盖你的实际文件。同时课程提示如果你使用 ESLint需要显式导入test、expect等全局变量以避免 lint 报错。常用匹配器Matchers编写测试时expect与各类匹配器构成断言体系。课程引用的常用匹配器包括匹配器用途toBe精确相等Object.is语义toEqual递归检查对象或数组的每个字段toMatch正则或子串匹配toContain数组或可迭代对象是否包含某项一个完整的实战练习集project_testing_practice.md 提供了一套非常适合入门练手的功能清单读者可以按先写测试、再让测试通过的方式完成capitalize接收字符串返回首字母大写的字符串reverseString接收字符串返回反转后的结果calculator对象包含add、subtract、divide、multiply四个函数各接收两个数字并返回正确计算结果caesarCipher接收字符串与移位因子返回每个字符被位移后的结果。需要重点覆盖三个边界环绕wrappingcaesarCipher(xyz, 3)应返回abc大小写保持case preservationcaesarCipher(HeLLo, 3)应返回KhOOr标点与空格不变caesarCipher(Hello, World!, 3)应返回Khoor, Zruog!analyzeArray接收数字数组返回包含average、min、max、length四个属性的对象const object analyzeArray([1,8,3,4,2,6]); // object should equal: { average: 4, min: 1, max: 8, length: 6 }课程还给出了一条重要测试原则不需要显式测试你写的每一个函数只需测试公开接口public functions。例如caesarCipher可以拆分为若干小函数但只需为最终公开的caesarCipher编写测试——只要它行为正确即可放心内部辅助函数按预期工作。让代码可测试纯函数、解耦与 Mocking紧耦合代码为何难以测试这是 more_testing.md 的核心主题。看这个典型例子function guessingGame() { const magicNumber 22; const guess prompt(guess a number between 1 and 100!); if (guess magicNumber) { alert(YOUR GUESS IS TOO BIG); } else if (guess magicNumber) { alert(YOUR GUESS IS TOO SMALL); } else if (guess magicNumber) { alert(YOU DID IT! ); } else { return INVALID INPUT; } }这个函数将判断逻辑与浏览器内置的prompt/alert紧紧耦合在一起。想象为它编写测试的难度你既无法方便地模拟用户输入也无须测试浏览器已经验证过的内置函数。解决方案是把逻辑抽离出来function evaluateGuess(magicNumber, guess) { if (guess magicNumber) { return YOUR GUESS IS TOO BIG; } else if (guess magicNumber) { return YOUR GUESS IS TOO SMALL; } else if (guess magicNumber) { return YOU DID IT! ; } else { return INVALID INPUT; } } function guessingGame() { const magicNumber 22; const guess prompt(guess a number between 1 and 100!); const message evaluateGuess(magicNumber, guess); alert(message); } guessingGame();重构后唯一需要测试的evaluateGuess具有清晰的输入输出、不调用任何外部函数测试难度大幅下降。这种实现也更易于扩展未来将prompt/alert替换为 DOM 操作、或支持多次猜测都会更加轻松。TDD 之所以能催生更好的程序架构正是因为它鼓励你写出纯函数Pure Functions。两个解耦方案移除依赖与 Mocking面对紧耦合代码有两个解决方案首选方案像上面那样从代码中移除依赖解耦次选方案Mocking当解耦不可行时编写假版本的函数让它总是精确返回你想要的行为。例如测试一个从 DOM 输入读取信息的函数时你不需要真的搭建网页并动态插入内容——只需创建一个 mock 函数让它固定返回某个值即可。课程建议进一步阅读 Jest 的 Setup and Teardown 文档 与 Mock Functions 文档并思考这些问题紧耦合代码是什么纯函数的两个必要条件是什么什么是副作用测试紧耦合代码前应优先尝试什么Mock 何时使用工具链的纵深扩展从浏览器到服务端原文档聚焦浏览器端 JavaScript 测试而本仓库的后续课程将同一套理念延伸到了整个工具链可作为继续深入的方向React UI 测试react/react_testing/introduction_to_react_testing.md使用 Vitest React Testing Library通过render渲染组件、getByRole等查询方法断言 DOM 内容用userEvent模拟点击等真实交互并利用 jsdom 在内存中模拟 DOM不实际打开浏览器。该课程还深入剖析了快照测试snapshot testing的利弊——它书写快、能拦截意外变更但也可能带来误报与误伤Express 路由测试nodeJS/testing_express/testing_routes_and_controllers.md使用 SuperTest底层基于 SuperAgent配合 Jest。核心技巧是将路由抽离为独立模块并导出用express.Router()测试时重建一个 Express 应用挂载该路由从而避免调用app.listen启动真实服务器test(index route works, done { request(app) .get(/) .expect(Content-Type, /json/) .expect({ name: frodo }) .expect(200, done); });这里的done参数用于异步测试完成信号SuperTest 允许把它传入最后一个.expect并代为调用。对 POST 场景可用.type(form).send(...)发送表单数据再用.then()串起后续断言。从源码结构看这一系列课程共同勾勒出一条完整的学习路径浏览器端纯函数测试Jest→ 组件/UI 测试Vitest RTL→ 服务端路由测试Jest SuperTest。测试哲学始终一致——围绕为什么测、测什么展开工具只是表达手段。小结回到原文档的起点测试的核心价值在于让你在破坏关键功能的第一时间发现它。从 QUnit、Jasmine 到 Jest 的演进改变的只是 API 形式不变的是断言-运行-反馈的循环以及 TDD 所倡导的先写测试、再写实现、让架构自然解耦的工作方式。无论你将来选择 Jest、Vitest 还是 SuperTest请记住课程反复强调的那句话写测试更重要的是 TDD 哲学——知道为什么写、写什么而不是怎么写。【免费下载链接】curriculumThe open curriculum for learning web development项目地址: https://gitcode.com/GitHub_Trending/cu/curriculum创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考