Node.js API 之旅:Assert 模块揭秘
断言(Assertion)是编程中一种常见的技巧,用于在代码执行过程中检查某个条件是否满足预期。如果满足预期,那么代码将正常执行,不会有任何输出;如果不满足预期,则抛出一个异常,提示开发者存在问题。
Node.js 的 Assert
模块提供了一系列强大的断言函数,帮助我们确保代码的正确性和稳定性。在本文中,我们将深入探讨 Assert
模块的各个 API,详细解读其作用、传参并提供相关代码示例。
为了贴近最佳实践,本文将不会涉及以下 5 个已废弃或者已经有更佳替代方案的 API,
- assert.fail(actual, expected[, message[, operator[, stackStartFn]]]) - 已废弃
- assert.equal - 建议使用
assert.strictEqual
- assert.notEqual - 建议使用
assert.notStrictEqual
- assert.deepEqual - 建议使用
assert.deepStrictEqual
- assert.notDeepEqual - 建议使用
assert.notDeepStrictEqual
感兴趣的小伙伴可以到官网查阅相关文档。
初始说明
在 Assert
模块的方法中,几乎每个方法都带有一个可选的 message
参数。为避免重复,我们在此单独介绍该参数,后续内容将不再详述。message
参数可以是字符串或 Error
实例。
- 如果未定义
message
: 当不传递message
参数时,如果断言测试失败,将抛出一个具有默认错误消息的AssertionError
异常。
import assert from 'node:assert/strict'
assert.ok(false)
// AssertionError [ERR_ASSERTION]: false == true
assert.ok('')
// AssertionError [ERR_ASSERTION]: '' == true
- 传递字符串作为
message
: 当message
为字符串时,如果断言失败,将抛出一个具有该自定义错误消息的AssertionError
异常。
import assert from 'node:assert/strict'
assert.ok(false, '发生意外错误')
// AssertionError [ERR_ASSERTION]: 发生意外错误
- 传递
Error
实例作为message
: 当message
为Error
实例时,如果断言失败,将直接抛出该Error
实例,而不是创建一个新的AssertionError
异常。
import assert from 'node:assert/strict'
assert.ok(false, new Error('自定义错误实例'))
// Error: 自定义错误实例
1. assert.ok(value[, message])
该方法为 assert(value[, message])
的别名
方法作用
用于验证一个值是否为真值,即在逻辑上等于 true
,相当于 assert.equal(!!value, true, message)
。如果 value
为真值,那么测试将通过,否则抛出 AssertionError
异常。
参数说明
value
:any\color{green}{any}any 需要验证的值message
(可选):string∣Error\color{green}{string|Error}string∣Error 断言测试失败时抛出的自定义错误消息
代码示例
import assert from 'node:assert/strict'
assert.ok(2)
// 断言测试通过
assert.ok(null)
// AssertionError [ERR_ASSERTION]: null == true
assert.ok(0, '发生意外错误')
// AssertionError [ERR_ASSERTION]: 发生意外错误
assert.ok(undefined, new Error('自定义错误实例'))
// Error: 自定义错误实例
2. assert.fail([message])
方法作用
用于直接触发一个 AssertionError
错误,当需要在测试中明确表示一个失败时非常有用。
参数说明
message
(可选):string∣Error\color{green}{string|Error}string∣Error 断言测试失败时抛出的自定义错误消息,默认值为"Failed"
代码示例
import assert from 'node:assert/strict'
assert.fail()
// AssertionError [ERR_ASSERTION]: Failed
assert.fail('出错咯')
// AssertionError [ERR_ASSERTION]: 出错咯
assert.fail(new TypeError('必须为数组'))
// TypeError: 必须为数组
3. assert(value[, message])
它和 assert.ok(value[, message])
完全一致
4. assert.strictEqual(actual, expected[, message])
方法作用
用于验证两个值是否严格相等,这意味着它们的类型和内容都必须完全相同。
参数说明
actual
:any\color{green}{any}any 实际值,即要进行比较的第一个值expected
:any\color{green}{any}any 期望值,即要进行比较的第二个值message
(可选):string∣Error\color{green}{string|Error}string∣Error 断言测试失败时抛出的自定义错误消息
代码示例
import assert from 'node:assert/strict'
const obj1 = { a: 1 }
const obj2 = { a: '1' }
assert.strictEqual(obj1, obj2, 'obj1 和 obj2 没有严格相等')
// AssertionError [ERR_ASSERTION]: obj1 和 obj2 没有严格相等
5. assert.notStrictEqual(actual, expected[, message])
方法作用
用于验证两个值是否不严格相等。换句话说,如果两个值严格相等,将抛出 AssertionError
异常。
参数说明
actual
:any\color{green}{any}any 实际值,即要进行比较的第一个值expected
:any\color{green}{any}any 期望值,即要进行比较的第二个值message
(可选):string∣Error\color{green}{string|Error}string∣Error 断言测试失败时抛出的自定义错误消息
代码示例
import assert from 'node:assert/strict'
const first = 42
const second = 42
const third = '42'
assert.notStrictEqual(first, second, '因为 first 和 second 严格相等,抛出异常')
// AssertionError [ERR_ASSERTION]: 因为 first 和 second 严格相等,抛出异常
assert.notStrictEqual(first, third)
// 断言测试通过,因为 42 和 '42' 不严格相等
6. assert.deepStrictEqual(actual, expected[, message])
方法作用
用于深度比较两个值是否相等。深度比较意味着它会递归地比较对象的所有属性以及数组的所有元素,在比较过程中,它会考虑值的类型。
参数说明
actual
:any\color{green}{any}any 实际值,即要进行比较的第一个值expected
:any\color{green}{any}any 期望值,即要进行比较的第二个值message
(可选):string∣Error\color{green}{string|Error}string∣Error 断言测试失败时抛出的自定义错误消息
比较规则
- 基本类型:值和类型必须完全相等,使用
Object.is()
进行比较。例如,数字1
和字符串'1'
被认为是不相等的; - 对象:所有属性的键和值都必须深度相等,对象的原型也必须相同;
- 数组:数组的长度和每个元素都必须深度相等。例如,
[1, 2, 3]
和[1, 2, 3]
是相等的,而[1, 2, 3]
和[1, '2', 3]
是不相等的; - 函数:函数必须具有相同的源代码,即
toString()
返回的字符串表示。函数的原型也必须相同; - Map 和 Set:
Map
和Set
必须具有相同的键值对/元素,并以相同的顺序排列。例如,两个具有相同键值对的 Map 是相等的,而具有相同元素但顺序不同的 Set 是不相等的; - 其他原生类型(例如 RegExp、Date、Buffer、TypedArray 等):这些类型的实例必须具有相同的属性和值。例如,具有相同模式和标志的两个 RegExp 对象是相等的;
- 特殊值:
NaN
被认为是等于NaN
,即使它们在常规相等性比较中被认为是不相等的。+0
和-0
被认为是不相等的;
代码示例
import assert from 'node:assert'
assert.deepStrictEqual({ a: 1 }, { a: '1' }, `1 和 '1' 不严格相等`)
// AssertionError [ERR_ASSERTION]: 1 和 '1' 不严格相等
const date = new Date()
const object = {}
const fakeDate = {}
Object.setPrototypeOf(fakeDate, Date.prototype)
assert.deepStrictEqual(object, fakeDate, '它们的 [[Prototype]] 不同')
// AssertionError [ERR_ASSERTION]: 它们的 [[Prototype]] 不同
assert.deepStrictEqual(date, fakeDate)
// AssertionError [ERR_ASSERTION]: 它们的类型标签不同
// date 是 Date 类型,fakeDate 是 Object 类型
assert.deepStrictEqual(NaN, NaN)
// 断言测试成功:Object.is(NaN, NaN) 返回 true
assert.deepStrictEqual(new String('foo'), Object('foo'))
// 断言测试成功:在解包后,对象和字符串是相同的
assert.deepStrictEqual(-0, -0)
// 断言测试成功:Object.is(-0, -0) 返回 true
7. assert.notDeepStrictEqual(actual, expected[, message])
方法作用
用于验证两个值是否不深度严格相等。换句话说,如果两个值深度严格相等,将抛出 AssertionError
异常。
参数说明
actual
:any\color{green}{any}any 实际值,即要进行比较的第一个值expected
:any\color{green}{any}any 期望值,即要进行比较的第二个值message
(可选):string∣Error\color{green}{string|Error}string∣Error 断言测试失败时抛出的自定义错误消息
代码示例
import assert from 'node:assert'
assert.notDeepStrictEqual({foo: 1}, {foo: '1'})
// 断言测试通过
assert.notDeepStrictEqual([1, 'a'], [1, 'a'], '两个值深度严格相等')
// AssertionError [ERR_ASSERTION]: 两个值深度严格相等
8. assert.match(string, regexp[, message])
方法作用
用于检查字符串 string
是否与正则表达式 regexp
相匹配。如果匹配成功,则断言测试通过,否则抛出 AssertionError
异常。
参数说明
string
: string\color{green}{string}string 需要检查的字符串regexp
: RegExp\color{green}{RegExp}RegExp 用于匹配字符串的正则表达式message
(可选):string∣Error\color{green}{string|Error}string∣Error 断言测试失败时抛出的自定义错误消息
代码示例
import assert from 'node:assert/strict'
assert.match('I will fail', /pass/, '字符串与正则表达式不匹配')
// AssertionError [ERR_ASSERTION]: 字符串与正则表达式不匹配
assert.match(123, /pass/, '第一个参数是数字,不是字符串,类型不对')
// AssertionError [ERR_ASSERTION]: 第一个参数是数字,不是字符串,类型不对
assert.match('I will pass', /pass/)
// 断言测试通过
9. assert.doesNotMatch(string, regexp[, message])
方法作用
用于检查字符串 string
是否与正则表达式 regexp
不匹配。换句话说,如果匹配成功,将抛出 AssertionError
异常。
参数说明
string
: string\color{green}{string}string 需要检查的字符串regexp
: RegExp\color{green}{RegExp}RegExp 用于匹配字符串的正则表达式message
(可选):string∣Error\color{green}{string|Error}string∣Error 断言测试失败时抛出的自定义错误消息
代码示例
import assert from 'node:assert'
assert.doesNotMatch('I will fail', /fail/, '字符串与正则表达式匹配成功')
// AssertionError [ERR_ASSERTION]: 字符串与正则表达式匹配成功
assert.doesNotMatch(123, /pass/, '第一个参数必须为字符串')
// AssertionError [ERR_ASSERTION]: 第一个参数必须为字符串
assert.doesNotMatch('I will pass', /different/)
// 断言测试通过
10. assert.rejects(promiseFn[, error][, message])
方法作用
用于验证异步函数 promiseFn
是否正确地抛出了预期的错误 error
。这个方法返回一个 Promise
,当异步函数按预期抛出错误时,Promise 将被解析。如果异步函数没有返回 Promise、没有抛出错误或抛出的错误与预期不符,将抛出 AssertionError
异常。
参数说明
promiseFn
:Function∣Promise\color{green}{Function|Promise}Function∣Promise 要测试的异步函数,必须返回 Promiseerror
(可选):RegExp∣Function∣Object∣Error\color{green}{RegExp|Function|Object|Error}RegExp∣Function∣Object∣Error 用于匹配抛出的错误的值message
(可选):string\color{green}{string}string 断言测试失败时抛出的自定义错误消息
代码示例
import assert from 'node:assert'
const asyncFunction = async () => {
throw new Error('出错了')
}
assert.rejects(asyncFunction, new Error('出错了'))
// 断言测试通过,按预期抛出了 Error 错误类型(message 和 name)一致
await assert.rejects(
async () => { throw new TypeError('Wrong value') },
{
name: 'TypeError',
message: 'Wrong value',
}
)
// 断言测试通过,因为 name 和 message 完全一致
await assert.rejects(
async () => {
return Promise.resolve('success')
},
{
name: 'AssertionErrorName',
message: 'Missing rejection'
},
'异步函数应该被 reject'
)
// AssertionError [ERR_ASSERTION]: Missing expected rejection (AssertionErrorName): 异步函数应该被 reject
11. assert.doesNotReject(promiseFn [, error] [, message])
方法作用
用于验证一个异步函数是否按预期不抛出错误。这个方法返回一个 Promise,当异步函数不抛出错误或抛出的错误与预期不符时,Promise 将被解析。如果异步函数抛出了预期的错误,将抛出 AssertionError
异常。
参数说明
promiseFn
:Function∣Promise\color{green}{Function|Promise}Function∣Promise 要测试的异步函数,必须返回 Promiseerror
(可选):RegExp∣Function∣Object∣Error\color{green}{RegExp|Function|Object|Error}RegExp∣Function∣Object∣Error 用于匹配抛出的错误的值message
(可选):string∣Error\color{green}{string|Error}string∣Error 断言测试失败时抛出的自定义错误消息
代码示例
import assert from 'node:assert'
const asyncFunction = async () => {
// 不抛出错误
}
// 验证 asyncFunction 是否按预期不抛出错误
assert.doesNotReject(
asyncFunction,
'异步函数抛出了意外的错误'
)
// 断言测试通过,因为 asyncFunction 未抛出错误
function syncFunction() {
throw new Error('未能执行函数')
}
assert.doesNotReject(syncFunction, Error, '未抛出预期错误')
// Error: 未能执行函数
// 当 promiseFn 是一个同步函数并且它抛出错误时,返回带有该错误的 Promise
function normalFunction() {
return '我是一个字符串,不是Promise'
}
assert.doesNotReject(normalFunction(), Error, 'ERR_INVALID_ARG_TYPE')
// TypeError [ERR_INVALID_ARG_TYPE]: The "promiseFn" argument must be of type function or an instance of Promise. Received type string ('我是一个字符串,不是Promise')
// 当 promiseFn 不返回 Promise 时,将返回带有 `ERR_INVALID_ARG_TYPE` 错误的 Promise。
12. assert.throws(fn[, error][, message])
方法作用
用于测试一个同步函数是否按预期抛出错误。如果函数没有抛出错误或抛出的错误与预期不符,将抛出 AssertionError
异常。
参数说明
fn
:Function\color{green}{Function}Function 要测试的同步函数,需要在其内部抛出异常error
(可选):RegExp∣Function∣Object∣Error\color{green}{RegExp|Function|Object|Error}RegExp∣Function∣Object∣Error 用于匹配抛出的错误的值message
(可选):string\color{green}{string}string 断言测试失败时抛出的自定义错误消息
代码示例
import assert from 'node:assert'
const errorFunction = () => {
throw new Error('Expected error')
}
assert.throws(
errorFunction,
/^Expected error$/,
'方法没有抛出预期错误'
)
// AssertionError [ERR_ASSERTION]: 方法没有抛出预期错误
assert.throws(
() => {
throw new Error('Wrong value')
},
/^Error: Wrong value$/
)
// 断言测试通过
13. assert.doesNotThrow(fn[, error][, message])
方法作用
用于测试一个同步函数是否按预期不抛出错误。如果函数抛出了错误,将抛出 AssertionError
异常。
参数说明
fn
:Function\color{green}{Function}Function 要测试的同步函数,需要在其内部抛出异常error
(可选):RegExp∣Function∣Object∣Error\color{green}{RegExp|Function|Object|Error}RegExp∣Function∣Object∣Error 用于匹配抛出的错误的值message
(可选):string\color{green}{string}string 断言测试失败时抛出的自定义错误消息
代码示例
import assert from 'node:assert/strict'
function myFunction() {
throw new TypeError('函数抛出异常')
}
assert.doesNotThrow(myFunction, TypeError, '发生了意外错误')
// AssertionError [ERR_ASSERTION]: Got unwanted exception: 发生了意外错误
14. assert.ifError(value)
方法作用
它用于测试一个值是否为 null
或 undefined
。如果传入的值不是 null
或 undefined
,则抛出 AssertionError
异常。
这个方法通常用于测试回调函数中的错误参数,以确保期望没有发生错误时,错误参数确实是假值。
参数说明:
value
:any\color{green}{any}any 要测试的值,通常是一个错误对象或假值
代码示例
import assert from 'node:assert/strict'
assert.ifError(null)
// 断言通过
assert.ifError(undefined)
// 断言通过
assert.ifError(false)
// AssertionError [ERR_ASSERTION]: ifError got unwanted exception: false
assert.ifError(0)
// AssertionError [ERR_ASSERTION]: ifError got unwanted exception: 0
assert.ifError('error')
// AssertionError [ERR_ASSERTION]: ifError got unwanted exception: 'error'
assert.ifError(new Error())
// AssertionError [ERR_ASSERTION]: ifError got unwanted exception: Error
转载自:https://juejin.cn/post/7228873464719048762