SpyOn使用茉莉花的骨干视图方法

时间:2011-10-26 06:47:07

标签: view backbone.js jasmine spy

我有一个骨干视图,我想创建一个测试来确认某个元素上的click事件会调用绑定到该元素的函数。 我的观点是:

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()是间谍和观点.__ proto __。answerYes,这是我真正想要窥探的那个。

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

5 个答案:

答案 0 :(得分:54)

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

[...]

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

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

[...]

More information about delegate events

玩得开心!

答案 1 :(得分:3)

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

答案 2 :(得分:3)

这会在answerYes的{​​{1}}方法上创建间谍:

PromptView

答案 3 :(得分: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方法将是间谍,而不是实际方法。这可能听起来不错,但它会导致问题,因为当您多次调用此方法时,您将无法访问有效的间谍数据。它只会累积对那个间谍的所有调用。如果你试图对原型方法进行两次侦察,你最终可能会遇到一个间谍间谍,这可能是一件奇怪的事情,可能会引发问题。

答案 4 :(得分:0)

If you have trouble using spyOn, you could consider creating a spy. So something like:

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