使用Jasmine测试Backbone JS中的模型绑定

时间:2012-01-14 00:46:20

标签: testing backbone.js jasmine

我有一个包含模型的视图。视图从模型中侦听事件,并在触发事件后执行操作。以下是我的代码

window.Category = Backbone.Model.extend({})

window.notesDialog = Backbone.View.extend({
  initialize: function() {
    this.model.bind("notesFetched", this.showNotes, this);
  },
  showNotes: function(notes) {
    //do stuffs here
  }
})

我想使用Jasmine进行测试,下面是我的测试(不起作用)

it("should show notes", function() {
   var category = new Category;

   var notes_dialog = new NotesDialog({model: category})

   spyOn(notes_dialog, "showNotes");
   category.trigger("notesFetched", "[]");
   expect(notes_dialog.showNotes).toHaveBeenCalledWith("[]");
})

有谁知道为什么上述测试不起作用?我得到的错误是“预期的间谍showNotes被调用了['[]']但它从未被调用过。”

5 个答案:

答案 0 :(得分:7)

我在做一个类似的地方,但是我没有让间谍正常工作,除非我把它添加到原型中,然后才创建视图实例。

这最终对我有用:

view.js

view = Backbone.View.extend({
   initialize: function(){
      this.collection.bind("change", this.onChange, this);
   },
   ...
   onChange: function(){
      console.log("Called...");
   }
});

jasmine_spec.js

describe("Test Event", function(){
   it("Should spy on change event", function(){
      var spy = spyOn(view.prototype, 'onChange').andCallThrough()
      var v = new view( {collection: some_collection });

      // Trigger the change event
      some_collection.set();

      expect(spy).toHaveBeenCalled()
   });
});

我最初会考虑toHaveBeenCalled()期望,并在您完成工作后更改为toHaveBeenCalledWith() ...

2013年5月6日更新:将update()更改为set()

答案 1 :(得分:3)

尝试按如下方式修改现有测试代码:

it("should show notes", function() {
   var category = new Category;

   spyOn(NotesDialog.prototype, "showNotes");
   var notes_dialog = new NotesDialog({model: category})

   category.trigger("notesFetched", "[]");
   expect(notes_dialog.showNotes).toHaveBeenCalledWith("[]");
})

在原始代码中,您调用的方法的实例是在绑定闭包中定义的实例,而您正在监视的实例是在notes_dialog实例中。通过将间谍移动到原型,您将在绑定发生之前替换它,因此绑定闭包封装了间谍,而不是原始方法。

答案 2 :(得分:1)

使用间谍手段替换你监视的功能。因此,在您的情况下,您将使用spy替换bind函数,因此原始间谍的内部逻辑将不再调用。这就是正确的方法,因为你不想测试Backbones bind是否正常工作,但是您已使用特定的参数bind调用了"notesFetched", this.showNotes, this

那么如何测试呢。如你所知,每个间谍都有toHaveBeenCalledWith(arguments)方法。在你的情况下它应该是这样的:

expect(category.bind).toHaveBeenCalledWith("notesFetched", category. showNotes, showNotes)

那么如何测试触发器模型上的“notesFetched”将调用你的showNotes函数。 每个间谍都会保存他所调用的所有参数。您可以使用mostRecentCall.args访问最后一个。

category.bind.mostRecentCall.args[1].call(category.bind.mostRecentCall.args[2], "[]");
expect(notes_dialog.showNotes).toHaveBeenCalledWith("[]");

mostRecentCall.args[1]是绑定调用中的第二个参数(this.showNotes)。 mostRecentCall.args[2]是绑定调用中的第三个参数(this)。

由于我们测试了使用您的公共方法bind调用showNotes,您还可以直接调用您的公共方法showNotes,但有时传递的参数可以从外部访问你将使用所示的方式。

答案 3 :(得分:0)

您的代码看起来很好,除了您是否将测试包装在describe函数中,以及它的功能?


describe("show notes", function(){
  it("should show notes", function(){
    // ... everything you already have here
  });
});

此时的总猜测,但由于你没有显示描述功能,我认为这就是全部。如果你没有测试,你必须有一个描述块才能使测试工作。

答案 4 :(得分:-1)

你非常接近;) spyOn用你的间谍取代这个功能,然后给你留下间谍。 所以如果你这样做:

   var dialog_spy = spyOn(notes_dialog, "showNotes");
   category.trigger("notesFetched", "[]");
   expect(dialog_spy).toHaveBeenCalledWith("[]");

应该工作得很好!