在Sinon中,如何断言在另一个测试替身之前/之后使用了属性/访问器?

问题描述 投票:0回答:1

注意:我会回答我自己的问题,但如果您有更好的答案,我会接受它。

我有一个如下所示的函数:

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

我想存根

param
并断言
param.firstProperty
func()
之前分配。我还想检查
func()
在设置
param.secondProperty
之前被调用。

Sinon 附带

spy.calledBefore(anotherSpy)
,这似乎是完成这项工作的正确工具,但我不确定如何设置
param
(一个对象文字)来记录其属性/访问器的使用顺序.

如何设置

param
以便我可以在其属性上调用
x.calledBefore(y)

javascript sinon
1个回答
0
投票

我知道有两种方法可以实现这一目标,并且都需要权衡。一种解决方案更冗长但更灵活。另一种解决方案更简洁,但应用有限。

冗长,但适用于 getter、setter 和/或属性

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

  it('tests order of setters', () => {
    // SETUP
    const param = {
      firstProperty: true, // 1
      secondProperty: true,
    };
    const firstPropertySetter = sinon.stub(); // 2
    sinon.stub(param, 'firstProperty').set(firstPropertySetter); // 3
    const secondPropertySetter = sinon.spy(); // 4
    sinon.stub(param, 'secondProperty').set(secondPropertySetter); // 5

    const aFunction = sinon.stub(
      {
        aFunction: () => {},
      },
      'aFunction'
    );

    // SUBJECT
    systemUnderTest(aFunction, param);

    // ASSERT
    expect(firstPropertySetter.calledBefore(aFunction)).toBeTrue(); // pass, as it should
    expect(firstPropertySetter.calledOnce).toBeTrue(); // pass, as it should

    expect(secondPropertySetter.calledBefore(aFunction)).toBeTrue(); // fail, as it should
  });

备注:

  1. 即使

    param
    具有属性(与 getter/setter 相对),测试仍可按预期运行。

    如果

    param
    有 getter/setter,则此测试仍将按预期运行。

  2. sinon.stub()
    需要保存在变量中。不幸的是,
    const firstPropertySetter = sinon.stub(param, 'firstProperty').set(sinon.stub());
    不会正常工作:
    firstPropertySetter.called*
    将始终返回 false/0。 (我很想知道为什么。)

  3. 如前所述,即使对象字面量没有 setter,对

    .set(...)
    的调用仍然有效。

  4. 如果您愿意,可以在此行使用

    sinon.spy()
    代替
    sinon.stub()

  5. 但是你不能在这里使用

    sinon.spy()
    .set(...)
    spy()
    上不存在。

我从这个 GitHub 评论了解到这个解决方案。

简洁,但仅适用于 getter 和 setter

  function systemUnderTest(func, param) {
    param.firstAccessor = !param.firstAccessor; // 1
    func();
    param.secondAccessor = !param.secondAccessor;
  }

  it('tests order of setters/getters', () => {
    // SETUP
    const param = {
      set firstAccessor(value) {}, // 2
      get firstAccessor() {
        return true;
      },
      set secondAccessor(value) {},
      get secondAccessor() {
        return true;
      },
    };
    const firstAccessor = sinon.spy(param, 'firstAccessor', ['get', 'set']); // 3
    const secondAccessor = sinon.spy(param, 'secondAccessor', ['get', 'set']);

    const aFunction = sinon.stub(
      {
        aFunction: () => {},
      },
      'aFunction'
    );

    // SUBJECT
    systemUnderTest(aFunction, param);

    // ASSERT
    expect(firstAccessor.set.calledBefore(aFunction)).toBeTrue(); // 4 // pass, as it should
    expect(firstAccessor.set.calledOnce).toBeTrue(); // pass, as it should

    expect(secondAccessor.set.calledBefore(aFunction)).toBeTrue(); // fail, as it should
  });

备注:

  1. 我想提请注意,我将这些键从

    *Property
    重命名为
    *Accessor

  2. param
    此解决方案必须使用 getter 和 setter...

  3. ...例如,如果

    firstAccessor
    是一个属性,则此行将出错:
    TypeError: Attempted to wrap undefined property firstAccessor as function
    。我不知道为什么这个错误消息说它是一个未定义的属性。这可能是错误消息中的错误?

    此外,该行必须使用

    sinon.spy()
    sinon.stub()
    的第三个参数不接受字符串数组。

  4. 我想提请注意这样一个事实:spy 会调用

    .set
    /
    .get
    来访问 sinon API。例如,
    firstAccessor.set.calledBefore()
    存在,
    firstAccessor.calledBefore
    不存在。

我从官方的Sinon间谍文档学到了这个解决方案。在该页面上搜索“使用间谍包装属性 getter 和 setter”以查找另一个示例。


这是用Sinon v17测试的。

© www.soinside.com 2019 - 2024. All rights reserved.