SpyOn метод просмотра позвоночника с использованием жасмина

У меня есть базовое представление, и я хочу создать тест, чтобы подтвердить, что событие click для некоторого элемента вызовет функцию, связанную с этим элементом. На мой взгляд:

PromptView = Backbone.View.extend({
        id:"promptPage",
        attributes:{
            "data-role":"page",
            "data-theme":"a"
        },
        events:{
            "click #btnYes":    "answerYes",
            "tap #btnYes":      "answerYes"
        },
        render: function(){
            $(this.el).html(_.template($('#promptPage-template').html(), this.model.toJSON()));

            return this;
        },
        answerYes: function(){
            alert('yes');
        }
    });

Моя спецификация:

beforeEach(function() {
            model = new PromptModel;
            view = new PromptView({model:model});
            loadFixtures('promptPage.tmpl');
        });

 it("should be able to answer a question with yes", function() {
                var button = $("#btnYes", view.render().el);
                expect(button.length).toBe(1);

                spyOn(view, 'answerYes');

                button.click();
                expect(view.answerYes).toHaveBeenCalled();

            });

Однако приведенное выше определение представления создает метод answerYes в прототипе proto, но шпион создает функцию для фактического экземпляра в представлении, поэтому в итоге я получаю представление view.answerYes(), которое является шпионом и представлением.__proto__. AnswerYes, на которую я действительно хочу шпионить.

Как я могу создать шпиона, чтобы он переопределял метод answerYes определения представления?

5 ответов

Привет у меня сегодня была такая же проблема. И я только что нашел решение, после создания spyed-метода (answerYes) вы должны обновить события представления, чтобы вызвать этот новый spyed-метод;):

[...]

    spyOn (просмотреть "answerYes");
    view.delegateEvents ();

    button.click ();
    ожидать (view.answerYes).toHaveBeenCalled ();

[...]

Больше информации о событиях делегатов

Повеселись!

Это создает шпион на answerYes метод PromptView:

spyOn(PromtView.prototype, 'answerYes');

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

TL;DR: следите за методом экземпляра, а не за прототипом.

Я думаю, вам нужно настроить тест по-другому. Есть слишком много проблем и слишком много ожиданий в it блок, и вы также загрязняете глобальное пространство имен, что может вызвать проблемы с тестами.

beforeEach(function() {
  loadFixtures('promptPage.tmpl');

  var model = new PromptModel();
  this.view = new PromptView({model:model});
  this.view.render();

  this.button = this.view.$("#btnYes");
});

it("should render the button", function(){
  expect(this.button.length).toBe(1);
});

it("should be able to answer a question with yes", function() {
  spyOn(this.view, 'answerYes');

  this.button.click();
  expect(this.view.answerYes).toHaveBeenCalled();
});

Вам не нужно строго рассчитывать на длину кнопки. Если кнопка не имеет длины (не найдена), вы получите другие сбои. Но, возможно, вы захотите, чтобы было проще понять, что представление не отображается правильно.

Вы также должны шпионить за view Например, как вы делали. Определение PromptView действительно добавляет answerYes метод к прототипу, да, но тот, за которым вы хотите следить, это экземпляр представления, а не прототип.

Если вы следите за методом прототипа, то каждый раз, когда вы пытаетесь использовать это представление в своих тестах, answerYes Метод будет шпионом, а не фактическим методом. Это может звучать хорошо, но это вызовет проблемы, так как у вас не будет доступа к действительным шпионским данным, когда вы вызываете этот метод несколько раз. Он просто накапливает все вызовы на этом шпионе. Если вы попытаетесь шпионить за прототипом дважды, у вас может получиться шпионить за шпионом, что было бы странно и могло вызвать проблемы.

Если у вас есть проблемы с использованием spyOn, вы можете подумать о создании шпиона. Так что-то вроде:

var eventSpy;
eventSpy = jasmine.createSpy('eventSpy');
view.$el.on('myCustom:event', eventSpy);
Другие вопросы по тегам