【问题标题】:Testing model binding in Backbone JS with Jasmine使用 Jasmine 在 Backbone JS 中测试模型绑定
【发布时间】:2012-01-14 00:46:19
【问题描述】:

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

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

有谁知道为什么上述测试不起作用?我得到的错误是“Expected spy showNotes to have been called with ['[]'] 但它从未被调用过。”

【问题讨论】:

    标签: testing backbone.js jasmine


    【解决方案1】:

    我在有视图的地方做了类似的事情,但我无法让间谍正常工作,除非我将它添加到原型中,并且在我创建视图实例之前。

    以下是最终对我有用的方法:

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

    【讨论】:

    • 集合不再有update() 方法;它已被替换为set() 以与模型更加一致。
    【解决方案2】:

    尝试如下修改你现有的测试代码:

    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 实例中。通过将 spy 移动到原型中,您将在绑定发生之前替换它,因此 bind 闭包封装了 spy,而不是原始方法。

    【讨论】:

      【解决方案3】:

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

      那么如何测试这个。如您所知,每个间谍都有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,但有时传递的参数可以从外部访问,所以你将使用所示的方式.

      【讨论】:

        【解决方案4】:

        您的代码看起来不错,除了您将测试包装在 describe 函数和 it 函数中吗?

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

        在这一点上的总​​猜测,但由于你没有显示描述功能,这就是我所能想到的。如果没有,您必须有一个描述块才能使测试工作。

        【讨论】:

          【解决方案5】:

          你很接近;) spyOn 将函数替换为您的间谍并将间谍返回给您。 所以如果你这样做:

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

          应该可以正常工作!

          【讨论】:

          • 您可以通过分配给 Jasmine 间谍的变量或函数的原始位置来引用它们。这两种方法都不起作用。
          猜你喜欢
          • 2012-04-25
          • 1970-01-01
          • 1970-01-01
          • 2012-04-29
          • 1970-01-01
          • 2012-06-27
          • 2015-02-15
          • 2013-07-14
          • 1970-01-01
          相关资源
          最近更新 更多