单元测试 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。
我对 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。