You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用node:assert断言Mock函数的指定调用参数?

扩展Node.js assert模块实现Mock函数参数断言

方案1:无需扩展,直接用现有API实现匹配检查

不用修改assert模块,结合assert.ok和数组的some方法就能实现类似Jest arrayContaining的效果:

const assert = require('node:assert');

it("should assert args", (t) => {
  const loggerSpy = t.mock.method(Logger, "info");
  myFunctionUnderTest();

  // 检查是否存在匹配参数的调用
  let hasMatchingCall = false;
  for (const call of loggerSpy.mock.calls) {
    try {
      assert.deepStrictEqual(call.arguments, [2, "No consumer application for given code", "MODEL_ENERGY_FLOW"]);
      hasMatchingCall = true;
      break;
    } catch {}
  }
  assert.ok(hasMatchingCall, 'Logger.info未被传入预期参数调用');
});

这里通过遍历调用记录,用assert.deepStrictEqual做参数匹配,只要找到一次匹配就标记为通过,避免全量对比。

方案2:扩展assert模块添加自定义断言方法

如果想复用类似Jest的简洁语法,可以直接扩展node:assert的功能,添加专属断言方法:

1. 添加toHaveBeenCalledWith断言

针对Mock函数的参数验证,封装一个直接可用的断言方法:

const assert = require('node:assert');

// 给assert添加自定义断言方法
assert.toHaveBeenCalledWith = (spy, ...expectedArgs) => {
  const matched = spy.mock.calls.some(call => {
    try {
      assert.deepStrictEqual(call.arguments, expectedArgs);
      return true;
    } catch {
      return false;
    }
  });

  if (!matched) {
    throw new assert.AssertionError({
      message: `Spy未被传入预期参数调用:${JSON.stringify(expectedArgs)}`,
      actual: spy.mock.calls.map(call => call.arguments),
      expected: expectedArgs
    });
  }
};

使用时直接调用,语法和Jest几乎一致:

it("should assert args", (t) => {
  const loggerSpy = t.mock.method(Logger, "info");
  myFunctionUnderTest();

  assert.toHaveBeenCalledWith(loggerSpy, 2, "No consumer application for given code", "MODEL_ENERGY_FLOW");
});

2. 添加arrayContaining匹配器

如果需要更灵活的数组包含验证,可以实现类似Jest的arrayContaining:

const assert = require('node:assert');
const originalDeepStrictEqual = assert.deepStrictEqual;

// 定义自定义匹配器标识
const ARRAY_CONTAINING_TAG = Symbol('ArrayContaining');

assert.arrayContaining = (expectedItems) => ({
  [ARRAY_CONTAINING_TAG]: true,
  expectedItems
});

// 重写deepStrictEqual以支持自定义匹配器
assert.deepStrictEqual = (actual, expected, message) => {
  if (expected?.[ARRAY_CONTAINING_TAG]) {
    const allMatched = expected.expectedItems.every(item => {
      return actual.some(actualItem => {
        try {
          originalDeepStrictEqual(actualItem, item);
          return true;
        } catch {
          return false;
        }
      });
    });

    if (!allMatched) {
      throw new assert.AssertionError({
        message: message || '数组未包含所有预期元素',
        actual,
        expected: `arrayContaining(${JSON.stringify(expected.expectedItems)})`
      });
    }
  } else {
    originalDeepStrictEqual(actual, expected, message);
  }
};

使用方式和你期望的Jest语法一致:

it("should assert args", (t) => {
  const loggerSpy = t.mock.method(Logger, "info");
  myFunctionUnderTest();

  assert.deepStrictEqual(loggerSpy.mock.calls, assert.arrayContaining([
    { arguments: [2, "No consumer application for given code", "MODEL_ENERGY_FLOW"] }
  ]));
});

注意事项

  • 扩展核心模块时,建议在项目测试入口文件中一次性完成定义,避免重复加载导致的冲突。
  • 如果你使用的测试框架(比如AVA)支持自定义断言,也可以直接在框架的断言对象上扩展,比如给t对象添加方法,会更贴合框架生态。

内容的提问来源于stack exchange,提问作者Frank

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 05:48:18