第 10 章 测试

以单元测试、工程自动化、基准、压力和业务数据转换建立正确性与性能回归证据。

直觉起点

、、、、共同构成本页的观察坐标。测试分离功能契约与性能预算:单元测试控制依赖和异步完成,基准测试隔离微小成本,压力测试在真实并发下观察吞吐、尾延迟和错误。 深入理解 Node 不是背诵 API,而是回答 JavaScript 与系统之间如何传递数据、谁拥有异步资源、错误沿哪条边传播、何时能安全退出。

六阶段执行链

1. 定义可观察契约

固定 Node 版本、依赖锁、入口参数、环境变量和输入,先预测同步栈、异步资源与最终输出。没有版本证据,就无法区分原书历史行为和现代运行时。

2. 隔离外部依赖

明确数据是模块标识、字节、事件、请求、消息还是制品,并标出创建资源与接收完成通知的所有者。资源创建必须同时设计错误、超时和关闭。

3. 控制异步完成

把正常路径压缩为最小可运行样本,只保留一个完成出口。回调、Promise、事件和进程消息不能为同一操作重复签发结果。

4. 建立性能基线

注入一个边界:空输入、分块、慢消费者、权限、断线、Worker 退出、依赖升级或部署失败。停止在首个偏离点并保存状态。

5. 施加真实压力

检查 2013 年接口在当前 Node 的状态:仍支持、语义变化、弃用或移出生态。现代替代保持原问题身份,同时明确迁移不能自动保证的行为。

6. 保存回归证据

删除故障并重放同一输入,等待文件、套接字、队列、Worker、日志和连接排空。输出、退出码与资源计数共同收敛才算恢复。

核心机制深挖

测试分离功能契约与性能预算:单元测试控制依赖和异步完成,基准测试隔离微小成本,压力测试在真实并发下观察吞吐、尾延迟和错误。 所有案例统一记录六类证据:输入表示、模块或协议边界、调度阶段、资源所有者、错误出口、关闭条件。表示错误会造成编码或分帧歧义;调度理解错误会把同步事件误认为异步回调;所有权不清会留下描述符、Worker 与连接;关闭条件缺失会让进程悬挂或强行丢数据。

本页签发不变量是:测试失败可重复,异步测试只完成一次,基准包含预热和统计,压力结果同时报告吞吐、分位延迟、错误率和资源上限。。代码必须回答正常路径完成什么、边界输入限制在哪里、失败由谁观察、取消怎样传播、关闭等待哪些资源,以及 2013 年接口在当前 Node 中是否仍适合新项目。成功输出不能独自证明这些条件。

2013 版与现代 Node 的版本账本

原书出版于 2013 年,覆盖早期 CommonJS、V8 分代回收、process.nextTick、setImmediate、node-heapdump、node-memwatch、旧 Buffer 构造器、cluster、node-inspector、AMD/CMD 和 CouchDB npm 仓库。重构保留 11 章 4 附录的知识身份,但现代示例采用安全且受支持的入口,并明确 node:* 模块、Promise/async、Buffer.alloc、N-API、Inspector、node:test、锁文件和当前供应链机制的对照关系。

版本账本至少包含原书接口、当时用途、当前支持状态、替代入口、行为差异和移除兼容层的条件。事件循环、TCP 无消息边界、字节编码、资源所有权等稳定原理不会因版本改变;模块解析细节、V8 回收器、默认超时、cluster 调度和包仓库实现必须按当前版本重新验证。

完整公开目录逐项讲解

第10章 测试

第10章 测试 要放回“定义可观察契约、隔离外部依赖、控制异步完成、建立性能基线、施加真实压力、保存回归证据”的完整运行链,先说明输入、资源、同步或异步边界,再说明错误与结束条件。

实验从“定义可观察契约”开始:固定 Node 版本、入口、依赖锁、输入和资源上限,先预测执行顺序,再只改变一个边界条件。记录首个偏离点,恢复后重放同一输入并等待文件、套接字、Worker、日志和队列排空。

10.1 单元测试

异步单元测试必须返回 Promise 或明确完成信号,测试替身只隔离边界。基准要预热并多轮统计,压力测试报告吞吐、分位延迟、错误率与资源,而非只给平均值。

