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

时间:2013-09-18 07:20:01

标签: unit-testing events asynchronous mocha chai

我想知道什么是正确的方法。首先是测试代码。

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 个答案:

答案 0 :(得分:2)

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

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

如果我理解正确,你担心的是这并没有测试回调没有被调用两次。

一般来说,很难测试事情是否会发生。例如,您要等多久才能看到它是否第二次被调用? 2秒? 2小时?您确实需要使用您对正在测试的代码的理解来了解所需的测试。单元测试不应该是完整的黑盒测试。

我不会测试它没有被调用两次,除非我知道底层代码可能会以导致它被调用两次的方式中断。