6.断言API

6.1. 软件开发中的断言

在软件开发中,断言 陈述关于值或代码片段必须为真的事实。如果不为真,则抛出异常。Node.js 通过其内置模块assert支持断言。例如:

import {strict as assert} from 'assert';
assert.equal(3 + 5, 8);

该断言表明 3 加 5 的预期结果为 8。import 语句建议使用 assertstrict版本

6.2. 本书中如何使用断言

在本书中,断言有两种用途:在代码示例中记录结果以及实现测试驱动的练习。

6.2.1. 通过断言记录代码示例中的结果

在代码示例中,断言表达了预期的结果。举例来说,以下函数:

function id(x) {
  return x;
}

id()返回其参数。我们可以通过断言来证明它:

assert.equal(id('abc'), 'abc');

在示例中,我通常省略导入assert的语句。

使用断言的动机是:

  • 您可以精确指定预期的内容。
  • 代码示例可以自动测试,这可以确保它们真正起作用。

6.2.2. 通过断言实现测试驱动的练习

本书的练习是通过测试框架mocha进行测试驱动的。测试内部的检查是通过assert的方法进行的。

以下是此类测试的示例:

// For the exercise, you must implement the function hello().
// The test checks if you have done it properly.
test('First exercise', () => {
  assert.equal(hello('world'), 'Hello world!');
  assert.equal(hello('Jane'), 'Hello Jane!');
  assert.equal(hello('John'), 'Hello John!');
  assert.equal(hello(''), 'Hello !');
});

有关更多信息,请参阅 7.测验和练习 的章节。

6.3. 正常比较与深度比较

严格的 equal()使用===来比较值。因此,一个对象只等于它自己——即使另一个对象具有相同的内容(因为===不比较对象的内容,只比较它们的唯一标识):

assert.notEqual({foo: 1}, {foo: 1});

deepEqual()是比较对象的更好选择:

assert.deepEqual({foo: 1}, {foo: 1});

此方法也适用于数组:

assert.notEqual(['a', 'b', 'c'], ['a', 'b', 'c']);
assert.deepEqual(['a', 'b', 'c'], ['a', 'b', 'c']);

6.4. 快速参考:模块assert

有关完整文档,请参阅 Node.js 文档

6.4.1. 普通相等

  • function equal(actual: any, expected: any, message?: string): void actual === expected必须是true。如果不是,则抛出AssertionError
    assert.equal(3+3, 6);
    
  • function notEqual(actual: any, expected: any, message?: string): void actual !== expected必须是true。如果不是,则抛出AssertionError
    assert.notEqual(3+3, 22);
    

可选的最后一个参数message可用于解释断言的内容。如果断言失败,则消息用于设置抛出的AssertionError

let e;
try {
  const x = 3;
  assert.equal(x, 8, 'x must be equal to 8')
} catch (err) {
  assert.equal(String(err), 'AssertionError [ERR_ASSERTION]: x must be equal to 8');
}

6.4.2. 深度相等

  • function deepEqual(actual: any, expected: any, message?: string): void actual必须与expected完全相同。如果不是,则抛出AssertionError
    assert.deepEqual([1,2,3], [1,2,3]);
    assert.deepEqual([], []);
    // To .equal(), an object is only equal to itself:
    assert.notEqual([], []);
    
  • function notDeepEqual(actual: any, expected: any, message?: string): void actual不得与expected深度相等。如果是,则抛出AssertionError

6.4.3. 期望异常

如果你想(或期望)接收异常,你需要throws():这个函数调用它的第一个参数,函数block,只有在它抛出异常时才会成功。其他参数可用于指定该异常必须是什么样的。

  • function throws(block: Function, message?: string): void
    assert.throws(
      () => {
        null.prop;
      }
    );
    
  • function throws(block: Function, error: Function, message?: string): void
    assert.throws(
      () => {
        null.prop;
      },
      TypeError
    );
    
  • function throws(block: Function, error: RegExp, message?: string): void
    assert.throws(
      () => {
        null.prop;
      },
      /^TypeError: Cannot read property 'prop' of null$/
    );
    
  • function throws(block: Function, error: Object, message?: string): void
    assert.throws(
      () => {
        null.prop;
      },
      {
        name: 'TypeError',
        message: `Cannot read property 'prop' of null`,
      }
    );
    

6.4.4. 另一个工具函数

  • function fail(message: string | Error): never 调用时始终抛出AssertionError。这有时对单元测试很有用。
    try {
      functionThatShouldThrow();
      assert.fail();
    } catch (_) {
      // Success
    }
    
下一节:在大多数章节中,都有测验和练习。它们是付费功能,但可以进行全面预览。本章介绍如何开始使用它们。