实验从“隔离外部依赖”开始:固定 Node 版本、入口、依赖锁、输入和资源上限,先预测执行顺序,再只改变一个边界条件。记录首个偏离点,恢复后重放同一输入并等待文件、套接字、Worker、日志和队列排空。

10.1.1 单元测试的意义

异步单元测试必须返回 Promise 或明确完成信号,测试替身只隔离边界。基准要预热并多轮统计,压力测试报告吞吐、分位延迟、错误率与资源,而非只给平均值。

实验从“控制异步完成”开始:固定 Node 版本、入口、依赖锁、输入和资源上限,先预测执行顺序,再只改变一个边界条件。记录首个偏离点,恢复后重放同一输入并等待文件、套接字、Worker、日志和队列排空。

10.1.2 单元测试介绍

异步单元测试必须返回 Promise 或明确完成信号,测试替身只隔离边界。基准要预热并多轮统计,压力测试报告吞吐、分位延迟、错误率与资源,而非只给平均值。

实验从“建立性能基线”开始:固定 Node 版本、入口、依赖锁、输入和资源上限,先预测执行顺序,再只改变一个边界条件。记录首个偏离点,恢复后重放同一输入并等待文件、套接字、Worker、日志和队列排空。

10.1.3 工程化与自动化

异步单元测试必须返回 Promise 或明确完成信号,测试替身只隔离边界。基准要预热并多轮统计,压力测试报告吞吐、分位延迟、错误率与资源,而非只给平均值。

实验从“施加真实压力”开始:固定 Node 版本、入口、依赖锁、输入和资源上限,先预测执行顺序,再只改变一个边界条件。记录首个偏离点,恢复后重放同一输入并等待文件、套接字、Worker、日志和队列排空。

10.1.4 小结

10.1.4 小结 要放回“定义可观察契约、隔离外部依赖、控制异步完成、建立性能基线、施加真实压力、保存回归证据”的完整运行链,先说明输入、资源、同步或异步边界,再说明错误与结束条件。

实验从“保存回归证据”开始:固定 Node 版本、入口、依赖锁、输入和资源上限,先预测执行顺序,再只改变一个边界条件。记录首个偏离点,恢复后重放同一输入并等待文件、套接字、Worker、日志和队列排空。

10.2 性能测试

产品化证据包括可追溯制品、配置边界、滚动部署、回滚、结构化日志、指标和报警演练。优化必须保持正确性,异构服务通过版本化协议而非隐式共享状态协作。

实验从“定义可观察契约”开始:固定 Node 版本、入口、依赖锁、输入和资源上限,先预测执行顺序,再只改变一个边界条件。记录首个偏离点,恢复后重放同一输入并等待文件、套接字、Worker、日志和队列排空。

10.2.1 基准测试

异步单元测试必须返回 Promise 或明确完成信号,测试替身只隔离边界。基准要预热并多轮统计,压力测试报告吞吐、分位延迟、错误率与资源,而非只给平均值。

实验从“隔离外部依赖”开始:固定 Node 版本、入口、依赖锁、输入和资源上限,先预测执行顺序,再只改变一个边界条件。记录首个偏离点,恢复后重放同一输入并等待文件、套接字、Worker、日志和队列排空。

10.2.2 压力测试

异步单元测试必须返回 Promise 或明确完成信号,测试替身只隔离边界。基准要预热并多轮统计,压力测试报告吞吐、分位延迟、错误率与资源,而非只给平均值。

实验从“控制异步完成”开始:固定 Node 版本、入口、依赖锁、输入和资源上限,先预测执行顺序,再只改变一个边界条件。记录首个偏离点,恢复后重放同一输入并等待文件、套接字、Worker、日志和队列排空。

10.2.3 基准测试驱动开发

异步单元测试必须返回 Promise 或明确完成信号,测试替身只隔离边界。基准要预热并多轮统计,压力测试报告吞吐、分位延迟、错误率与资源,而非只给平均值。

实验从“建立性能基线”开始:固定 Node 版本、入口、依赖锁、输入和资源上限,先预测执行顺序,再只改变一个边界条件。记录首个偏离点,恢复后重放同一输入并等待文件、套接字、Worker、日志和队列排空。

