单元测试 Backbone 模型保存句柄

unit test Backbone model save handle

我对 submit 方法有看法。如何编写单元测试以检查事件是否在以下代码中触发

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

注意:我不想检查是否调用成功

尝试:

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 

编辑 第二次尝试(成功但不确定方法是否正确)

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

进行单元测试时,需要对所涉及的单元进行决策。 When/where 测试开始和结束。您可能会认为重要的是代码覆盖率,它可以通过 Istanbul.

等工具计算得出

您的第一个示例将 运行 Model.save 代码,并且 立即 断言事件已触发。这意味着您将 100% 覆盖此功能。但请记住,Model.save 是 运行,您可能不希望覆盖模型。很可能这不起作用,因为 save 操作不是同步的,因此断言 运行 在代码完成之前。如果您还没有使用 sinon 的 fakeServer,那么您应该考虑一下。

您的第二个示例存根 Model.save 并且永远不会 运行 。这将为您提供 1 行代码覆盖率 (50%),但考虑到此处理程序只有一行,您需要通过这种方式询问此测试是否有任何价值。

如果您是单元测试的纯粹主义者,并且希望此单元测试只为被测函数添加覆盖范围,则以下方法可行:

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

这提供了 100% 的函数覆盖率(仍然只有 2 行,但这就是函数)。现在是同步的 Model.save 没有被调用,而是被存根。它断言函数的最终输出,事件被触发。它还会测试保存的响应是否包含在事件中。

如果你不是纯粹主义者,那就看看诗乃的fakeServer