诗乃间谍继承功能

时间:2018-01-11 15:11:14

标签: javascript sinon

如何使用sinon监视继承的函数?

如果我有 -

    class Parent{
        constructor(){}
        foo(){
            //do foo
        }
    }

    class Child extend Parent{
        constructor(){
            super();
        }
    }

    const childSpy = sinon.spy(Child.prototype, 'foo')
    const parentSpy = sinon.spy(Parent.prototype, 'foo')


    new Child().foo();

    expect(childSpy).to.have.been.called; //false
    expect(parentSpy).to.have.been.called; //true

我做错了什么?

以上示例是我的代码的简化版本,在实际代码中我无法访问ChildParent类的实例

2 个答案:

答案 0 :(得分:1)

所以,我试过这个并收到了与你列出的不同的结果。在我的情况下,childSpy 被调用,而parentSpy不是,而且 - 鉴于sinon的工作原理 - 是我所期待的。所以我假设你把它们混合在你的帖子中并从那里开始。

这里发生的事情有点微妙,并且在了解sinon在物体上产生间谍时实际上做了什么的时候有点了解。

执行此行时:

const childSpy = sinon.spy(Child.prototype, 'foo')

Sinon首先访问Child.prototype上名为foo.的属性。Child.prototype上实际上不存在此属性,因此JavaScript将原型链升级到Parent.prototype,,其中 找到这样的财产。

因此,sinon获得了对存储Parent.prototype.foo的原始函数的引用。它将此函数包装在间谍中,然后将其作为Child.prototype分配给Child.prototype.foo

这里的奇怪之处在于Child.prototype之前没有自己对原始foo函数的引用,但现在它已经引用了, 现在将被调用当您在foo

的实例上致电Child

执行行时:

const parentSpy = sinon.spy(Parent.prototype,'foo')

Sinon访问Parent.prototype.foo处的函数,将其包装在间谍中,并将间谍分配给它。这似乎应该影响Child.prototype.foo间谍包裹的功能,但事实并非如此。位于那里的间谍仍在包裹原始 Parent.prototype.foo

你可能会翻转你的间谍创作语句的顺序来试图解决这个问题,但你会发现sinon不允许这样做。您无法包装已映射的方法。即如果某事已经是间谍,试图使用sinon来“窥探间谍”就会抛出。这是有充分理由的,但我确信在这种情况下看起来很令人沮丧。

您无法访问类的实例似乎很奇怪,但如果您真的必须以这种方式执行操作,那么解决此问题的方法之一就是为Child类提供自己的foo方法。它需要做的就是在super上使用相同的签名调用相同的方法:

class Parent{
    constructor(){}
    foo(){
        //do foo
    }
}

class Child extend Parent{
    constructor(){
        super();
    }

    foo(...args){
        return super.foo(...args)
    }
}

const childSpy = sinon.spy(Child.prototype, 'foo')
const parentSpy = sinon.spy(Parent.prototype, 'foo')


new Child().foo();

expect(childSpy).to.have.been.called;
expect(parentSpy).to.have.been.called;

执行此操作将使您的childSpy换行Child.prototype.foo,这将调用Parent.prototype.foo恰好在调用它时的值。

答案 1 :(得分:0)

你最好试着窥探具体的对象而不是类。
例如

const expect = require('chai').expect;
const sinon = require('sinon');


describe('Some', () => {
  it('one', () => {
    class Parent {
      constructor() { }
      foo() {
        //do foo
      }
    }

    class Child extends Parent{
      constructor() {
        super();
      }
    }

    const child = new Child();
    const childSpy = sinon.spy(child, 'foo');

    child.foo();

    expect(childSpy.called).to.be.true; //true    

  });
});

希望得到这个帮助。