Тестирование приложения backbone.js с помощью jasmine - как проверить привязки модели к представлению? - PullRequest
20 голосов
/ 24 июня 2011

У меня были некоторые интересные трудности при попытке проверить, правильно ли привязаны представления к событиям.В магистрали мы обычно привязываемся к событиям в методе initialize, используя что-то вроде: something.bind("change", this.render);.В своем тесте я хочу убедиться, что эта привязка настроена, поэтому я сделал следующее:

this.myView = new MyView();
spyOn(this.myView, "render");;
this.legendView.groupData.trigger("change");
expect(this.legendView.render).toHaveBeenCalled();

Но это не сработает.Поскольку связывание происходит в функции инициализации MyView, событие get привязывается к функции рендеринга myView в ТО ВРЕМЯ.Поэтому, когда вы добавляете своего шпиона, он оборачивает функцию рендеринга и устанавливает его обратно в myView.render.Но замыкание, созданное первым связыванием, все еще существует, и мы полностью замерзли.Так что мы можем с этим поделать?Что я сделал, так это переместил мой вызов связывания в отдельную функцию, что-то вроде:

myView = Backbone.View.extend({
initialize: function(){
    _.bindAll(this, "render");
    this.initialize_model_bindings();
},
initialize_model_bindings: function(){
    something.bind("change", this.render);
},
render: function(){ //... }
});

, и мой тест выглядит так:

this.myView = new MyView();
spyOn(this.myView, "render");
this.myView.initialize_model_bindings();
this.legendView.groupData.trigger("change");
expect(this.legendView.render).toHaveBeenCalled();

Это работает, но я смотрюдля лучшего решения.Спасибо

Ответы [ 6 ]

12 голосов
/ 23 сентября 2011

Мне удалось добиться этого с помощью исправления прототипа. Перед созданием экземпляра представления spyOn прототип конструктора.

spyOn(MyView.prototype, 'changeSelected');
var view = new MyView();
view.selectSomething();
expect(view.changeSelected).toHaveBeenCalled();
5 голосов
/ 12 июля 2011

Вместо того, чтобы шпионить за обратным вызовом, вы можете попробовать что-то шпионить. Затем проверить, что связывание было названо с соответствующими аргументами. Это работает для меня до сих пор. Я использую sinon.js вместо встроенных шпионов Жасмин. sinon.js упрощает проверку аргументов, передаваемых вызову метода, в стеке вызовов одного и того же метода (например, связки вызовов для привязки в представлении init). Поэтому я не проверял эту идею без жасмина, но считаю, что это возможно.

spyOn(this.legendView.groupData, 'bind');
this.myView = new MyView();
expect(this.legendView.groupData.mostRecentCall.args).toEqual('change', this.myView.render); // example!! only works if testing a single call to bind or the last call in a series (ie mostRecentCall)

И ж / sinon.js

sinon.spy(this.legendView.groupData, 'bind');
this.myView = new MyView();
expect(this.legendView.groupData.bind.calledWith('change', this.myView.render); // works w/ any number of calls to bind
3 голосов
/ 20 июля 2011

Я решил эту проблему, следя за функцией, вызываемой моей функцией рендеринга. Итак, в вашем примере:

myView = Backbone.View.extend({
  initialize: function(){
      _.bindAll(this, "render");
      something.bind("change", this.render);
  },
  someOtherFunction: function(){},  //this function only called from render
  render: function(){ this.someOtherFunction(); /* rest of render function */ }
});

тест выглядит так:

this.myView = new MyView();
spyOn(this.myView, "someOtherFunction");
this.myView.something.trigger("change");
expect(this.myView.someOtherFunction).toHaveBeenCalled();  

тогда я написал отдельный тест для того, что делает someOtherFunction.

2 голосов
/ 01 августа 2011

Вы должны рассмотреть возможность просмотра Sinon.js. Вы можете заглушить / смоделировать вызов render () и даже не беспокоиться о функции someOtherFunction ().

1 голос
/ 08 августа 2011

Это может быть слишком тесно связано с внутренними компонентами Backbone, но вы можете проверить цепочку обратных вызовов вручную:

expect(this.legendView.groupData._callbacks['change']).toContain(this.myView.render)
0 голосов
/ 26 октября 2012

Я столкнулся с той же проблемой и изменил свой код Views с:

this.model.on('change', this.render, this);

на:

this.model.on('change', function () {
    this.render();
}, this);

И мои тесты на жасмин сработали, как и ожидалось.

...