编写单元测试以检查事件是否已触发。

3
我想知道正确的方法。首先这是测试代码。
describe 'Something', ->
    it 'should trigger event', (done) ->
        spy = sinon.spy()
        instance = new Something()
        instance.on("itsdone", spy)
        instance.methodCall()
        spy.should.have.been.calledOnce
        done()

看起来很简单,但由于事件通常是异步的,所以这样做行不通。

class Something
    constructor: ->
        @events = {}
    on: (event, cb) ->
        @events[event] = new signals.Signal() unless @events[event]?
        @events[event].add cb
    methodCall: ->
        # Fire up `itsdone` event when everything else is done
        setTimeout (=> @events['itsdone']?.dispatch()), 0

这样测试显然会失败。然后我想到了这样的做法...
describe 'Something', ->
    it 'should be triggering even', (done) ->
        instance = new Something()
        instance.on("itsdone", done)
        instance.methodCall()

这个测试用例目前能够正确运行,如果事件没有触发,则在2秒后测试将失败。然而,并没有验证它是否只触发了一次。也许我需要另一个测试来验证这一点?既然我已经知道它至少触发了一次,那么可能会在这之后使用带有间谍的测试。虽然似乎为了一个事件而麻烦太多。
另一个“非常规”的方法可能是这样:
describe 'Something', ->
    it 'should be triggering even', (done) ->
        spy = sinon.spy()
        instance = new Something()
        instance.on("itsdone", spy)
        instance.methodCall()
        setTimeout ->
            spy.should.have.been.calledOnce
            done()
        , 0

这可能并不是绝对可靠的解决方案。为了确保其有效性,可能需要更长的超时时间。然而这意味着测试需要更长的处理时间,这并不是一个好主意。

你有什么其他的想法来解决这个问题吗?

1个回答

2

我认为你的第三个选择是正确的:


describe 'Something', ->
    it 'should be triggering even', (done) ->
        instance = new Something()
        instance.on("itsdone", done)
        instance.methodCall()

如果我理解正确,您的担忧是这个测试没有测试回调函数不会被调用两次。
通常情况下,很难测试某些事情不会发生。例如,您要等多久才能确定它不会第二次被调用?2秒?2小时?您需要根据被测试代码的理解来知道需要哪些测试。单元测试不应该是完全的黑盒测试。
除非我知道底层代码可能会出现问题导致它被调用两次,否则我不会测试它不会被调用两次。

好的,谢谢确认。我也已经想到了最佳解决方案。之后我放弃了事件并使用了 Promises/A :) - FredyC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接