Подтвердить что ты не робот

Тестирование приложения backbone.js с жасмином - как проверить привязки модели к представлению?

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

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

Но это не сработает. Поскольку привязка происходит в функции инициализации MyView, событие привязывается к функции рендеринга myView AT THAT TIME. Таким образом, когда вы добавляете своего шпиона, он обертывает функцию рендеринга и устанавливает ее на место в 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();

Это работает, но я ищу лучшее решение. Благодаря

4b9b3361

Ответ 1

Вместо того, чтобы следить за обратным вызовом, вы можете попробовать следить за чем-то. Затем проверьте, что bind было вызвано w/соответствующими аргументами. Это работает для меня до сих пор. Я использую 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)

И w/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

Ответ 2

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

spyOn(MyView.prototype, 'changeSelected');
var view = new MyView();
view.selectSomething();
expect(view.changeSelected).toHaveBeenCalled();

Ответ 3

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

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 */ }
});

test выглядит так:

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

тогда я написал отдельный тест для любой функции someOtherFunction.

Ответ 4

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

Ответ 5

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

expect(this.legendView.groupData._callbacks['change']).toContain(this.myView.render)

Ответ 6

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

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

в

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

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