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 秒后失败。但是没有验证,它只被触发了一次。也许我需要另一个测试?因为我已经知道它至少被触发了一次,所以我可以在这个之后使用 test 和 spy 。虽然对于一个事件来说似乎太麻烦了。

另一种“肮脏”的方法可能是:

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

它可能不是真正的防弹。可能需要更大的超时时间才能确定。然而,这意味着测试将需要更长的时间来处理,这不是一个好主意。

您还有其他想法应该如何解决?

4

1 回答 1

2

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

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

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

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

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

于 2013-10-07T16:40:01.017 回答