View SpyOn使用jasmine的主干视图方法

View SpyOn使用jasmine的主干视图方法,view,backbone.js,jasmine,spy,View,Backbone.js,Jasmine,Spy,我有一个主干视图,我想创建一个测试来确认某个元素上的单击事件将调用绑定到该元素的函数。 我的看法是: PromptView = Backbone.View.extend({ id:"promptPage", attributes:{ "data-role":"page", "data-theme":"a" }, events:{ "click #btnYes":

我有一个主干视图,我想创建一个测试来确认某个元素上的单击事件将调用绑定到该元素的函数。 我的看法是:

PromptView = Backbone.View.extend({
        id:"promptPage",
        attributes:{
            "data-role":"page",
            "data-theme":"a"
        },
        events:{
            "click #btnYes":    "answerYes",
            "tap #btnYes":      "answerYes"
        },
        render: function(){
            $(this.el).html(_.template($('#promptPage-template').html(), this.model.toJSON()));

            return this;
        },
        answerYes: function(){
            alert('yes');
        }
    });
我的规格是:

beforeEach(function() {
            model = new PromptModel;
            view = new PromptView({model:model});
            loadFixtures('promptPage.tmpl');
        });

 it("should be able to answer a question with yes", function() {
                var button = $("#btnYes", view.render().el);
                expect(button.length).toBe(1);

                spyOn(view, 'answerYes');

                button.click();
                expect(view.answerYes).toHaveBeenCalled();

            });
然而,上面的视图定义在prototypeproto上创建了answerYes方法,但是spy在视图中的实际实例上创建了一个函数,因此我最终得到了一个view.answerYes(),它是spy和view.\uu proto\uuu.answerYes,这是我真正想要监视的


如何创建spy,使其覆盖视图定义的answerYes方法?

TL;DR:监视实例方法,而不是原型

我认为你需要以不同的方式设置你的测试。
it
块中有太多的关注点和期望,而且您还污染了全局名称空间,这可能会导致测试出现问题

beforeEach(function() {
  loadFixtures('promptPage.tmpl');

  var model = new PromptModel();
  this.view = new PromptView({model:model});
  this.view.render();

  this.button = this.view.$("#btnYes");
});

it("should render the button", function(){
  expect(this.button.length).toBe(1);
});

it("should be able to answer a question with yes", function() {
  spyOn(this.view, 'answerYes');

  this.button.click();
  expect(this.view.answerYes).toHaveBeenCalled();
});
你不需要严格要求按钮的长度。如果按钮没有长度(未找到),则会出现其他故障。但是,您可能希望它在那里更容易找出视图渲染不正确的原因

您还应该像以前一样监视
视图
实例。
PromptView
的定义确实为原型添加了一个
answerYes
方法,是的,但是您想要监视的是视图实例,而不是原型


如果您监视原型的方法,那么每次在测试中尝试使用此视图时,
answerYes
方法将是监视,而不是实际的方法。这听起来不错,但会导致问题,因为当您多次调用此方法时,您将无法访问有效的间谍数据。它将简单地累积对该间谍的所有呼叫。如果您尝试对原型方法进行两次监视,最终可能会发现一个间谍的间谍,这将是一件奇怪的事情,可能会导致问题。

嗨,我今天遇到了同样的问题。我刚刚找到了解决方案,在创建了spyed方法(answerYes)之后,您必须刷新视图的事件才能调用新的spyed方法;):

[...] spyOn(视图“answerYes”); view.delegateEvents(); 按钮。单击(); 期望(view.answerYes).tohavebeincalled(); [...]


玩得开心

我通常喜欢假设框架代码已经做了它应该做的事情,并且只测试我对它的使用,因此我发现可以接受测试来验证事件散列。如果我发现自己为了测试我的东西而复制主干功能(比如委派事件),那么也许我离集成测试更近了一步。为了在单元测试中成为超级隔离女士,我还大量使用了原型。当然,有一个集成层来完成所有这些练习仍然很重要,但是我发现反馈循环对于试驾阶段来说太长了。

这会对
PromptView的
应答是
方法造成间谍:

spyOn(PromtView.prototype, 'answerYes');

如果你使用间谍软件有困难,你可以考虑创建间谍。比如:

var eventSpy;
eventSpy = jasmine.createSpy('eventSpy');
view.$el.on('myCustom:event', eventSpy);

你为什么要监视原型方法?您有一个视图实例,并且正在针对该实例进行测试。你应该监视该实例。我认为可能需要这样做的唯一原因是,当我使用view时,测试从未通过。回答是瑞克关于更改结构的提示很好,但除了在该实例上声明视图之外,测试中没有实质性的更改。然而,当我运行这个测试时,我仍然得到一个警报,而不是抛出间谍执行。这个期望也失败了,我不明白为什么。主干绑定是否会以某种方式影响结果?这很有帮助!但是,有没有更好的方法,或者当我监视视图的方法时,是否总是必须调用delegateEvents()?(标准做法?)非常感谢!经过几个小时的反复试验,我找到了这篇文章。FWIW这可用于
Sinon.stub()
var eventSpy;
eventSpy = jasmine.createSpy('eventSpy');
view.$el.on('myCustom:event', eventSpy);