单元测试中如何使两个NaN判定为相等?
解决单元测试中NaN相等判定的问题
针对你用Map批量测试时遇到的NaN不相等问题,这里提供几种无需单独判断NaN的全局解决方案:
1. 自定义通用深度相等断言函数
写一个递归处理的比较函数,自动识别并判定两个NaN为相等,同时支持Map、对象、数组等嵌套结构的批量比较:
function deepEqualWithNaN(a, b) { // 优先处理NaN场景:两者均为NaN则判定相等 if (Number.isNaN(a) && Number.isNaN(b)) { return true; } // 处理Map类型的键值对遍历比较 if (a instanceof Map && b instanceof Map) { if (a.size !== b.size) return false; for (const [key, val] of a) { if (!b.has(key) || !deepEqualWithNaN(val, b.get(key))) { return false; } } return true; } // 处理普通对象/数组的递归比较 if (typeof a === 'object' && a !== null && typeof b === 'object' && b !== null) { const keysA = Object.keys(a); const keysB = Object.keys(b); if (keysA.length !== keysB.length) return false; for (const key of keysA) { if (!keysB.includes(key) || !deepEqualWithNaN(a[key], b[key])) { return false; } } return true; } // 基本类型直接比较 return a === b; } // 封装成断言函数,替换原有expect调用 function expectEqualWithNaN(result, expected) { const isEqual = deepEqualWithNaN(result, expected); if (!isEqual) { throw new Error(`Expected: <${expected}> Actual: <${result}>`); } }
使用时直接调用expectEqualWithNaN(result, expected)即可,批量测试Map时无需单独处理NaN,函数会自动遍历所有键值对完成比较。
2. 扩展现有测试库的匹配器(以Jest为例)
如果使用Jest等支持扩展的测试框架,可以自定义全局匹配器,让现有断言语法支持NaN相等判定:
expect.extend({ toBeEqualWithNaN(received, expected) { const pass = deepEqualWithNaN(received, expected); return { message: () => pass ? `Expected: <${expected}> not to equal Actual: <${received}>` : `Expected: <${expected}> Actual: <${received}>`, pass }; } }); // 测试中直接使用 expect(result).toBeEqualWithNaN(expected);
这种方式可以保留原有测试库的语法风格,全局生效后所有批量测试场景都能自动处理NaN。
3. 轻量方案:利用JSON序列化处理
如果你的测试数据没有复杂嵌套类型(如Date、正则),可以通过序列化替换NaN为标记值来实现比较:
function equalWithNaN(a, b) { // 将NaN替换为统一标记,Map转为可序列化的数组 const normalize = (val) => { if (val instanceof Map) return Array.from(val.entries()).map(([k, v]) => [k, normalize(v)]); if (typeof val === 'object' && val !== null) { const obj = {}; for (const key in val) obj[key] = normalize(val[key]); return obj; } return Number.isNaN(val) ? '[NaN_MARKER]' : val; }; return JSON.stringify(normalize(a)) === JSON.stringify(normalize(b)); }
该方案实现简单,但对特殊类型的兼容性较差,适合结构简单的测试数据。
内容的提问来源于stack exchange,提问作者Almis
相关产品推荐
相关产品推荐

