首页 / 资讯中心 / 文章详情

Tone.js 测试指南:用 gulp 驱动 Mocha 浏览器测试并按类收集用例(chrome-music-lab)

Tone.js 测试指南:用 gulp 驱动 Mocha 浏览器测试并按类收集用例(chrome-music-lab) ★ FEATURED ARTICLE
【免费下载链接】chrome-music-labA collection of experiments for exploring how music works, all built with the Web Audio API.项目地址https://gitcode.com/gh_mirrors/ch/chrome-music-lab点击查看免费下载本篇技术指南以 pianoroll/third_party/Tone.js/test/README.md 为骨架系统讲解 Tone.js0.6.1Web Audio 交互音乐框架在浏览器端测试体系的完整工作流如何从 gulp 目录启动测试服务器运行全部用例、如何通过gulp collectTests按单个类或按目录分组收集测试以及浏览器兼容性预期与运行环境注意事项。结合 chrome-music-lab 仓库中 pianoroll 实验项目实际使用的 Tone.js 源码与测试用例读者可以掌握一套可复用的类级 分组级音频库测试方法论。一、Tone.js 测试体系的整体面貌Tone.js 是构建在 Web Audio API 之上的交互音乐框架其测试同样运行在浏览器环境中以 Mocha 作为测试框架、Chai 提供断言、RequireJSAMD负责模块加载。测试入口的依赖装配可以从 test/index.html 中看到script src./deps/mocha.js/script script src./deps/chai.js/script script>gulp test执行前提是命令必须在gulp文件夹内部运行原文from within the gulp folder即先进入 gulp 任务目录再执行。这条命令会完成两件事启动一个本地 HTTP 服务器然后在该服务器环境下运行全部测试用例。这与 Tone.js 的 package.json 中登记的 npm 脚本保持一致scripts: { test: cd gulp gulp test }也就是说也可以从项目根目录直接运行npm test其内部等价于先cd gulp再执行gulp test。之所以必须借助服务器而非直接双击 HTML 文件是因为测试页面通过 RequireJS 异步加载../Tone源码与helper/Test等模块——这类 AMD 模块加载在file://协议下会被浏览器跨域策略拦截必须经由 HTTP 服务提供。说明当前 chrome-music-lab 仓库快照仅保留了 Tone.js 的Tone/源码、test/与examples/等目录未包含 gulp 构建任务目录本身若需在本地跑通gulp test需要从 Tone.js 上游完整版本获取 gulp 任务。除此之外也可以直接通过 HTTP 服务托管 test/index.html例如python3 -m http.server于test/上层目录再由浏览器打开页面手动执行。gulp test最终走向的测试入口是 test/Main.jsrequire.config({ baseUrl:./, paths : { Tone : ../Tone, Test : helper/Test }, }); window.MANUAL_TEST false; require([Test,source/ExternalInput], function(Test){ Test.run(); });其中paths把Tone映射到../Tone即 Tone 源码目录把Test映射到helper/Test即 helper/Test.jsTest.run()内部直接调用mocha.run()启动测试执行。可以看到Main.js中实际加载的测试模块列表此处是source/ExternalInput正是由 collectTests 任务动态生成的见下一节。三、按类运行单个测试gulp collectTests -f当只需要验证某一个类时不必跑全量用例。测试 README 给出的做法是gulp collectTests -f [Tone class name]其中-f后跟Tone 类名例如Signal、Oscillator。该命令的行为是更新test/Main.js把给定类的测试文件写进入口随后再配合gulp test运行。换句话说collectTests负责选定测试集gulp test负责启动并执行。这一机制与 CHANGELOG 中测试被重构为独立文件的变更直接呼应每个类都有对应的独立测试文件例如 test/signal/Signal.js 测试Signal类、test/source/Oscillator.js 测试Oscillator类、test/core/Tone.js 测试核心类与 AudioContext。因此只要把目标文件挂载进Main.js的require([...])列表mocha.run()就会只执行这部分用例实现单个类级的快速回归。四、按目录分组收集测试--signal等 flag除了单个类还可以按目录整组收集。README 给出的示例是gulp collectTests --signal这会收集 test/signal 目录下的全部信号类测试该目录下包含 Signal、Add、Multiply、Subtract、Scale 等 32 个类级测试文件。README 同时提供了完整的 flag 速查表短 flag长 flag对应测试目录-s--signaltest/signal-i--instrumenttest/instrument-o--sourcetest/source-v--eventtest/event-e--effecttest/effect-c--coretest/core-m--componenttest/component-t--controltest/control两种写法完全等价例如# 以下两条命令等价均收集全部信号类测试 gulp collectTests --signal gulp collectTests -s将单个类-f与整组目录分组 flag结合使用就形成了灵活的分层测试策略日常开发某个模块时跑单类用例模块改动涉及信号链路时跑-s信号组发版前再跑gulp test全量回归。五、浏览器兼容性预期测试 README 对兼容性给出了明确的预期Chrome 是目标测试平台100% 的用例应当通过Safari 上通过的用例较少Firefox 上更少长期目标是所有浏览器 100% 通过但由于Web Audio 规范与浏览器实现都还相对较新仍存在少量待处理的差异。这段话对应的背景是Tone.js 大量依赖 Web Audio API 的原生节点GainNode、WaveShaperNode 等与较新的规范能力如OfflineAudioContext、AudioParam 自动化调度。不同浏览器对这些规范的实现成熟度不一致因此测试通过率会随平台浮动。这一点同样可以从测试代码中得到印证例如 test/core/Tone.js 中专门有一组用例断言Tone.context是AudioContext实例、Tone.context.createOscillator等 shim 后的 API 存在has shimmed API说明 Tone.js 需要通过 shim 弥合浏览器差异而这些 shim 行为本身就是被测试覆盖的对象。六、运行测试的环境注意事项README 最后强调了一条容易被忽略的运行时约束测试运行期间必须保证浏览器窗口处于焦点状态。原因是 Tone.js 的时钟与定时基于requestAnimationFrame实现——当标签页失去焦点时浏览器会把 rAF 回调降级为低优先级甚至完全不触发导致基于时间推进的用例如开始后 100ms 应处于 started 状态超时或失败。这与 CHANGELOG.md 中Clock uses requestAnimationFrame instead of ScriptProcessorNode的变更记录一致Tone.js 特意用 rAF 替代了 ScriptProcessorNode 来驱动时钟以降低延迟与开销但代价就是定时精度依赖标签页的可见性。因此无论是跑gulp test全量还是单类用例都要保持测试标签页在前台避免在跑测试的同时切换到其他标签页工作。七、测试基建源码剖析helper 工具如何支撑音频测试浏览器端的音频测试有一个天然难点无法像纯逻辑测试那样仅靠断言返回值必须验证真的发出了声音时序是否正确。Tone.js 通过 test/helper 下的一组辅助模块解决了这个问题这也是理解整套测试体系的关键。1. Test.js全局测试环境装配helper/Test.js 承担三件事为 Chai 扩展自定义断言percentageFrom允许按百分比容差比较适配音频信号的精度需求设置window.expect chai.expect与mocha.setup(bdd)统一使用 BDD 风格的describe/it/expect语法提供Test.run()内部mocha.run()、Test.connect(node)把被测节点接到一个公共 GainNode 输入上再断开用于连通性验证以及Test.wasDisposed(obj)递归检查对象所有非函数/非基本类型属性是否被置为null用于验证dispose()是否真正释放了资源。2. Basic.js每个类的公共冒烟测试helper/Basic.js 导出一个工厂函数Basic(Constr, args)任何类的测试文件开头都会调用它自动获得两条公共用例can be created and disposed实例化 →dispose()→Test.wasDisposed(instance)确认无资源泄漏extends Tone断言实例是Tone基类的实例。例如 test/signal/Signal.js 第一行就是Basic(Signal)test/source/Oscillator.js 同样BasicTests(Oscillator)。这保证了每个类无论功能多复杂都至少具备最基本的生命周期正确性。3. Offline.js 与 Meter.js离线渲染验证音频行为helper/Offline.js 基于OfflineAudioContext实现离线渲染测试以 44100Hz 采样率渲染一段指定时长默认 0.7 秒的音频渲染完成后在oncomplete回调中逐采样把渲染结果交给this._test(sample, time)断言。测试过程中通过Tone.setContext(...)临时把 Tone.js 的全局上下文切到离线上下文结束后再切回在线上下文互不干扰。它提供的链式 API 是new Offline(duration, channels) .before(function(dest){ /* 在此连接被测节点 */ }) .test(function(sample, time){ /* 逐采样断言 */ }) .after(function(){ /* 清理与结束 */ }) .run();helper/Meter.js 是 Offline 的变体专门做 RMS 电平测量以 256 帧为窗口滑动计算均方根值用于验证声音在某个时间点之后才出现停止后输出归零这类时序断言。4. OutputAudio.js静音检测helper/OutputAudio.js 封装了最常见的是否发声测试渲染 0.5 秒音频只要任何一个采样绝对值大于 0.01 即认为节点输出了声音否则在after回调中抛出node outputs silence错误。5. SourceTests.js音源的公共行为契约helper/SourceTests.js 为所有Tone.Source音源定义了公共契约例如实例必须继承Tone.Source初始state为stoppedstart().stop(0.2)后状态依次变为started再回到stopped必须发出声音且双声道均有输出可以被调度到未来开始/停止通过 Meter 验证time 0.1后才出现非零采样。6. 实测用例示例Signal 与 Oscillator以 test/signal/Signal.js 为例可以看到离线渲染在调度测试中的典型用法it (can be scheduled to set a value in the future, function(done){ var sig; var offline new Offline(); offline.before(function(dest){ sig new Signal(0).connect(dest); sig.setValueAtTime(2, 0.2); }); offline.test(function(sample, time){ if (time 0.2){ expect(sample).to.be.closeTo(0, 0.001); } else if (time 0.21){ expect(sample).to.be.closeTo(2, 0.001); } }); offline.after(function(){ sig.dispose(); done(); }); offline.run(); });这条用例验证了Signal.setValueAtTime(2, 0.2)在 0.2 秒后确实把信号值从 0 跳到 2。同文件还覆盖了linearRampToValueAtTime线性斜坡、exponentialRampToValueAtTime指数斜坡、setTargetAtTime逼近目标值、setRampPoint以及多条自动化叠加等调度能力。test/source/Oscillator.js 则展示了更音频化的验证通过 Offline 渲染 1Hz 振荡器并逐采样检查波形相位验证phase: 90时前 0.25 秒输出在 [-1, 0] 区间、后 0.25 秒在 [0, 1] 区间90 度相位偏移的正确表现phase: 270则相反。这类用例充分体现了离线渲染 逐采样断言对音频时序测试的价值。八、在 chrome-music-lab 项目中落地这套测试的价值本仓库的 pianoroll 实验钢琴卷帘等模块全部构建在 Tone.js 之上其工程配置也直接印证了测试体系的依赖关系在 webpack.config.js 中modulesDirectories明确加入了third_party/Tone.js/使应用代码能以模块名直接引用 Tone.js应用侧源码则通过 AMD 语法引入具体模块例如 app/sound/Synth.js 的依赖声明define([Tone/core/Tone, Tone/source/Oscillator, Tone/instrument/PolySynth, Tone/instrument/SimpleSynth], ...)又如 app/sound/Piano.js 引用Tone/core/Buffer、Tone/core/Transportapp/sound/Sampler.js 引用Tone/source/MultiPlayer。这意味着 Tone.js 的核心类Transport、Buffer、Signal、各音源与乐器直接决定实验应用的音序、采样与发声行为——test/core/Tone.js 中对 Transport 时钟与单位换算gainToDb/dbToGain的验证、test/signal 对信号调度的验证本质上就是在为这些上层应用提供回归保障。因此在实际开发中建议形成如下测试节奏修改或新增某个 Tone.js 相关模块后先用gulp collectTests -f ClassName收集对应类的用例并运行做最小范围回归涉及信号链或音源改动时用gulp collectTests -s或-o扩展到整组用例发布/合并前在 Chrome 前台标签页执行gulp test全量回归确认 100% 通过若在 Safari/Firefox 上出现用例失败先对照测试 README 的兼容性说明判断是否为已知的平台差异再决定是否需要在 shim 层修复。这套gulp 收集 Mocha 浏览器执行 离线渲染断言的测试工作流不仅适用于 Tone.js 本身对于任何依赖 Web Audio API 的交互音乐项目都是一份可直接借鉴的工程实践模板。赞分享【免费下载链接】chrome-music-labA collection of experiments for exploring how music works, all built with the Web Audio API.项目地址https://gitcode.com/gh_mirrors/ch/chrome-music-lab点击查看免费下载相关推荐chrome-music-lab 收录版 Tone.js 测试指南用 gulp、mocha 与离线渲染跑通 Web Audio 单元测试chrome music lab 收录版 Tone.js 测试指南用 gulp、mocha 与离线渲染跑通 Web Audio 单元测试 本文以 chromeTone.js 测试套件实战指南用 gulp 驱动 Mocha 跑通 Web Audio 框架的全部单元测试Tone.js 测试套件实战指南用 gulp 驱动 Mocha 跑通 Web Audio 框架的全部单元测试 导读 本文以 chrome music labchrome-music-lab 技术解析用 Web Audio、Tone.js 与 getUserMedia 构建浏览器音乐实验chrome music lab 技术解析用 Web Audio、Tone.js 与 getUserMedia 构建浏览器音乐实验 chrome music上一篇戴森球计划工厂蓝图库3000专业设计方案打造高效太空工厂下一篇如何高效配置Mobaxterm中文版3个核心技巧提升远程服务器管理效率创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?
咨询建站