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

如何在Sinon中断言属性赋值与函数调用的执行顺序?

用Sinon验证对象属性赋值与函数调用的执行顺序

被测函数

function systemUnderTest(func, param) {
  param.firstProperty = !param.firstProperty;
  func();
  param.secondProperty = !param.secondProperty;
}

需求

需要验证以下执行顺序:

  • param.firstProperty 的赋值操作早于 func() 的调用
  • func() 的调用早于 param.secondProperty 的赋值

已知Sinon的spy.calledBefore(anotherSpy)方法可用于断言调用顺序,但不清楚如何给对象字面量param的属性添加调用记录,使其支持该方法。


解决方案

核心思路是给param的目标属性添加setter类型的Spy,每次对属性执行赋值操作时,Spy会被触发并记录调用时间,之后就能和func的Spy一起用calledBefore做顺序断言。

方法一:手动用Object.defineProperty创建Spy Setter

const sinon = require('sinon');

describe('systemUnderTest 执行顺序验证', () => {
  it('属性赋值与函数调用顺序符合预期', () => {
    // 1. 创建func的Spy
    const funcSpy = sinon.spy();

    // 2. 给param的属性创建Setter Spy
    const param = {};
    const firstPropSetSpy = sinon.spy();
    const secondPropSetSpy = sinon.spy();

    // 给firstProperty设置带Spy的setter,同时提供默认getter避免赋值时取反出错
    Object.defineProperty(param, 'firstProperty', {
      set: firstPropSetSpy,
      get: () => false
    });

    Object.defineProperty(param, 'secondProperty', {
      set: secondPropSetSpy,
      get: () => false
    });

    // 3. 执行被测函数
    systemUnderTest(funcSpy, param);

    // 4. 断言顺序
    sinon.assert.calledBefore(firstPropSetSpy, funcSpy);
    sinon.assert.calledBefore(funcSpy, secondPropSetSpy);
  });
});

方法二:用Sinon Stub简化Setter Spy创建

如果param本身已有初始属性值,可以直接用Sinon的stub快速替换为带Spy的访问器:

const sinon = require('sinon');

describe('systemUnderTest 执行顺序验证', () => {
  it('属性赋值与函数调用顺序符合预期', () => {
    // 1. 创建func的Spy
    const funcSpy = sinon.spy();

    // 2. 初始化param并给属性创建Setter Spy
    const param = {
      firstProperty: false,
      secondProperty: false
    };
    sinon.stub(param, 'firstProperty').set(sinon.spy());
    sinon.stub(param, 'secondProperty').set(sinon.spy());

    // 3. 执行被测函数
    systemUnderTest(funcSpy, param);

    // 4. 断言顺序(通过stub的setter属性获取Spy)
    sinon.assert.calledBefore(param.firstProperty.setter, funcSpy);
    sinon.assert.calledBefore(funcSpy, param.secondProperty.setter);
  });
});

原理说明

对对象属性的赋值操作会触发属性的setter方法,我们用Sinon Spy替换原本的setter后,每次赋值都会让Spy记录一次调用。这样firstProperty的setter Spy、func Spy、secondProperty的setter Spy就都有了调用时间戳,通过calledBefore就能轻松验证三者的执行顺序。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 09:00:11