[英]Event-based unit tests fail with “done() called multiple times”
I have a simple async callback test that I've set up with mocha
:我使用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();
});
});
});
The idea is that the client does some async operation and should receive an error event.这个想法是客户端执行一些异步操作并且应该接收一个错误事件。 If it receives anything else, then the test should fail.如果它收到其他任何东西,那么测试应该失败。
Unfortunately, mocha
keeps complaining:不幸的是, mocha
一直在抱怨:
done() called multiple times
I've done all sorts of things to verify that this is not true.我已经做了各种各样的事情来验证这不是真的。 For example, I've tried throwing an error before the done
in the success handler, logging when control reaches the success handler, etc.例如,我尝试在成功处理程序中的done
之前抛出错误,在控制到达成功处理程序时进行记录等。
How can I get this test to run without telling me I'm calling done
twice?如何在不告诉我我调用done
两次的情况下运行此测试? I would throw an error instead of calling done
with an error message, but that would cause the test to fail with a timeout instead of the error I want.我会抛出错误而不是使用错误消息调用done
,但这会导致测试失败并出现超时而不是我想要的错误。
Your tests are failing because you are still listening for events after the test is finished .您的测试失败是因为您在测试完成后仍在侦听事件。
A completed test doesn't automatically remove the event listeners.完成的测试不会自动删除事件侦听器。
On your next test you are firing the event again but previous test event listeners are called again since they are still listening for the event.在您的下一个测试中,您将再次触发该事件,但之前的测试事件侦听器将再次被调用,因为它们仍在侦听该事件。 Since done
was already called on them when that test completed, they fire again hence you get the error that done was called multiple times
.由于在测试完成时已经对它们调用了done
,因此它们再次触发,因此您会得到done was called multiple times
的错误。
Couple of options here:这里有几个选项:
once
listener.您可以使用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()
})
})
Note that you might need to use off
or removeEventListener
instead of removeListener
- whichever method your client
uses to remove a listener.请注意,您可能需要使用off
或removeEventListener
而不是removeListener
- 无论您的client
使用哪种方法来删除侦听器。
once
listener:使用once
监听器: Alternatively, you can use the once
listener to listen for events.或者,您可以使用once
侦听器来侦听事件。 Like the name suggests, this handler fires only once so there's no need to manually remove listeners afterwards.顾名思义,此处理程序仅触发一次,因此之后无需手动删除侦听器。
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()
})
})
Warning: These methods have an important caveat.警告:这些方法有一个重要的警告。 They don't allow you to test the edge case on whether your client
actually fires the event just once .它们不允许您测试边缘情况,以确定您的client
是否实际上只触发了一次事件。 If client
erroneously fires success
more than once your test would erroneously succeed as well.如果client
多次错误地触发success
,您的测试也会错误地成功。 I'm not sure how you can handle this gracefully at this time but comments are welcome.我不确定此时您如何优雅地处理这个问题,但欢迎提出意见。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.