Backbone,Marionette,Jasmine:如何测试jQuery延迟事件

时间:2014-01-10 19:24:35

标签: backbone.js jasmine marionette jquery-deferred

我对Jasmine和Marionette非常陌生,并寻求一些关于如何测试的帮助,甚至是考虑测试我的应用程序的正确方法。欢迎任何指示。

我有一个Marionette控制器,用于获取我的模型,实例化我的视图并渲染它们。我使用了本页底部的方法,以便在呈现视图之前获取模型:https://github.com/marionettejs/backbone.marionette/blob/master/upgradeGuide.md#marionetteasync-is-no-longer-supported

我的控制器方法来获取模型并显示视图如下所示:

showCaseById: function(id){
  App.models.Case = new caseModel({ id: id });

  var promise = App.models.Case.fetch();
  $.when(promise).then(_.bind(this.showContentView, this));
},

如您所见,它在获取模型后调用showContentView。那个方法在这里:

showContentView: function(model){
  App.views.Body = new bodyView({
    model: App.models.Case
  });

  App.views.Body.on('case:update', this.submitCase, this);

  // this.layout is defined in the controller's initialize function
  this.layout.content.show(App.views.Body);
},

测试此功能的正确方法是什么?我想在完成p​​romise之后测试showContentView函数的调用。我应该如何分解这个规格?

感谢。

2 个答案:

答案 0 :(得分:0)

首先,窥探你的showContentView方法并声明它已被调用:

it('showCaseById', function (done) {
    var controller = new Controller();
    spyOn(controller, 'showContentView');

    controller.showCaseById('foo');
    expect(controller.showContentView).toHaveBeenCalledWith(jasmine.any(caseModel));
});

其次,我建议你把对fetch()的调用存根,这样就不会打网络了,但是现在它开始变得有点毛茸茸了:

function caseModel() {
    this.fetch = function () {
        // return a promise here that resolves to a known value, e.g. 'blah'
    };
}

现在,你可以有一个稍强的断言,但这有点不显眼,因为你正在摆弄你的依赖的内部:

expect(controller.showContentView).toHaveBeenCalledWith('blah');

通过覆盖caseModel,当你的控制器方法创建一个时,它会得到你的新版本而不是旧版本,你可以控制新版本的实现,只是为了这个测试。

有一些方法可以使这些代码更易于测试,但是看起来你刚刚开始测试我不会全部考虑。当你做更多的测试时,你肯定会为自己找到这些东西。

答案 1 :(得分:0)

首先,了解_.bind(fn, context)实际上并不调用fn很重要。相反,它返回一个函数,在调用时将调用fn()context定义fn将在内部用作this的对象。

没有必要,但您可以将showCaseById写为:

showCaseById: function(id){
  App.models.Case = new caseModel({ id: id });

  var promise = App.models.Case.fetch();
  var fn = _.bind(this.showContentView, this);
  $.when(promise).then(fn);
},

正如我所说,这是不必要的,但现在你明白_.bind()返回一个函数,而$.when(promise).then(...)接受一个函数作为它的(第一个)参数。

要回答实际问题,您可以通过添加另一个App.models.Case.fetch()语句并使用您自己选择的测试功能来确认已履行$.when(promise).then(...)承诺。

showCaseById: function(id){
  App.models.Case = new caseModel({ id: id });

  var promise = App.models.Case.fetch();
  $.when(promise).then(_.bind(this.showContentView, this));

  // start: test
  $.when(promise).then(function() {
    console.log("caseModel " + id + " is ready");//or alert() if preferred
  });
  // fin: test
},

第二个$.when(promise).then(...)不会干扰第一个console.log();相反,这两个将按顺序执行。 this.showContentView satatement将提供可靠的确认,即this.showContentView已被成功调用,并且初始渲染应该已经发生。

如果此时或之后没有呈现任何内容,则必须怀疑需要调试{{1}}。