测试驾驶骨干视图事件

Dav*_*e K 0 backbone.js jasmine

我试图使用Jasmine测试驱动视图事件,问题可能最好通过代码解释.

视图看起来像:

App.testView = Backbone.View.extend({
  events: { 'click .overlay': 'myEvent' },
  myEvent: function(e) {
    console.log('hello world')
  }
Run Code Online (Sandbox Code Playgroud)

测试看起来像:

describe('myEvent', function() {
  it('should do something', function() {
    var view = new App.testView();
    view.myEvent();
    // assertion will follow
  });
});
Run Code Online (Sandbox Code Playgroud)

问题是从不调用view.myEvent方法(没有任何日志记录到控制台).我试图避免从DOM中触发.有人有过类似的问题吗?

jev*_*lio 5

(就像我在问题中评论的那样,你的代码看起来很好并且应该可以工作.你的问题不在你发布的代码中.如果你可以扩展代码示例并提供更多信息,我们可以再看看它.接下来是更多关于测试Backbone视图的一般建议.)

像你一样调用事件处理函数是一种合法的测试策略,但它有一些缺点.

  1. 它不测试事件是否正确连接.您正在测试的是回调是否按预期执行,但它不会测试当您的用户与页面交互时实际触发的操作.
  2. 如果您的事件处理程序需要引用event参数,则测试将不起作用.

我更喜欢从事件中一直测试我的观点:

var view = new View().render();
view.$('.overlay').click();

expect(...).toEqual(...);
Run Code Online (Sandbox Code Playgroud)

就像你说的那样,在测试中操作DOM通常是不可取的,所以这种测试视图的方式要求view.render不会将任何东西附加到DOM.

实现此目的的最佳方法是将DOM操作留给负责初始化视图的代码.如果没有el为视图设置属性(在View.extend定义或视图构造函数中),Backbone将创建一个新的,分离的DOM节点view.el.此元素的工作方式与附加节点类似 - 您可以操纵其内容并在其上触发事件.

而不是......

View.extend({el: '#container'});
Run Code Online (Sandbox Code Playgroud)

...要么...

new View({el:'#container'});
Run Code Online (Sandbox Code Playgroud)

...您应该按如下方式初始化您的视图:

var view = new View();
$("#container").html(view.render().el);
Run Code Online (Sandbox Code Playgroud)

定义这样的视图有很多好处:

  1. 完全启用测试视图,而无需将其附加到DOM.
  2. 视图可重用,您可以创建多个实例并将它们呈现给不同的元素.
  3. 如果您的render方法执行一些复杂的DOM操作,则在分离的节点上执行它会更快.
  4. 从责任的角度来看,你可能会认为一个视图不应该知道它放在哪里,就像一个模型不应该知道它应该添加到哪个集合一样.这实现了更好的视图合成设计.

恕我直言,这种视图渲染模式是一般的最佳实践,而不仅仅是与测试相关的特殊情况.