20

私はbackbone.js、jasmine.js、sinon.jsを使用してボタンクリックをテストしようとしています。しかし、次のテストケースは失敗します。私はスパイを使用して、呼び出されているかどうかを追跡しています。これを手伝ってくれませんか。

ありがとう。

新しいタスクテンプレート

<script id='new_task_template' type='text/template'>
  <input type='text' id='new_task_name' name='new_task_name'></input>
  <button type='button' id='add_new_task' name='add_new_task'>Add Task</button>
</script>

NewTaskView

T.views.NewTaskView = Backbone.View.extend({
  tagName: 'section',
  id: 'new_task_section',
  template : _.template ( $("#new_task_template").html() ),
  initialize: function(){
    _.bindAll( this, 'render', 'addTask');
  },
  events:{
    "click #add_new_task" : "addTask"
  },
  render: function(){
    $(this.el).html( this.template() );
    return this;
  },
  addTask: function(event){
    console.log("addTask");
  }
});

ジャスミンテストケース

describe("NewTaskView", function(){
  beforeEach( function(){    
    this.view = new T.views.NewTaskView();
    this.view.render();
  });

  it("should #add_new_task is clicked, it should trigger the addTask method", function(){
    var clickSpy = sinon.spy( this.view, 'addTask');
    $("#add_new_task").click();
    expect( clickSpy ).toHaveBeenCalled();
  });
});

ジャスミン出力

NewTaskView
  runEvents
    runshould #add_new_task is clicked, it should trigger the addTask method
      Expected Function to have been called.
4

3 に答える 3

41

問題は、バックボーンがクリック イベントを addTask 関数に直接バインドした後にスパイを追加することです (ビューの構築中にそれを行います)。したがって、スパイは呼び出されません。

ビューを構築するに、ビューのプロトタイプにスパイをアタッチしてみてください。このような:

this.addTaskSpy = sinon.spy(T.views.NewViewTask.prototype, 'addTaskSpy');
this.view = new T.views.NewTaskView();

そして、それを削除することを忘れないでください:

T.views.NewViewTask.prototype.addTaskSpy.restore()
于 2012-04-24T16:20:37.950 に答える
0
events:{
    "click" : "addTask"
},

this.elクリックイベントを、この場合はIDを持つビューのルート要素にバインドしていることを意味しますnew_task_section。あなたはそれをあなたの「タスクの追加」ボタンであるとバインドする必要があり#add_new_taskます-これはそれを修正するはずです!

events:{
    "click #add_new_task" : "addTask"
},

アップデート:

$( "#add_new_task")は、ビューがドキュメントDOMツリーに追加されていないため、要素を検出しません。を使用するthis.view.$('#add_new_task')と、ビューに保存されているデタッチされたフラグメント内の要素を検索するため、機能するはずです。

于 2012-02-03T02:44:19.880 に答える
0

あなたのアプローチにはいくつかの問題があります。最初に、テストしたいクラスをスパイします。これは、クラスの動作ではなく、クラスの内部ロジックをテストするため、単体テストが機能する方法ではありません。次に、それがテストが失敗する理由です。ビュー el を DOM にアタッチしていません。したがって、el を DOM にアタッチするか、クリック イベントを el: に直接発生させます$('#add_new_task', this.view.el).click()

ところで。要素を作成してイベントをバインドするバックボーンの方法では、適切な単体テストを作成するのが難しくなり、DOM と jquery を使用する必要があります。テスト可能なコードを作成するためのより良い方法は、常にすべての依存関係をコンストラクターに渡し、コードで新しいインスタンスを作成しないことです。これらのオブジェクトをテストするのが難しくなります。したがって、あなたの場合、elオブジェクトをコンストラクターにjqueryオブジェクトとして、イベントで手動で挿入する方がはるかに簡単です。このようにすると、DOM や jquery に依存せずにクラスをテストできます。

したがって、あなたの場合、コンストラクターは次のようになります。

initialize: function(){
   this.el.click(_.bind( this, 'addTask'));
}

そしてあなたのテスト:

var el = {click: function(){}};
spyOn( el, 'click');
new T.views.NewTaskView({el: el});
expect(el.click).toHaveBeenCalled(); //test the click event was bind
//call the function that was bind to the click event, 
//which is the same as trigger the event on a real DOM object
el.click.mostRecentCall.args[0]() 

結局のところ、どのアプローチがニーズに合うかを決定する必要があります。バックボーン ヘルパーを使用した無駄のないコード、または jquery、DOM、およびバックボーンへの依存度が低く、テストしやすいコード。

于 2012-02-03T10:24:34.510 に答える