likes
comments
collection
share

Node.js API 之旅:Assert 模块揭秘

作者站长头像
站长
· 阅读数 45

断言(Assertion)是编程中一种常见的技巧,用于在代码执行过程中检查某个条件是否满足预期。如果满足预期,那么代码将正常执行,不会有任何输出;如果不满足预期,则抛出一个异常,提示开发者存在问题。

Node.js 的 Assert 模块提供了一系列强大的断言函数,帮助我们确保代码的正确性和稳定性。在本文中,我们将深入探讨 Assert 模块的各个 API,详细解读其作用、传参并提供相关代码示例。

为了贴近最佳实践,本文将不会涉及以下 5 个已废弃或者已经有更佳替代方案的 API,

  1. assert.fail(actual, expected[, message[, operator[, stackStartFn]]]) - 已废弃
  2. assert.equal - 建议使用 assert.strictEqual
  3. assert.notEqual - 建议使用 assert.notStrictEqual
  4. assert.deepEqual - 建议使用 assert.deepStrictEqual
  5. assert.notDeepEqual - 建议使用 assert.notDeepStrictEqual

感兴趣的小伙伴可以到官网查阅相关文档。

Node.js API 之旅:Assert 模块揭秘

初始说明

Assert 模块的方法中,几乎每个方法都带有一个可选的 message 参数。为避免重复,我们在此单独介绍该参数,后续内容将不再详述。message 参数可以是字符串或 Error 实例。

  1. 如果未定义 message: 当不传递 message 参数时,如果断言测试失败,将抛出一个具有默认错误消息的 AssertionError 异常。
import assert from 'node:assert/strict'

assert.ok(false)
// AssertionError [ERR_ASSERTION]: false == true

assert.ok('')
// AssertionError [ERR_ASSERTION]: '' == true
  1. 传递字符串作为 message: 当 message 为字符串时,如果断言失败,将抛出一个具有该自定义错误消息的 AssertionError 异常。
import assert from 'node:assert/strict'

assert.ok(false, '发生意外错误')
// AssertionError [ERR_ASSERTION]: 发生意外错误
  1. 传递 Error 实例作为 message: 当 messageError 实例时,如果断言失败,将直接抛出该 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 异常。

参数说明

  • valueany\color{green}{any}any 需要验证的值
  • message(可选):string∣Error\color{green}{string|Error}stringError 断言测试失败时抛出的自定义错误消息

代码示例

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}stringError 断言测试失败时抛出的自定义错误消息,默认值为"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])

方法作用

用于验证两个值是否严格相等,这意味着它们的类型和内容都必须完全相同。

参数说明

  • actualany\color{green}{any}any 实际值,即要进行比较的第一个值
  • expectedany\color{green}{any}any 期望值,即要进行比较的第二个值
  • message(可选):string∣Error\color{green}{string|Error}stringError 断言测试失败时抛出的自定义错误消息

代码示例

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 异常。

参数说明

  • actualany\color{green}{any}any 实际值,即要进行比较的第一个值
  • expectedany\color{green}{any}any 期望值,即要进行比较的第二个值
  • message(可选):string∣Error\color{green}{string|Error}stringError 断言测试失败时抛出的自定义错误消息

代码示例

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])

方法作用

用于深度比较两个值是否相等。深度比较意味着它会递归地比较对象的所有属性以及数组的所有元素,在比较过程中,它会考虑值的类型。

参数说明

  • actualany\color{green}{any}any 实际值,即要进行比较的第一个值
  • expectedany\color{green}{any}any 期望值,即要进行比较的第二个值
  • message(可选):string∣Error\color{green}{string|Error}stringError 断言测试失败时抛出的自定义错误消息

比较规则

  1. 基本类型:值和类型必须完全相等,使用 Object.is() 进行比较。例如,数字 1 和字符串 '1' 被认为是不相等的;
  2. 对象:所有属性的键和值都必须深度相等,对象的原型也必须相同;
  3. 数组:数组的长度和每个元素都必须深度相等。例如,[1, 2, 3][1, 2, 3] 是相等的,而 [1, 2, 3][1, '2', 3] 是不相等的;
  4. 函数:函数必须具有相同的源代码,即 toString() 返回的字符串表示。函数的原型也必须相同;
  5. Map 和 Set:MapSet 必须具有相同的键值对/元素,并以相同的顺序排列。例如,两个具有相同键值对的 Map 是相等的,而具有相同元素但顺序不同的 Set 是不相等的;
  6. 其他原生类型(例如 RegExp、Date、Buffer、TypedArray 等):这些类型的实例必须具有相同的属性和值。例如,具有相同模式和标志的两个 RegExp 对象是相等的;
  7. 特殊值: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 异常。

参数说明

  • actualany\color{green}{any}any 实际值,即要进行比较的第一个值
  • expectedany\color{green}{any}any 期望值,即要进行比较的第二个值
  • message(可选):string∣Error\color{green}{string|Error}stringError 断言测试失败时抛出的自定义错误消息

代码示例

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}stringError 断言测试失败时抛出的自定义错误消息

代码示例

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}stringError 断言测试失败时抛出的自定义错误消息

代码示例

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 异常。

参数说明

  • promiseFnFunction∣Promise\color{green}{Function|Promise}FunctionPromise 要测试的异步函数,必须返回 Promise
  • error(可选):RegExp∣Function∣Object∣Error\color{green}{RegExp|Function|Object|Error}RegExpFunctionObjectError 用于匹配抛出的错误的值
  • 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 异常。

参数说明

  • promiseFnFunction∣Promise\color{green}{Function|Promise}FunctionPromise 要测试的异步函数,必须返回 Promise
  • error(可选):RegExp∣Function∣Object∣Error\color{green}{RegExp|Function|Object|Error}RegExpFunctionObjectError 用于匹配抛出的错误的值
  • message(可选):string∣Error\color{green}{string|Error}stringError 断言测试失败时抛出的自定义错误消息

代码示例

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 异常。

参数说明

  • fnFunction\color{green}{Function}Function 要测试的同步函数,需要在其内部抛出异常
  • error(可选):RegExp∣Function∣Object∣Error\color{green}{RegExp|Function|Object|Error}RegExpFunctionObjectError 用于匹配抛出的错误的值
  • 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 异常。

参数说明

  • fnFunction\color{green}{Function}Function 要测试的同步函数,需要在其内部抛出异常
  • error(可选):RegExp∣Function∣Object∣Error\color{green}{RegExp|Function|Object|Error}RegExpFunctionObjectError 用于匹配抛出的错误的值
  • 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)

方法作用

它用于测试一个值是否为 nullundefined。如果传入的值不是 nullundefined,则抛出 AssertionError 异常。

这个方法通常用于测试回调函数中的错误参数,以确保期望没有发生错误时,错误参数确实是假值。

参数说明:

  • valueany\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
评论
请登录