Почему этот шпион Синон не вызывается, когда я запускаю этот тест?

У меня есть модель позвоночника:

class DateTimeSelector extends Backbone.Model

  initialize: ->
    @bind 'change:date', @updateDatetime
    @bind 'change:time', @updateDatetime

  updateDatetime: =>
    # do some stuff with the sate and time

И у меня есть несколько тестов для этого кода с использованием jasmin и sinon.js

describe "DateTimeSelector", ->
  beforeEach ->
    @datetime = new DateTimeSelector()

    describe "updateDatetime", ->
      beforeEach ->
        @updateSpy = sinon.spy(@datetime, 'updateDatetime')

      afterEach ->
        @datetime.updateDatetime.restore()

      # passes
      it "should be called when we call it", ->
        @datetime.updateDatetime()
        expect(@updateSpy).toHaveBeenCalledOnce()

      # fails
      it "should be called when we trigger it", ->
        @datetime.trigger 'change:date'
        expect(@updateSpy).toHaveBeenCalled()

      # fails
      it "should be called when we set the date", ->
        @datetime.set { date: new Date() }
        expect(@updateSpy).toHaveBeenCalled()

Кажется, это работает, когда я использую его в браузере, но я не могу пройти тесты. Кто-нибудь может просветить меня?

2 ответа

Решение

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

Чтобы убедиться, что привязка события на самом деле указывает на упакованную шпионскую функцию, вы должны создать шпиона перед созданием объекта модели (то же самое происходит, если вы тестируете представления). Для этого создайте шпиона по прототипу."Метод" класса:

в разделе beforeEach -> before @datetime = new DateTimeSelector () создайте шпиона: @updateSpy = sinon.spy (DateTimeSelector.prototype, 'updateDatetime')

Обязательно измените раздел afterEach ->, где вы вернете прототип обратно в нормальное состояние, например так: @ updateSpy.restore ()

это должен быть ваш код:

describe "DateTimeSelector", ->
  beforeEach ->
    @updateSpy = sinon.spy(DateTimeSelector.prototype, 'updateDatetime')
    @datetime = new DateTimeSelector()

  afterEach ->
    @updateSpy.restore()

  # passes
  it "should be called when we call it", ->
    @datetime.updateDatetime()
    expect(@updateSpy).toHaveBeenCalledOnce()

  # should pass now
  it "should be called when we trigger it", ->
    @datetime.trigger 'change:date'
    expect(@updateSpy).toHaveBeenCalled()

  # should pass now
  it "should be called when we set the date", ->
    @datetime.set { date: new Date() }
    expect(@updateSpy).toHaveBeenCalled() 

Кстати, если вы используете плагин jasmin-sinon.js, то ваш синтаксис в порядке

Вы смешиваете насмешливый синтаксис жасмина и синона.

В вашем прохождении теста ваш шпион Синон выставляет собственность calledOnce но вы используете функцию жасмина toHaveBeenCalledOnce(), Эта функция не существует в шпионских шпионах, так что по существу никакого утверждения не происходит.

В ваших неудачных тестах вы вызываете функцию жасмина шпиона toHaveBeenCalled() на твоего синона шпиона. Жасмин имеет собственный синтаксис для создания шпиона: spyOn(obj, 'method');

Другие вопросы по тегам