SAGAR TALLA
SAGAR TALLA

Reputation: 375

unit test Backbone model save handle

I have a view with submit method. How do I write a unit test to check that the event is triggered in the following code

submit:(event) ->
    MyModel.save(null, {
        success: (model, response)=>
            @trigger('saveSuccess', response)
    })

note: I do not want to check that the success is called

Attempt:

it 'Should trigger events on save', (done) ->
    originalSave = MyModel.save
    triggerSpy = sinon.spy()
    MyModel.on('rating:saveSuccess', triggerSpy)
    stub = sinon.stub(MyModel, "save", ->
        successSpy = sinon.spy(arguments[1].success)
        originalSave.apply(MyModel, arguments);
        # want to call this line in the successSpy callback
        expect(triggerSpy.callCount).to.equal(1);
        done()
    )
    MyView.submit({})   
    expect(stub).to.have.been.called 

Edit Second Attempt (worked but not sure its the correct way)

it 'Should trigger events on save', (done) ->
    triggerSpy = sinon.spy()
    MyView.on('saveSuccess', triggerSpy)
    stub = sinon.stub(MyModel, "save", ->
        arguments[1].success()
        expect(triggerSpy.callCount).to.equal(1);
        done()
    )
    MyView.submitReval({})  
    expect(stub).to.have.been.called

Upvotes: 1

Views: 302

Answers (1)

mikeapr4
mikeapr4

Reputation: 2856

When unit testing, a decision needs to be made on the unit involved. When/where does the test begin and end. You may decide that what's important is code coverage as would be calculated by a tool like Istanbul.

Your first example will run the Model.save code, and immediately assert the event was triggered. This means you will have 100% coverage of this function. But keep in mind, Model.save is run, and you may not want coverage on the model. The chances are that this didn't work because the save operation isn't synchronous, and therefore the assertions run before the code completes. If you aren't already using sinon's fakeServer, then you should consider it.

Your second example stubs Model.save and never runs it. This will give you 1 line of code coverage (50%), but considering this handler only has a single line, you need to ask whether this test has any value this way.

If you are a unit test purist, and want this unit test to only add coverage for the function under test, the following would work:

it 'Should trigger events on save', ->
    triggerSpy = sinon.spy()
    MyModel.on('saveSuccess', triggerSpy)
    stub = sinon.stub(MyModel, "save", (attr, opts) ->
        opts.success.apply(null, [this, {}])
    )
    MyView.submit({})   
    expect(stub).to.have.been.called
    expect(triggerSpy.callCount).to.equal(1)
    expect(triggerSpy.args[0][0]).to.deep.equal({})

This provides 100% coverage of the function (still only 2 lines, but that's the function). It is synchronous now that the Model.save is not called, but stubbed. It asserts the final output of the function, the event is triggered. And it also tests that the response from the save is included in the event.

If you aren't a purist, then look at sinon's fakeServer.

Upvotes: 2

Related Questions