Почему этот шпион Синон не вызывается, когда я запускаю этот тест? - PullRequest
21 голосов
/ 09 декабря 2011

У меня есть модель магистрали:

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 ]

48 голосов
/ 26 января 2012

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, то ваш синтаксис в порядке

0 голосов
/ 16 декабря 2011

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

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

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

...