javascript - Probar la aplicación backbone.js con jasmine: ¿cómo probar los enlaces de modelos en una vista?
view (6)
Deberías considerar mirar a Sinon.js. Podría apagar / simular la llamada render () y ni siquiera tener que preocuparse por ''someOtherFunction ()''.
Tuve algunas tribulaciones interesantes al tratar de probar si las vistas estaban vinculadas correctamente a los eventos. En la red troncal, por lo general, nos unimos a los eventos en el método de inicialización, utilizando algo en la línea de: something.bind("change", this.render);
. En mi prueba, quiero asegurarme de que este enlace esté configurado, por lo que hice lo siguiente:
this.myView = new MyView();
spyOn(this.myView, "render");;
this.legendView.groupData.trigger("change");
expect(this.legendView.render).toHaveBeenCalled();
Pero, eso no funcionará. Debido a que la vinculación se produce en la función de inicialización de MyView, el evento se vincula a la función de renderización de myView EN ESE MOMENTO. Entonces, cuando agrega su espía, envuelve la función de renderización y la vuelve a colocar en su lugar en myView.render. Pero el cierre creado por el primer enlace todavía existe, y estamos totalmente atados. Entonces, ¿qué podemos hacer al respecto? Lo que hice, es mover mis llamadas de enlace a una función separada, algo como:
myView = Backbone.View.extend({
initialize: function(){
_.bindAll(this, "render");
this.initialize_model_bindings();
},
initialize_model_bindings: function(){
something.bind("change", this.render);
},
render: function(){ //... }
});
y mi prueba entonces parece:
this.myView = new MyView();
spyOn(this.myView, "render");
this.myView.initialize_model_bindings();
this.legendView.groupData.trigger("change");
expect(this.legendView.render).toHaveBeenCalled();
Esto funciona, pero estoy buscando una mejor solución. Gracias
En lugar de espiar la devolución de llamada, puedes intentar espiar algo. A continuación, la prueba que vinculación se llama w / los argumentos apropiados. Esto está funcionando para mí hasta ahora. Estoy usando sinon.js en lugar de los espías incorporados de jasmine. sinon.js hace que sea un poco más fácil probar los argumentos pasados a una llamada de método en una pila de llamadas del mismo método (por ejemplo, un montón de llamadas para enlazar en una vista init). Así que no he probado esta idea solo con jazmín, pero creo que debería ser posible.
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)
Y 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
Esto puede estar muy relacionado con las funciones internas de Backbone, pero puede verificar la cadena de devolución de llamada manualmente:
expect(this.legendView.groupData._callbacks[''change'']).toContain(this.myView.render)
He logrado lograr esto utilizando prototipos de parches. Antes de crear la instancia de la vista, spyOn
el prototipo del constructor.
spyOn(MyView.prototype, ''changeSelected'');
var view = new MyView();
view.selectSomething();
expect(view.changeSelected).toHaveBeenCalled();
Me encontré con el mismo problema y cambié mi código de Vistas desde:
this.model.on(''change'', this.render, this);
a:
this.model.on(''change'', function () {
this.render();
}, this);
Y mis pruebas de jazmín funcionaron como se esperaba.
Resolví este problema espiando una función llamada por mi función de render. Así que en tu ejemplo:
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 */ }
});
la prueba se ve como
this.myView = new MyView();
spyOn(this.myView, "someOtherFunction");
this.myView.something.trigger("change");
expect(this.myView.someOtherFunction).toHaveBeenCalled();
Luego escribí una prueba por separado para lo que sea que haga alguna otra función.