Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/backbone.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 用西农监视一种方法。方法绑定到事件侦听器。方法已执行,但是。calledOnce是否为false?_Javascript_Backbone.js_Sinon - Fatal编程技术网

Javascript 用西农监视一种方法。方法绑定到事件侦听器。方法已执行,但是。calledOnce是否为false?

Javascript 用西农监视一种方法。方法绑定到事件侦听器。方法已执行,但是。calledOnce是否为false?,javascript,backbone.js,sinon,Javascript,Backbone.js,Sinon,我的代码运行正常,但是我的测试用例没有达到预期的效果。我不明白为什么我的间谍不相信已经执行了一种方法 我绑定一个事件侦听器,如下所示: var playlists = Backbone.Collection.extend({ initialize: function(){ this.on('add', this._onAdd); }, // Method: _onAdd: function (model, collection, options

我的代码运行正常,但是我的测试用例没有达到预期的效果。我不明白为什么我的间谍不相信已经执行了一种方法

我绑定一个事件侦听器,如下所示:

var playlists = Backbone.Collection.extend({
    initialize: function(){
        this.on('add', this._onAdd);
    },

    //  Method:
    _onAdd: function (model, collection, options) {
        console.log('onAdd');
        this._foo();
    },

    _foo: function(){
        console.log('foo');
    }
});

Playlists = new playlists();
我正在使用sinon监视我的目标:

it('should call _onAdd when adding a model to the collection', function() {
    sinon.spy(Playlists, '_onAdd');
    sinon.spy(Playlists, '_foo');

    Playlists.add({});
    expect(Playlists._onAdd.calledOnce).to.equal(true);
    expect(Playlists._foo.calledOnce).to.equal(true);

    Playlists._onAdd.restore();
    Playlist._foo.restore();
});
我的测试用例失败,因为一次调用
\u onAdd
的期望值不正确。然而,
\u foo
被调用一次的期望是正确的


我在监视我的事件侦听器时做了一些不正确的事情。为什么sinon不相信已经调用了添加。如何更正此问题?

您的问题是函数引用引起的。当您在
playlists
变量中创建播放列表时,它正在
playlists
集合上运行
initialize()
,该集合将参照
设置事件侦听器

当你做一个间谍时,它会重新定义_onAdd指向什么,但不会更新事件侦听器正在使用的引用。考虑以下事项:

_onAdd: function(){...} // Call this FuncRefA
调用
initialize
时(通过
newplaylists();
),事件侦听器将被计算为指向
FuncRefA
,因为这是添加时
指向的内容

this.on('add', FuncRefA);
然后当你添加间谍时,它实际上是在做这样的事情

_onAdd: function(){ FuncRefA() } // Wraps the existing function, Call the new function FuncRefB
此时,
\u onAdd
现在指向
FuncRefB
,但事件侦听器仍然指向
FuncRefA
,因此当测试运行时,事件侦听器正在被调用(和
FuncRefA
),但您的间谍没有被调用,因为事件侦听器不知道它的存在(它指向一个
FuncRefA

有两种解决方案:

1) 在创建
播放列表
之前,您可以在
播放列表
集合中的
原型
上设置spy,这样在创建
播放列表
时,将函数引用带到spy

sinon.spy(playlists.prototype, '_onAdd');
Playlists = new playlists();
//... run tests now.
2) 使事件侦听器具有一个匿名函数,该函数调用添加
,以便在事件发生时对其进行评估。这将允许您监视
播放列表的
\onAdd
方法,因为一旦触发
添加
事件,就会对其引用进行评估

initialize: function(){
    var self = this;
    this.on('add', function(){ self._onAdd(arguments) });
},

您的问题是函数引用的原因。当您在
playlists
变量中创建播放列表时,它正在
playlists
集合上运行
initialize()
,该集合将参照
设置事件侦听器

当你做一个间谍时,它会重新定义_onAdd指向什么,但不会更新事件侦听器正在使用的引用。考虑以下事项:

_onAdd: function(){...} // Call this FuncRefA
调用
initialize
时(通过
newplaylists();
),事件侦听器将被计算为指向
FuncRefA
,因为这是添加时
指向的内容

this.on('add', FuncRefA);
然后当你添加间谍时,它实际上是在做这样的事情

_onAdd: function(){ FuncRefA() } // Wraps the existing function, Call the new function FuncRefB
此时,
\u onAdd
现在指向
FuncRefB
,但事件侦听器仍然指向
FuncRefA
,因此当测试运行时,事件侦听器正在被调用(和
FuncRefA
),但您的间谍没有被调用,因为事件侦听器不知道它的存在(它指向一个
FuncRefA

有两种解决方案:

1) 在创建
播放列表
之前,您可以在
播放列表
集合中的
原型
上设置spy,这样在创建
播放列表
时,将函数引用带到spy

sinon.spy(playlists.prototype, '_onAdd');
Playlists = new playlists();
//... run tests now.
2) 使事件侦听器具有一个匿名函数,该函数调用添加
,以便在事件发生时对其进行评估。这将允许您监视
播放列表的
\onAdd
方法,因为一旦触发
添加
事件,就会对其引用进行评估

initialize: function(){
    var self = this;
    this.on('add', function(){ self._onAdd(arguments) });
},

这对我来说真的很奇怪。如何在不修改代码以支持测试的情况下测试单例?您的两种解决方案都有意义,我也理解为什么会发生这种情况,但是#2不好,因为它使代码更加复杂,以支持间谍活动,而#1不好,因为它没有为我的应用程序传达正确的意图。播放列表只能实例化一次。@SeanAnderson:1为什么有问题?我同意2有点奇怪,但为什么在实例化之前检测原型是不好的呢?事实上,我想说,检查添加是否被称为一件奇怪的事情,为什么不测试行为而不是显式的调用序列呢?好吧,我可以通过一些重构使1工作,但我失去了通过设计强制播放列表作为一个单例的能力。目前,播放列表在其作用域内实例化自身,然后将单件公开给外部世界。重构后,父对象将需要实例化播放列表并公开其单个实例。我之所以检查_onAdd,是因为我想确保_onAdd中的一个方法没有根据给_onAdd的参数执行,而是调用了_onAdd本身。如果没有调用_onAdd,那么测试用例可能会错误地通过。这对我来说真的很奇怪。如何在不修改代码以支持测试的情况下测试单例?您的两种解决方案都有意义,我也理解为什么会发生这种情况,但是#2不好,因为它使代码更加复杂,以支持间谍活动,而#1不好,因为它没有为我的应用程序传达正确的意图。播放列表只能实例化一次。@SeanAnderson:1为什么有问题?我同意2有点奇怪,但为什么在实例化之前检测原型是不好的呢?事实上,我想说,检查ADD是否被称为一件奇怪的事情,为什么不测试它呢