基于事件的单元测试失败 "done() called multiple times"
Event-based unit tests fail with "done() called multiple times"
我用 mocha
:
设置了一个简单的异步回调测试
describe('test', function () {
it('should not work', function(done) {
client.on('success', function () {
return done('client saw success message but should have errored');
});
client.on('error', function (err) {
return done();
});
});
});
想法是客户端执行一些异步操作并且应该接收错误事件。如果它收到其他任何东西,那么测试应该会失败。
不幸的是,mocha
一直在抱怨:
done() called multiple times
我做了各种各样的事情来验证这不是真的。例如,我尝试在成功处理程序中的 done
之前抛出错误,在控制到达成功处理程序时记录日志等
如何在不告诉我我正在调用 done
两次的情况下将此测试进行到 运行?我会抛出错误而不是调用 done
并显示错误消息,但这会导致测试失败并超时而不是我想要的错误。
您的测试失败了,因为您 仍在监听
测试完成.
完成的测试不会自动删除事件侦听器。
在您的下一次测试中,您将再次触发该事件,但之前的测试事件
监听器会再次被调用,因为他们仍在监听事件。
因为 done
在测试完成时已经被调用了,
他们再次开火因此你得到 done was called multiple times
.
的错误
这里有几个选项:
- 您可以在每次测试后使用命名函数删除事件侦听器。
- 您可以使用
once
侦听器。
通过命名函数删除事件侦听器:
describe('test', () => {
it('should work', done => {
const finish = err => {
done(err)
client.removeListener('success', finish)
client.removeListener('error', finish)
}
client.on('error', finish)
client.on('success', result => {
result.should.equal('foo')
// rest of tests for result...
finish()
})
client.fireEvent()
})
})
请注意,您可能需要使用 off
或 removeEventListener
而不是 removeListener
- 无论您的 client
使用哪种方法删除侦听器。
使用 once
侦听器:
或者,您可以使用 once
侦听器来侦听事件。顾名思义,此处理程序仅触发一次,因此之后无需手动删除侦听器。
describe('test', function () {
it('should work', done => {
client.once('error', done)
client.once('success', result => {
result.should.equal('foo')
// rest of tests for result...
done()
})
client.fireEvent()
})
})
警告:这些方法有一个重要的警告。他们不允许您测试 client
是否真的触发事件 一次 的边缘情况。如果 client
错误地触发 success
不止一次,您的测试也会错误地成功。我不确定你现在如何优雅地处理这个问题,但欢迎发表评论。
我用 mocha
:
describe('test', function () {
it('should not work', function(done) {
client.on('success', function () {
return done('client saw success message but should have errored');
});
client.on('error', function (err) {
return done();
});
});
});
想法是客户端执行一些异步操作并且应该接收错误事件。如果它收到其他任何东西,那么测试应该会失败。
不幸的是,mocha
一直在抱怨:
done() called multiple times
我做了各种各样的事情来验证这不是真的。例如,我尝试在成功处理程序中的 done
之前抛出错误,在控制到达成功处理程序时记录日志等
如何在不告诉我我正在调用 done
两次的情况下将此测试进行到 运行?我会抛出错误而不是调用 done
并显示错误消息,但这会导致测试失败并超时而不是我想要的错误。
您的测试失败了,因为您 仍在监听 测试完成.
完成的测试不会自动删除事件侦听器。
在您的下一次测试中,您将再次触发该事件,但之前的测试事件
监听器会再次被调用,因为他们仍在监听事件。
因为 done
在测试完成时已经被调用了,
他们再次开火因此你得到 done was called multiple times
.
这里有几个选项:
- 您可以在每次测试后使用命名函数删除事件侦听器。
- 您可以使用
once
侦听器。
通过命名函数删除事件侦听器:
describe('test', () => {
it('should work', done => {
const finish = err => {
done(err)
client.removeListener('success', finish)
client.removeListener('error', finish)
}
client.on('error', finish)
client.on('success', result => {
result.should.equal('foo')
// rest of tests for result...
finish()
})
client.fireEvent()
})
})
请注意,您可能需要使用 off
或 removeEventListener
而不是 removeListener
- 无论您的 client
使用哪种方法删除侦听器。
使用 once
侦听器:
或者,您可以使用 once
侦听器来侦听事件。顾名思义,此处理程序仅触发一次,因此之后无需手动删除侦听器。
describe('test', function () {
it('should work', done => {
client.once('error', done)
client.once('success', result => {
result.should.equal('foo')
// rest of tests for result...
done()
})
client.fireEvent()
})
})
警告:这些方法有一个重要的警告。他们不允许您测试 client
是否真的触发事件 一次 的边缘情况。如果 client
错误地触发 success
不止一次,您的测试也会错误地成功。我不确定你现在如何优雅地处理这个问题,但欢迎发表评论。