0

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

视图如下所示:

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

测试看起来像:

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

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

4

1 回答 1

5

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

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

  1. 它不会测试事件是否正确连接。您正在测试的是回调执行了它应该做的事情,但它没有测试当您的用户与页面交互时该操作是否被实际触发。
  2. 如果您的事件处理程序需要引用event参数或测试将不起作用。

我更喜欢从事件开始测试我的观点:

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

expect(...).toEqual(...);

就像您说的那样,通常不建议在测试中操作 DOM,因此这种测试视图的方式要求view.render不将任何内容附加到 DOM。

实现这一点的最佳方法是将 DOM 操作留给负责初始化视图的代码。如果您没有el为视图设置属性(无论是在View.extend定义中还是在视图构造函数中),Backbone 将创建一个新的、分离的 DOM 节点作为view.el. 这个元素就像一个附加的节点一样工作——你可以操纵它的内容并在它上面触发事件。

所以,而不是...

View.extend({el: '#container'});

...或者...

new View({el:'#container'});

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

var view = new View();
$("#container").html(view.render().el);

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

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

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

于 2013-01-09T13:06:23.080 回答