20

ビューがイベントに正しくバインドされているかどうかをテストしようとすると、いくつかの興味深い問題が発生しました。バックボーンでは、通常、次の行に沿って何かを使用して、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の初期化関数で発生するため、イベントはその時点でmyViewのレンダリング関数にバインドされます。したがって、スパイを追加すると、render関数がラップされ、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();

これは機能しますが、より良い解決策を探しています。ありがとう

4

6 に答える 6

12

私はプロトタイプパッチを使用してこれを達成することができました。ビューのインスタンスを作成する前にspyOn、コンストラクターのプロトタイプ。

spyOn(MyView.prototype, 'changeSelected');
var view = new MyView();
view.selectSomething();
expect(view.changeSelected).toHaveBeenCalled();
于 2011-09-23T14:08:48.237 に答える
5

コールバックをスパイする代わりに、something.bindをスパイしてみてください。次に、適切な引数を使用してバインドが呼び出されたことをテストします。これは今のところ私のために働いています。ジャスミンの組み込みスパイの代わりにsinon.jsを使用しています。sinon.jsを使用すると、同じメソッド呼び出しのスタック内のメソッド呼び出しに渡される引数をテストするのが少し簡単になります(たとえば、ビューの初期化でバインドする一連の呼び出し)。だから私はジャスミンだけでこのアイデアをテストしていませんが、それは可能であるはずだと信じています。

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
于 2011-07-11T20:36:37.303 に答える
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 */ }
});

テストは次のようになります:

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

次に、someOtherFunctionが実行するものに対して別のテストを作成しました。

于 2011-07-20T16:15:34.193 に答える
2

Sinon.jsの確認を検討する必要があります。render()呼び出しをスタブ/モックすることができ、「someOtherFunction()」について心配する必要さえありません。

于 2011-07-31T23:32:03.733 に答える
1

これはバックボーン内部と密接に関連している可能性がありますが、コールバックチェーンを手動で確認できます。

expect(this.legendView.groupData._callbacks['change']).toContain(this.myView.render)
于 2011-08-08T14:25:52.167 に答える
0

同じ問題が発生し、Viewsコードを次のように変更しました。

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

に:

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

そして、私のジャスミンテストは期待通りに機能しました。

于 2012-10-26T13:51:07.703 に答える