【发布时间】:2017-09-14 07:58:32
【问题描述】:
我的设置使用chai、sinon、chai-sinon、chai-as-promised、babel 和 es6 语法。
我有以下(简化的)代码
// example.js
'use strict';
import EventEmitter from 'events';
class Dispatcher extends EventEmitter {
send(x) {
doSomethingAsync() // promise is NOT returned
.then(() => {
this.emit('sent');
})
.catch((err) => {
this.emit('error', err);
});
}
}
注意:doSomethingAsync 的承诺不会被返回。 (永远不会)
这是我的(简化的)测试文件
let dispatcher;
let onSent;
let onError;
beforeEach(() => {
dispatcher = new Dispatcher();
onSent = sinon.stub();
onError= sinon.stub();
dispatcher.on('sent', onSent);
dispatcher.on('error', onError);
});
describe('send', () => {
it('should emit "error" on sendFn error instead of "sent"', () => {
... set up state for failure ...
dispatcher.send(...);
... What do I do here or how do I wrap the following? ...
expect(onSent).not.to.have.been.called;
expect(onError).to.have.been.called;
});
});
如果我可以将doSomethingAsync 的承诺作为send 的结果返回,我知道该怎么做,但这里不是这样。我所拥有的只是知道最终会发出“发送”或“错误”事件。
我理想的语法应该是这样的:
expect(onError).to.eventually.have
但是,这行不通。只需将expect 包装在一个新的承诺中,我就可以获得一个无错误的版本,如下所示。但我不知道为什么会这样。
// This one works for some unknown reason!
it('should emit "send" on send success', () => {
... set up state for success ...
dispatcher.send(...);
return Promise.resolve().then(() => {
expect(onSent).to.have.been.called;
expect(onError).not.to.have.been.called;
});
});
如果我可以重构代码以暴露内部承诺,那么这将是微不足道的解决方案。在其他情况下,我已经无数次这样做了。然而,我的问题是非常具体如何解决这个 exact 模式;即如何测试无法访问的承诺或异步代码的副作用,特别是当我无法重构代码以公开承诺时,在事件发射器周围。
我至少尝试了以下方法,看看是否可以在测试调用期望之前触发所需的发送函数以完成其所有内部回调/承诺
- 将期望包装在一个承诺中
- 使用
sinon.useFakeTimers控制时间 - 在超时中包装期望
- 以各种异步/等待模式包装发送调用和期望
提前致谢。
编辑:
好的,这完全是荒谬的,但这里有一个适用于已解决和已拒绝的承诺的解决方案:
it('should behave as expected already!', (done) => {
... set up for failure or success as desired
dispatcher.send();
process.nextTick(() => {
Promise.resolve().then(() => {
... expectations ...
done();
});
});
});
我认为这是可行的,因为(我完全在猜测!)我假设抛出的错误或被拒绝的承诺会在当前滴答中立即处理,而已解决的承诺会在下一个滴答中排队。所以...process.nextTick 确保我们将在下一个滴答声中排队这个函数,允许所有捕获/错误完成,并且 Promise.resolve 确保它在任何已经排队的承诺运行后排队。顺便说一句,您还可以切换 order 或 nextTick 和 promise.resolve() ,它工作得很好。
NB 如果事件是真正异步发出的(例如在它们自己的process.nextTick 中,那么您必须有一个 3 级嵌套。Promise-nextTick-promise 或 nextTick-promise-nextTick。
我的话是乱七八糟的!
...虽然仍然比超时更好:D
【问题讨论】:
标签: node.js testing promise sinon chai