JavaScript数组排序函数单元测试需覆盖正确性、边界情况、副作用控制三维度:验证排序结果、确保不修改原数组、测试自定义比较函数及null/undefined/NaN等异常输入。

对 JavaScript 数组排序函数写单元测试,核心是覆盖 正确性、边界情况、副作用控制 三个维度。排序函数看似简单,但容易忽略原数组是否被修改、比较逻辑是否稳定、特殊值(null、undefined、NaN)如何处理等问题。
验证排序结果是否符合预期
这是最基础也最关键的测试点。用已知输入和明确期望输出做断言,避免依赖随机或模糊判断。
- 对数字数组,测试升序、降序、含重复值、单元素、空数组等场景
- 对字符串数组,注意大小写敏感性(如
'apple'和'Banana'的默认排序顺序) - 使用
toEqual(Jest)或deepEqual(Node.js assert)比对整个数组,不要只检查首尾元素
示例(Jest):
test('sorts numbers in ascending order', () => {
expect(sortNumbers([3, 1, 4, 1, 5])).toEqual([1, 1, 3, 4, 5]);
});
检查是否修改了原始数组(纯函数性)
很多开发者误用 Array.prototype.sort() 直接修改原数组。若你的函数承诺“不改变输入”,就必须验证这一点。
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 先保存原数组的浅拷贝(
JSON.parse(JSON.stringify(arr))或[...arr]),再调用被测函数 - 断言原数组未变,返回值是新数组且已排序
- 特别注意对象数组:比较的是引用,需用深比较或只比关键字段
示例:
test('does not mutate original array', () => {
const original = [3, 1, 2];
const result = sortNumbers(original);
expect(result).toEqual([1, 2, 3]);
expect(original).toEqual([3, 1, 2]); // 原数组不变
});
测试自定义比较函数的逻辑分支
如果排序支持传入 compareFn(如按对象某个字段排序),要单独覆盖 compareFn 的各种返回值路径。
- 模拟 compareFn 返回负数、0、正数三种情况,确认排序行为符合规范(a < b → -1,a === b → 0,a > b → 1)
- 测试对象数组:按字符串字段(注意空值)、数字字段(注意 NaN)、布尔字段排序
- 故意传入
undefined或非函数值,验证是否抛出合理错误
示例:
test('sorts objects by name field, case-insensitive', () => {
const users = [{name: 'Zoe'}, {name: 'alice'}, {name: 'Bob'}];
expect(sortBy(users, item => item.name.toLowerCase())).toEqual([
{name: 'alice'}, {name: 'Bob'}, {name: 'Zoe'}
]);
});
覆盖边界与异常输入
真实环境里,数据往往不“干净”。这些测试能提前暴露隐式假设。
- 空数组
[]、单元素数组[42]、全相同元素[5,5,5] - 含
null、undefined、NaN、Infinity的数组(注意NaN !== NaN) - 混合类型数组(如
[1, '2', true]),明确文档是否支持,测试实际行为是否一致 - 超大数组(如 10000+ 元素)可选做性能快照,但非必测项
示例:
test('handles array with null and undefined', () => {
expect(sortMixed([null, 2, undefined, 1])).toEqual([1, 2, null, undefined]);
// 根据 JS 规范,null > undefined,所以排在后面
});

















