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

如何用Sinon多次包装方法并按参数返回不同对象?解决重复包装报错

解决Sinon中多次包装同一方法(getRepository)的问题

这个问题我之前也碰到过,核心原因是你连续两次调用sandbox.mock(Salesforce).expects('getRepository'),Sinon的mock机制会直接替换目标方法,第二次尝试包装同一个方法时就会触发TypeError: Attempted to wrap getRepository which is already wrapped错误。

下面给你两种可行的解决思路,都能实现让getRepository根据传入的不同参数返回不同仓库实例的需求:

方法一:使用Stub替代Mock(推荐)

Stub比Mock更适合这种“根据参数返回不同结果”的场景,它支持链式设置不同参数对应的返回值,不会出现重复包装的问题:

// 先创建两个仓库实例,并分别mock它们的方法
const servicePackagesOfferingRepository = new Repository(ServicePackageOffering);
sandbox.mock(servicePackagesOfferingRepository)
  .expects('findOneById')
  .withArgs(inputModel.servicePackageOfferingId)
  .resolves({});

const serviceCallRepository = new Repository(ServiceCall);
sandbox.mock(serviceCallRepository)
  .expects('save')
  .once();

// 用Stub包装getRepository,根据传入的参数返回对应的仓库实例
sandbox.stub(Salesforce, 'getRepository')
  .withArgs(ServicePackageOffering).returns(servicePackagesOfferingRepository)
  .withArgs(ServiceCall).returns(serviceCallRepository);

这样设置后,当代码第一次调用Salesforce.getRepository(ServicePackageOffering)时会返回你创建的第一个仓库实例,第二次调用Salesforce.getRepository(ServiceCall)时返回第二个实例,完美匹配你的业务逻辑。

方法二:在同一个Mock中设置多调用行为

如果你更倾向于用Mock来严格验证调用次数和顺序,可以在同一个Mock对象上通过onCall()方法指定每次调用的行为:

// 先创建两个仓库实例
const servicePackagesOfferingRepository = new Repository(ServicePackageOffering);
const serviceCallRepository = new Repository(ServiceCall);

// 创建一个针对getRepository的Mock,明确预期会被调用两次
const getRepoMock = sandbox.mock(Salesforce)
  .expects('getRepository')
  .twice();

// 设置第一次调用的行为:传入ServicePackageOffering时返回对应仓库
getRepoMock.onCall(0)
  .withArgs(ServicePackageOffering)
  .returns(servicePackagesOfferingRepository);

// 设置第二次调用的行为:传入ServiceCall时返回对应仓库
getRepoMock.onCall(1)
  .withArgs(ServiceCall)
  .returns(serviceCallRepository);

// 最后mock两个仓库的具体方法
sandbox.mock(servicePackagesOfferingRepository)
  .expects('findOneById')
  .withArgs(inputModel.servicePackageOfferingId)
  .resolves({});

sandbox.mock(serviceCallRepository)
  .expects('save')
  .once();

这种方式通过onCall(index)指定第N次调用的参数和返回值,既避免了重复包装的问题,也能严格验证getRepository的调用次数和顺序。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 10:00:57