[英]How do I correctly test asynchronous stream error event handling with mocha/sinon/chai?
I am testing an async method that returns some data from a web request using the native https.request() method in NodeJS.我正在测试一个异步方法,该方法使用 NodeJS 中的本机 https.request() 方法从 web 请求中返回一些数据。 I am using mocha, chai, and sinon with the relevant extensions for each.我正在使用 mocha、chai 和 sinon 以及它们的相关扩展。
The method I'm testing essentially wraps the boilerplate https.request() code provided in the NodeJS docs in a Promise and resolves when the response 'end' event is received or rejects if the request 'error' event is received.我正在测试的方法基本上包装了 Promise 中 NodeJS 文档中提供的样板 https.request() 代码,并在收到响应“结束”事件时解析,或者在收到请求“错误”事件时解决。 The bits relevant to discussion look like this:与讨论相关的部分如下所示:
async fetch(...) {
// setup
return new Promise((resolve, reject) => {
const req = https.request(url, opts, (res) => {
// handle response events
});
req.on('error', (e) => {
logger.error(e); // <-- this is what i want to verify
reject(e);
});
req.end();
});
}
As indicated in the comment, what I want to test is that if the request error event is emitted, the error gets logged correctly.如评论中所示,我要测试的是,如果发出请求错误事件,则错误会被正确记录。 This is what I'm currently doing to achieve this:这就是我目前正在做的事情:
it('should log request error events', async () => {
const sut = new MyService();
const err = new Error('boom');
const req = new EventEmitter();
req.end = sinon.fake();
const res = new EventEmitter();
sinon.stub(logger, 'error');
sinon.stub(https, 'request').callsFake((url, opt, cb) => {
cb(res);
return req;
});
try {
const response = sut.fetch(...);
req.emit('error', err);
await response;
} catch() {}
logger.error.should.have.been.calledOnceWith(err);
});
This feels like a hack, but I can't figure out how to do this correctly using the normal patterns.这感觉就像一个黑客,但我无法弄清楚如何使用正常模式正确地做到这一点。 The main problem is I need to emit the error event after the method is called but before the promise is fulfilled, and I can't see how to do that if I am returning the promise as you normally would with mocha.主要问题是我需要在调用方法之后但在 promise 完成之前发出错误事件,如果我像通常使用摩卡咖啡一样返回 promise,我看不到该怎么做。
I should have thought of this, but @Bergi's comment about using setTimeout() in the fake gave me an idea and I now have this working with the preferred syntax:我应该想到这一点,但@Bergi 关于在假中使用 setTimeout() 的评论给了我一个想法,我现在可以使用首选语法:
it('should log request error events', () => {
const sut = new MyService();
const err = new Error('boom');
const req = new EventEmitter();
req.end = sinon.fake();
const res = new EventEmitter();
sinon.stub(logger, 'error');
sinon.stub(https, 'request').callsFake((url, opt, cb) => {
cb(res);
setTimeout(() => { req.emit('error', err); });
return req;
});
return sut.fetch(...).should.eventually.be.rejectedWith(err)
.then(() => {
logger.error.should.have.been.calledOnceWith(err);
});
});
I don't like adding any delays in unit tests unless I'm specifically testing delayed functionality, so I used setTimeout() with 0 delay just to push the emit call to the end of the message queue.除非我专门测试延迟功能,否则我不喜欢在单元测试中添加任何延迟,因此我使用了延迟为 0 的 setTimeout() 来将发出调用推送到消息队列的末尾。 By moving it to the fake I was able to just use promise chaining to test the call to the logger method.通过将它移动到假的,我能够使用 promise 链接来测试对记录器方法的调用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.