ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Jasmine Core 2.0 破坏性变更与架构演进深度解析:异步规格、Spy 语法、Reporter 接口与相等性测试重构全记录

Jasmine Core 2.0 破坏性变更与架构演进深度解析:异步规格、Spy 语法、Reporter 接口与相等性测试重构全记录 测试质量保障【免费下载链接】jasmineSimple JavaScript testing framework for browsers and node.js项目地址https://gitcode.com/gh_mirrors/ja/jasmine点击查看免费下载本文基于 Jasmine 仓库 release_notes/20.md 发布说明撰写。Jasmine 2.0 是框架历史上一次推倒重来式的大版本它重写了异步测试语法、Spy 与自定义 Matcher 接口替换了相等性测试引擎重构了 Reporter 协议并把 Node.js 提升为一级支持对象。读完本文你将系统掌握 2.0 版本每一项破坏性变更的前因后果、新接口的用法以及这些设计如何在当前仓库源码中落地与延续从而在升级或阅读新旧代码时准确判断接口语义。一、2.0 版本定位一次面向接口一致性的重构Jasmine Core 2.0的发布说明release_notes/20.md开篇即明确这一版本的核心不是新增功能而是接口的全面重设计。官方列出的破坏性变更不兼容 1.x共八项异步规格async specs的新语法Spy 的新语法Reporter 的新接口更好的相等性Equality测试自定义 Matcher 接口替换toThrowmatcher 行为变更Clock 在规格结束后保持安装更多内部变量/函数被移入闭包下面逐项展开并对照当前仓库源码给出实现印证。二、破坏性变更逐项详解附源码印证2.1 异步规格新语法done回调驱动的串行队列1.x 时代异步测试依赖waitsFor/runs这类显式调度原语写法繁琐。2.0 参考了 Mocha 的做法before/it/after系列函数可以接受可选的done回调框架会等待done被调用或超时后才继续执行下一个before、spec或after。这套语义的底层实现正是当前仓库的 src/core/QueueRunner.js在attempt()中QueueRunner 检查queueableFn.fn.length若函数声明了形参即接收done则以fn.call(this.userContext, next)方式调用并标记为未同步完成completedSynchronously false若函数未声明形参但返回了 thenable则通过wrapInPromiseResolutionHandler(next)桥接 Promise每个 queueableFn 都会注册超时定时器queueableFn.timeout || j$.DEFAULT_TIMEOUT_INTERVAL超时后产生Timeout - Async function did not complete within Nms错误见 QueueRunner.jsnext被once()包裹重复调用done会触发onMultipleDone告警防止异步回调被调用多次导致队列混乱。这一设计沿用至今只是后来3.x 起Jasmine 进一步支持直接返回 Promise 的 async/await 风格。从源码结构看2.0 引入的回调串行队列 超时保护是整套异步模型的地基。2.2 Spy 新语法and链式配置与属性保留2.0 重构了 Spy 的配置语法核心动机是保留被 spy 函数上已有的属性并形成更清晰的测试模式。发布说明提到 preserve any of the properties on a spied-upon function这一点在 src/core/Spy.js 中仍有直接体现for (const prop in originalFn) { if (prop and || prop calls) { throw new Error(Jasmine spies would overwrite the and and calls properties ...); } wrapper[prop] originalFn[prop]; }Spy 包装函数会复制原函数的所有自有属性同时保留两个专用接口wrapper.and策略配置入口与wrapper.calls调用追踪器。新语法形态为spyOn(someObj, func).and.returnValue(42); spyOn(someObj, func).and.callThrough(); spyOn(someObj, func).and.callFake(function() { return fake; }); spyOn(someObj, func).and.throwError(boom); spyOn(someObj, func).and.stub();这些策略方法在 src/core/SpyStrategy.js 中均有定义其中returnValue与throwError正是发布说明 Bug 修复条目中提到的更佳命名A spys strategy now has propertiesreturnValueandthrowErrorbecause they are better names。此外Spy#withArgs允许按参数精确匹配策略Spy.js调用记录则通过CallTracker以callDataobject / invocationOrder / args / returnValue结构化保存Spy.js配合toHaveBeenCalledWith等匹配器使用。2.3 Reporter 新接口面向结果数据的事件协议2.0 将 Reporter 接口整体替换为更一致的回调集合并且传入的对象只提供报告结果所需的数据从而让自定义 Reporter 与 Jasmine 内部实现解耦。Reporter API 还新增了timer对象的槽位对应发布说明中 Reporters get execution time 这条合并的 PR。当前仓库 src/core/reporterEvents.js 定义了完整的事件集合事件触发时机jasmineStarted所有规格加载完毕、执行开始前jasmineDone整个套件执行结束suiteStarted/suiteDone每个describe开始 / 结束含子套件specStarted/specDone每个it含其beforeEach/afterEach开始 / 结束事件对象通过 src/core/ReportDispatcher.js 分发到所有注册的 ReporterEnv#addReportersrc/core/Env.js负责登记。这套六个事件 结构化结果对象的协议自 2.0 定型后基本保持稳定成为社区编写 Jasmine 自定义报告器的基础契约。2.4 更好的相等性测试源自 UnderscoreisEqual的重写2.0 删除了旧的相等性代码以 Underscore.js 的isEqual为起点重写并补充了大量测试。这一渊源在当前源码中仍有注释可查——src/core/matchers/matchersUtil.js 明确写道// Equality function lovingly adapted from isEqual in // [Underscore](http://underscorejs.org)新引擎MatchersUtil#equals标注since 2.0.0支持的语义包括原始值、字符串、数字含NaN、0/-0区分、布尔值的按值比较日期按毫秒时间戳比较正则按source与 flags 比较数组、Map、Set、嵌套对象的深度递归比较并处理循环引用DOM 节点走isEqualNode支持不对称相等性测试器asymmetric equality testers如jasmine.any()、jasmine.objectContaining()与equals/contains无缝协作通过customTesters_支持用户自定义相等性测试器Env#addCustomEqualityTester见 src/core/Env.js。同一文件中MatchersUtil#contains同样标注since 2.0.0用于toContain等匹配器。这也是jasmine.Any支持Boolean合并的 PR #392这类修复能够落地的底层基础。2.5 自定义 Matcher 接口替换官方匹配器同机制自举发布说明直言自定义 Matcher 的 API此前几乎无文档、难以测试2.0 将其整体替换并且Jasmine 自身的所有匹配器也改用同一套自定义机制注册——即Dogfooding吃自己的狗粮自举式开发。这一设计在 src/core/requireCore.js 中清晰可见private$.matchers jRequire.requireMatchers(jRequire, j$, private$); private$.asyncMatchers jRequire.requireAsyncMatchers(jRequire, j$, private$);requireMatchers.js/requireAsyncMatchers.js把官方匹配器统一装载后注入private$再由private$.Expectation.addCoreMatchers(...)挂到期望对象上src/core/Env.js。用户侧注册接口收敛为两个env.addMatchers({ ... }); // 同步匹配器 env.addAsyncMatchers({ ... }); // 异步匹配器见 src/core/Env.js。发布说明还提到自定义 Matcher 可传入negativeCompare用于.not场景的定制实现当前 src/core/Expectation.js 中依然保留.not对负向比较的调度逻辑。2.6toThrow拆分错误类型校验交给toThrowError2.0 改变了toThrow的职责边界将抛出特定类型 Error / 特定消息的校验能力迁移到新匹配器toThrowError从而覆盖更多使用场景src/core/matchers/toThrow.js只负责是否抛出了东西以及抛出的值与期望值是否相等matchersUtil.equals(thrown, expected)src/core/matchers/toThrowError.jssince 2.0.0支持四种组合用法——expect(fn).toThrowError(); // 只要抛出 Error expect(fn).toThrowError(MyCustomError); // 必须是某 Error 子类实例 expect(fn).toThrowError(message); // 消息精确匹配 expect(fn).toThrowError(MyCustomError, /bar/); // 类型 正则消息实现中isAnErrorType通过构造Surrogate原型链判断类型是否为 Error 子类exactMatcher则用error instanceof errorType与expected.test(error.message)双重判定toThrowError.js。另有一条相关修复toThrowmatchers handle falsy exceptionsPR #317保证抛出0、、null等 falsy 异常时也能正确报告。2.7 Clock 保持安装消除计时函数归属歧义1.x 中 Clock 会在规格结束时自动卸载导致当前到底用的是 mock 还是全局计时函数存在歧义。2.0 起安装install之后 Clock一直保持生效直到显式调用uninstall。当前 src/core/Clock.js 中的实现印证了这一契约install()since 2.0.0校验全局计时函数未被篡改后用setTimeout/clearTimeout/setInterval/clearInterval的 fake 版本替换全局Clock.jsuninstall()since 2.0.0恢复真实计时函数同时卸载MockDateClock.jstick(millis)驱动DelayedFunctionScheduler前进并同步推进 mock 日期。配套修复还包括Clock ticking 默认改为 0PR #340、Mock clock 更少侵入——仅在安装时替换全局计时函数以及Clock 支持将eval的字符串作为函数调度等。典型用法jasmine.clock().install(); jasmine.clock().mockDate(new Date(2020, 0, 1)); // ... 触发 setTimeout 逻辑 jasmine.clock().tick(1000); jasmine.clock().uninstall();2.8 内部变量闭包化更干净的全局接口2.0 将一批内部函数如获取下一个 spec id移入闭包使jasmine命名空间只暴露真正的公共 API。这一治理思路在当前源码中体现为 src/core/requireCore.js 中private$与j$的双层隔离所有实现细节存于private$闭包对象对外只开放jasminej$接口并利用Object.defineProperty将公共成员设为不可写、不可配置防止误改requireCore.js。三、其他重要变更3.1 大规模重构与更好的测试发布说明将大规模重构列为最大的一组变更几乎每个文件、每个对象都被触及对象被合并或拆分代码风格统一几乎所有测试被重写。其结果是Jasmine 由更小、更松耦合、通过显式依赖注入进行单元测试的对象组成。这一架构特征在 src/core/requireCore.js 的装配清单中体现得淋漓尽致——Env、QueueRunner、Suite、Spec、Spy、CallTracker、ReportDispatcher、TreeProcessor等均通过工厂函数注入依赖组合而成也直接服务于 2.0 以来的可扩展性社区更容易提交合理的一轮通过的 Pull Request。3.2 环境初始化移至boot.jsJasmine 环境的实例化与装配——包括构建 Reporter、暴露全局函数、执行测试——被集中到独立的boot.js文件目的有二一是让自定义 Reporter 的接入、对象配置、外部使用方式的定制变得更简单二是支持自加载两次的开发模式devboot.js分别从打包的jasmine.js与源码目录各加载一次用于自测。当前仓库的浏览器端入口 src/boot/boot.js 仍保持这一职责划分在window.onload中读取 URL 查询参数配置环境env.configure(urls.configFromCurrentUrl())创建HtmlReporterV2并通过env.addReporter()注册最后调用env.execute()。也就是说从 2.0 起谁搭环境、谁报结果、谁执行被明确分离用户可以在execute()之前自由插入自己的 Reporter。3.3 开发与构建迁移到 GruntNode.js 工具链2.0 将命令行开发任务从 Ruby 迁移到 Node.js Grunt.js。官方给出的理由很直白JavaScript 工具擅长构建 JavaScript 项目团队维护成本更低社区也能在提交 PR 前先在浏览器和 Node 中验证贡献。构建相关脚本在当前仓库中仍有传承见 scripts/buildDistribution.js、scripts/buildStandaloneDist.js 与 scripts/lib/buildDistribution.js只是具体任务编排已随时代演进而变化。3.4 自定义 require 方案浏览器与 Node 统一加载为了不引入新的运行时依赖又保持加载的干净2.0 编写了一套同时工作在 Node.js 与浏览器中的自定义 require 方案。其当前形态集中在 src/core/requireCore.js 与 src/core/requireSuffix.jsgetJasmineRequireObj根据环境选择exportsNode或普通对象浏览器core()完成全部内部模块装配返回{ jasmine: j$, private: private$ }bootJasmine()在 Node 下module.exports bootJasmine(...)在浏览器下直接bootJasmine().installGlobals()把describe、it、expect等挂到全局。发布说明特别提醒这套方案只影响新增文件的 Pull Request新增源文件时必须挂到 require 链路上否则无法被加载。3.5 用 Jasmine 测试 Jasminejasmine与j$的双轨约定自定义 require 系统强化了自举测试打包后的jasmine.js用来测试源码目录中的 Jasmine 自身。在 Jasmine 的测试代码里会出现两个标识符jasmine永远指源码版本的 Jasminej$指被加载到引用中的 Jasmine 实现。官方要求所有贡献者遵守该约定。当前仓库 spec/helpers/defineJasmineUnderTest.js 及其 Node 版本 spec/helpers/nodeDefineJasmineUnderTest.js 正是这一自测机制的载体用于把待测的 Jasmine源码版暴露为jasmineUnderTest供规格引用。3.6 Node.js 成为一等公民2.0 将 Node.js 正式纳入官方 CI 构建矩阵Travis。当时的node_suite.js本质上是面向 Node 的 boot.js官方 npm 包随后发布。当前仓库中Node 侧运行规格的脚本已演进为 scripts/runSpecsInNode.js并支持并行执行scripts/runSpecsInParallel.js而 src/core/requireSuffix.js 的 Node 分支module.exports正是Node 上一等公民加载方式的直接证据。3.7 CI 矩阵、支持矩阵与工程治理Travis CI 矩阵2.0 的 CI 在浏览器矩阵中运行核心规格覆盖 Firefox、Chrome、Safari 5/6、PhantomJS、Node.js 以及 IE 8/9/10OS 矩阵尚不完整并接受社区补充 OS/浏览器组合的 PR。当前仓库的 Sauce 支持脚本scripts/run-sauce-browsers、scripts/start-sauce-connect可视为这一浏览器矩阵测试策略的延续。支持矩阵更新2.0 起放弃 IE 8 以下版本IE 8需要兼容老浏览器的项目可继续使用 Jasmine 1.x。移除 JsDoc 页面官方理由是代码中的注释是等待发生的谎言——过时的 JsDoc 注释与更过时的生成页面毫无帮助因此全部移除转而维护面向真实使用接口的introduction.js页面。引入 Code Climate用于快速定位 JavaScript 代码热点code hotspots属于当时的工程质量度量工具。四、2.0 合并的 Pull Requests 与 Bug 修复亮点发布说明末尾列出了 2.0 周期内合并的 PR 与修复按主题归纳如下与上文各节对应功能与接口类jasmine.Any支持Boolean#392Reporters 可获得执行时间#30toThrow匹配器正确处理 falsy 异常#317Clock 默认 tick 改为 0#340Env.execute允许接收可选的 spec/suite id 列表与当前 src/core/Env.js 中execute(runablesToRun)的参数形态一致Spy 策略属性更名为returnValue/throwError见 2.2 节。质量与行为修复白空格失败信息更易读#332、UTF-8 编码修复#333getGlobal()在严格模式下可用异步规格抛出异常时也能清除超时定时器延迟函数内调度的超时被正确调度与执行移除jasmine.Matchers.pp弃用 API#363消除j$的意外全局污染、修复timer全局泄漏beforeEach/it/afterEach之间保持一致的this没有 expectation 的规格被视为通过异步回调未在默认时间间隔内调用时错误信息更友好所有异步函数均受超时约束自定义 matcher 可传negativeCompare以支持.not的定制实现HTML 输出性能优化CSS 改动#428、HTML 标题可复制、规格全名不加多余句点、favicon 换用更高分辨率。HTML/加载类小改进HTML Reporter 为简洁与性能重构HTML runner 页默认 UTF-8 编码对spec参数中的正则特殊字符做转义favicon 回归失败时总有堆栈移除未使用的jasmine.VERBOSE与jasmine.XmlHttpRequest引用。五、从 1.x 迁移到 2.0 的要点清单综合发布说明从 1.x 升级到 2.0 时最需要关注的迁移点如下异步规格弃用waitsFor/runs风格改用beforeEach/it/afterEach的done回调或返回 Promise 的写法Spy将spyOn(...).andReturn(x)之类的旧链式写法改为spyOn(...).and.returnValue(x)注意and.returnValue与and.throwError的命名变更Reporter按jasmineStarted / jasmineDone / suiteStarted / suiteDone / specStarted / specDone六事件重写自定义 Reporter并可通过timer对象获取执行时间自定义 Matcher改用env.addMatchers()/env.addAsyncMatchers()注册匹配器通过返回{ pass, message }或使用negativeCompare实现.not语义异常断言区分toThrow抛出了什么值与toThrowError抛出何种 Error 类型 / 消息Clock显式调用jasmine.clock().uninstall()恢复全局计时函数否则 mock 时钟会跨规格保持生效环境初始化环境装配已移至boot.js自定义 Reporter 应在env.execute()前通过env.addReporter()接入加载方式新增文件需挂接到自定义 require 链路上测试 Jasmine 自身时遵循jasmine源码版与j$被测引用的双轨约定。六、结语Jasmine Core 2.0 的价值不在于堆砌新功能而在于把 1.x 时代积累的接口不一致性一次性清算异步模型收敛为done回调串行队列Spy 语法统一到and策略链Reporter 变成六个稳定事件相等性测试换上新引擎自定义 Matcher 与官方匹配器共用同一套机制。这些决策大多在当前仓库源码中依然可循——QueueRunner.js、Spy.js、reporterEvents.js、matchersUtil.js、boot.js 等文件共同构成了 2.0 留给后世的架构遗产也奠定了 Jasmine 之后十余年版本迭代的接口基石。对于需要阅读历史版本代码、维护老旧测试库或理解当前 Jasmine 接口演化的开发者这份 2.0 发布说明都是不可跳过的关键文献。赞分享测试质量保障【免费下载链接】jasmineSimple JavaScript testing framework for browsers and node.js项目地址https://gitcode.com/gh_mirrors/ja/jasmine点击查看免费下载相关推荐type-graphql 版本演进全景解析从 CHANGELOG 看 2.0 重构、破坏性变更与架构升级type graphql 版本演进全景解析从 CHANGELOG 看 2.0 重构、破坏性变更与架构升级 type graphql 是一个基于 TypeScr后端GraphQLAPI设计Litho 版本演进深度解析从 v0.23 到 v0.51 的关键变更、破坏性迁移与架构重构全指南Litho 版本演进深度解析从 v0.23 到 v0.51 的关键变更、破坏性迁移与架构重构全指南 导读本文以仓库根目录 CHANGELOG.md http移动开发UI组件Fabric.js 版本演进全解析从 1.0 到 7.4 的核心变更、破坏性更新与架构重构指南Fabric.js 版本演进全解析从 1.0 到 7.4 的核心变更、破坏性更新与架构重构指南 本篇技术指南以本仓库根目录 CHANGELOG.md http前端图形学上一篇MetaboAnalystR 实战从原始峰表到通路富集的 5 步工作流下一篇3 个步骤跑通 sndcpy让手机声音直接传到电脑播放创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表