Подтвердить что ты не робот

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

У меня есть модель Backbone:

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()

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

4b9b3361

Ответ 1

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

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

в разделе beforeEach → до @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, тогда ваш синтаксис прекрасен

Ответ 2

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

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

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