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

Ava并行测试时Sinon Stub报错:Attempted to wrap已包装函数

问题分析与解决方案

错误原因

当Ava以并行模式运行时,如果同一测试文件内的多个测试被允许并行执行(比如通过配置concurrency或命令行参数开启),不同测试的beforeEach钩子会同时触发。虽然每个测试都持有独立的Sinon沙箱,但它们操作的是Node.js进程内缓存的同一个myModule导出对象——模块在进程内是单例存在的。

当第一个测试的沙箱还未完成myFunction的Stub(或未执行restore),第二个测试的beforeEach就尝试再次包装同一个函数,Sinon就会抛出「Attempted to wrap myFunction which is already wrapped」错误。

而串行模式下,测试按顺序执行,前一个测试的afterEach会先恢复原函数,后一个测试的beforeEach再进行Stub,因此不会出现冲突。

解决方案

1. 限制同一文件内测试串行执行

修改Ava配置,让同一文件内的测试串行运行,同时保持不同测试文件的并行能力:

// ava.config.js
export default {
  concurrency: 1, // 每个文件内仅允许1个测试并行执行
  // 也可针对特定文件单独配置
  files: [
    { pattern: 'test/**/*.test.js', concurrency: 1 }
  ]
};

或直接通过命令行参数执行:

ava --concurrency=1

2. 提前检查并恢复已包装的函数

在beforeEach中先检查目标函数是否已被Sinon包装,若已包装则先恢复,再创建新的Stub:

import sinon from 'sinon';
import * as myModule from '../../../src/myModule';

test.beforeEach(t => {
  t.context.sandbox = sinon.createSandbox();
  // 检查函数是否已被Stub,若已存在则先恢复
  const existingStub = sinon.getStub(myModule, 'myFunction');
  if (existingStub) {
    existingStub.restore();
  }
  t.context.sandbox.stub(myModule, 'myFunction').returns(false);
});

test.afterEach.always(t => {
  t.context.sandbox.restore();
});

3. 启用Ava的隔离模式

开启Ava的isolated模式,让每个测试都在独立的Node.js进程中运行。每个进程的模块缓存相互独立,从根本上避免共享模块对象导致的冲突:

// ava.config.js
export default {
  isolated: true
};

或通过命令行执行:

ava --isolated

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 20:33:39