20

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

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();

            });

然而,上面的视图定义在原型proto上创建了 answerYes 方法,但是间谍在视图中的实际实例上创建了一个函数,所以我最终得到了一个 view.answerYes() ,它是间谍和 view.__proto__.answerYes,这是我真正想要监视的那个。

如何创建一个间谍,以便它覆盖视图定义的 answerYes 方法?

4

5 回答 5

56

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

[...]

    spyOn(view, 'answerYes');
    view.delegateEvents();

    按钮.click();
    期望(view.answerYes).toHaveBeenCalled();

[...]

有关委托事件的更多信息

玩得开心!

于 2011-10-28T14:00:22.500 回答
3

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

于 2012-11-21T15:01:51.277 回答
3

answerYes这会在 的方法上创建一个间谍PromptView

spyOn(PromtView.prototype, 'answerYes');
于 2013-07-05T14:33:51.557 回答
1

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();
});

您并不严格需要对按钮长度的期望。如果按钮没有长度(未找到),您将遇到其他故障。但是您可能希望它在那里更容易找出视图没有正确呈现。

你也应该view像你一直在做的那样监视实例。的定义PromptView确实answerYes向原型添加了一个方法,是的,但是您要监视的是视图实例,而不是原型。

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

于 2011-10-26T12:55:48.193 回答
0

如果您在使用 spyOn 时遇到问题,可以考虑创建一个间谍。所以像:

var eventSpy;
eventSpy = jasmine.createSpy('eventSpy');
view.$el.on('myCustom:event', eventSpy);
于 2015-06-25T18:20:47.733 回答