10.2.4 测试数据与业务数据的转换

异步单元测试必须返回 Promise 或明确完成信号,测试替身只隔离边界。基准要预热并多轮统计,压力测试报告吞吐、分位延迟、错误率与资源,而非只给平均值。

实验从“施加真实压力”开始:固定 Node 版本、入口、依赖锁、输入和资源上限,先预测执行顺序,再只改变一个边界条件。记录首个偏离点,恢复后重放同一输入并等待文件、套接字、Worker、日志和队列排空。

10.3 总结

10.3 总结 要放回“定义可观察契约、隔离外部依赖、控制异步完成、建立性能基线、施加真实压力、保存回归证据”的完整运行链,先说明输入、资源、同步或异步边界,再说明错误与结束条件。

实验从“保存回归证据”开始:固定 Node 版本、入口、依赖锁、输入和资源上限,先预测执行顺序,再只改变一个边界条件。记录首个偏离点,恢复后重放同一输入并等待文件、套接字、Worker、日志和队列排空。

10.4 参考资源

10.4 参考资源 要放回“定义可观察契约、隔离外部依赖、控制异步完成、建立性能基线、施加真实压力、保存回归证据”的完整运行链,先说明输入、资源、同步或异步边界,再说明错误与结束条件。

实验从“定义可观察契约”开始:固定 Node 版本、入口、依赖锁、输入和资源上限,先预测执行顺序,再只改变一个边界条件。记录首个偏离点,恢复后重放同一输入并等待文件、套接字、Worker、日志和队列排空。

资源与失败矩阵

资源正常完成常见边界失败出口关闭证据
模块与包导出一次、依赖锁定循环依赖、平台差异解析或 ABI 错误模块图可追溯
Buffer 与流编码完整、背压生效截断、跨字符、慢目标pipeline 拒绝描述符关闭
套接字与请求响应一次半包、断线、超时error 或 abortclose 已观察
Worker 与制品退出、接管或回滚崩溃、重启风暴非零码与报警在途请求排空

最小可运行实验

import assert from "node:assert/strict";
import test from "node:test";
 
test("async operation rejects once", async () => {
  await assert.rejects(() => Promise.reject(new Error("expected")), {
    message: "expected",
  });
});
book: 深入浅出 Node.js
edition: 2013-12
page: dnj-10-testing
sample: normal | boundary | failure | recovery
module_graph_fixed: true
resource_owner_known: true
single_completion: true
close_observed: true
freeze node version + dependency lock + input
predict sync stack + async resources + byte boundaries
change exactly one boundary condition
stop at the first divergent state
remove fault and replay the same sample
wait for files, sockets, workers, and logs to close

常见误区与故障注入

四类样本与验收

样本注入方式必查证据通过条件
正常小输入、依赖健康字节、事件、响应、提交只完成一次
边界空、长、分块、慢、并发上限、背压、顺序内存与延迟受控
失败权限、断线、Worker退出、部署失败首个错误与所有者错误不丢不重复
恢复删除故障后同样本重放close、exit、连接数、回滚无悬挂资源

目录证据:第10章 测试、10.1 单元测试、10.1.1 单元测试的意义、10.1.2 单元测试介绍、10.1.3 工程化与自动化、10.1.4 小结、10.2 性能测试、10.2.1 基准测试、10.2.2 压力测试、10.2.3 基准测试驱动开发、10.2.4 测试数据与业务数据的转换、10.3 总结、10.4 参考资源。本页按完整公开目录独立教学重构,不复制原书正文;13 个条目全部进入输入、机制、失败、版本和关闭证据链。

练习

小结

  • 单元测试:对应“定义可观察契约”的核心观察量。
  • 测试替身:对应“隔离外部依赖”的核心观察量。
  • 基准测试:对应“控制异步完成”的核心观察量。
  • 压力测试:对应“建立性能基线”的核心观察量。
  • 性能预算:对应“施加真实压力”的核心观察量。
  • 13 个本页公开目录条目已全部映射到执行链与版本账本。
  • 先预测再运行;最终输出、错误传播和资源关闭共同决定是否通过。

术语表

讨论

评论区加载中…