backbone.js шпион события события не вызывается с использованием jasmine.js и sinon.js - PullRequest
20 голосов
/ 02 февраля 2012

Я пытаюсь проверить нажатие кнопки, используя 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.

Ответы [ 3 ]

41 голосов
/ 24 апреля 2012

Проблема в том, что вы добавляете своего шпиона после того, как магистраль уже связала событие щелчка непосредственно с функцией addTask (это происходит во время создания представления). Поэтому ваш шпион не будет вызван.

Попробуйте прикрепить шпиона к прототипу View до того, как создадите его. Как это:

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

и затем не забудьте удалить его:

T.views.NewViewTask.prototype.addTaskSpy.restore()
0 голосов
/ 03 февраля 2012

Есть некоторые проблемы с вашим подходом. Сначала вы шпионите за своим классом, и вы хотите его протестировать, ведь юнит-тест не должен работать, потому что вы проверяете внутреннюю логику своего класса, а не его поведение. Во-вторых, и по этой причине ваш тест не пройден, вы не прикрепили свои представления в DOM. Поэтому вы либо присоединяете свой el к DOM, либо запускаете событие click непосредственно к el: $('#add_new_task', this.view.el).click().

Btw. Базовый способ создания элементов и событий связывания затрудняет написание хороших модульных тестов, потому что вы вынуждены работать с 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 и магистрали.

0 голосов
/ 03 февраля 2012
events:{
    "click" : "addTask"
},

означает, что вы связываете событие click с this.el - корневым элементом представления, в вашем случае с идентификатором new_task_section. Вам нужно привязать его к #add_new_task, которая, как я полагаю, является вашей кнопкой «Добавить задачу» - это должно исправить это!

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

Обновление:

$ ("# add_new_task") не найдет элемент, так как представление не добавлено в дерево DOM документа. используйте this.view.$('#add_new_task'), и он должен работать, так как будет искать элемент в отдельном фрагменте, сохраненном в представлении.

...