Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is this sinon spy not being called when I run this test?

Tags:

I have a Backbone Model:

class DateTimeSelector extends Backbone.Model    initialize: ->     @bind 'change:date', @updateDatetime     @bind 'change:time', @updateDatetime    updateDatetime: =>     # do some stuff with the sate and time 

And I have some tests for that code using jasmin and 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() 

It seems to work when I use it in the browser but I can't seem to get the tests to pass. Can anyone enlighten me?

like image 744
David Tuite Avatar asked Dec 09 '11 05:12

David Tuite


People also ask

How does Sinon spy work?

The function sinon. spy returns a Spy object, which can be called like a function, but also contains properties with information on any calls made to it. In the example above, the firstCall property has information about the first call, such as firstCall. args which is the list of arguments passed.

What does Sinon spy return?

spy. Returns true if spy was called at least once with the provided arguments. Can be used for partial matching, Sinon only checks the provided arguments against actual arguments, so a call that received the provided arguments (in the same spots) and possibly others as well will return true .

How do you mock this in Sinon?

Mocks allow you to create a fake function that passes or fails depending on your needs. You can ensure it was called with certain arguments, or check how many times it was called. You must call mock() on an object.

How do you stub a function with Sinon?

The sinon. stub() substitutes the real function and returns a stub object that you can configure using methods like callsFake() . Stubs also have a callCount property that tells you how many times the stub was called. For example, the below code stubs out axios.


1 Answers

duckyfuzz, you are experiencing this problem because when you are creating the spy (which actually wraps the original function and creates a level of indirection to insert its services of tracking method invocation) the binding of the events has already taken place. Which means that even though the spy wrapped the original function the event binding references the original function and not the wrapped spy. Hence, when you test, the original function gets executed on the event trigger but the spy tracking is one level above and is not executed.

To make sure that the event binding is actually pointing to the wrapped spy function you have to create the spy before create the model object (same goes if you are testing views). To do that create the spy on the prototype."method" of the class:

in the beforeEach -> section before @datetime = new DateTimeSelector() create the spy: @updateSpy = sinon.spy(DateTimeSelector.prototype, 'updateDatetime')

be sure to change your afterEach -> section where you return the prototype back to normal, like so: @updateSpy.restore()

this should be your code:

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

BTW, if you are using jasmin-sinon.js plugin then your syntax is fine

like image 143
vadimich Avatar answered Sep 22 '22 16:09

vadimich