gpt4 book ai didi

node.js - Mocha Chai Sinon 测试无法访问的 promise/async/event-emitter

转载 作者:行者123 更新时间:2023-11-28 20:11:03 27 4
gpt4 key购买 nike

我的设置使用chaisinonchai-sinonchai-as-promisedbabel 和 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 的 promise 。 (而且永远不会)

这是我的(简化的)测试文件

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 返回 promise 作为 send 的结果,我知道该怎么做,但这里不是这种情况。我所知道的是最终会发出“已发送”或“错误”事件。

我理想的语法是这样的:

expect(onError).to.eventually.have

但是,那是行不通的。只需将 expect 包装在一个新的 promise 中,我就可以获得一个无错误的版本,如下所示。但我不知道为什么会这样。

  // 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;
});
});

如果我能以公开内部 promise 的方式重构代码,那么这将很容易解决。我在其他情况下这样做过无数次。然而,我的问题是非常具体如何解决这个精确模式;即如何测试无法访问的 promise 或异步代码的副作用,特别是当我无法重构代码以公开 promise 时围绕事件发射器。

我至少尝试了以下方法,看看我是否可以在测试调用期望之前触发所需的发送函数以完成其所有内部回调/ promise

  • 将期望包装在 promise 中
  • 使用 sinon.useFakeTimers 控制时间
  • 在超时中包装期望
  • 在各种异步/等待模式中包装发送调用和期望

提前致谢。

编辑:

好吧,这是完全荒谬的,但这里有一个解决方案,适用于已解决和已拒绝的 promise :

it('should behave as expected already!', (done) => {
... set up for failure or success as desired
dispatcher.send();
process.nextTick(() => {
Promise.resolve().then(() => {
... expectations ...
done();
});
});
});

我认为这是可行的,因为(我完全是在猜测!)我假设抛出的错误或拒绝的 promise 会在当前 tick 中立即处理,而已解决的 promise 会在下一个 tick 中排队。所以...... process.nextTick 确保我们将在下一个滴答中排队这个函数,允许所有捕获/错误完成,并且 Promise.resolve 确保它在任何已经排队的之后排队 promise 已兑现。顺便说一句,您也可以切换顺序或 nextTick 和 promise.resolve(),它工作得很好。

NB 如果事件是真正异步发出的(例如在它们自己的 process.nextTick 中),那么您必须有一个 3 级嵌套。Promise-nextTick-promise或 nextTick-promise-nextTick。

我的话太乱了!

...不过还是比超时好 :D

最佳答案

由于测试不会等待您正在测试的代码块来解决/拒绝 promise ,因此断言将不起作用。

你的分析都是正确的,但解决的方法是解决断言中的 promise 。

我对您的代码进行了一些更改并使其正常工作。

我已经让 doSomethingAsync 返回 promise (我认为这是正确的解决方案)

//待测代码

import EventEmitter from 'events';

const doSomethingAsync = async (x) => {
return x;
};

class Dispatcher extends EventEmitter {
send(x) {
return doSomethingAsync(x)
.then((res) => {
this.emit('sent');
})
.catch((err) => {
this.emit('error', err);
});
}
}

export default Dispatcher;

//测试

选项 1:使用 await

import sinon from 'sinon';
import { expect } from 'chai';
import Dispatcher from '../dispatcher';

describe('send', () => {
let dispatcher;
let onSent;
let onError;

beforeEach(() => {
dispatcher = new Dispatcher();
onSent = sinon.stub();
onError = sinon.stub();
dispatcher.on('sent', onSent);
dispatcher.on('error', onError);
});

it('Test 1: should emit "error" on sendFn error instead of "sent"', async () => {
await dispatcher.send('hello');
expect(onSent.callCount).to.equal(1);
expect(onError.callCount).to.equal(0);
});
});

//结果

yarn run spec

send ✓ should emit "error" on sendFn error instead of "sent"

1 passing (1s)

✨ Done in 4.18s.

选项 2:有 promise

在测试中,您可以看到我在 dispatcher.send 上使用 await,或者您也可以使用 promises 断言,如下所示

it('Test 2: should emit "error" on sendFn error instead of "sent"', () => {
let error = false;
dispatcher.send('hello').then(() => {
expect(onSent.callCount).to.equal(1);
expect(onError.callCount).to.equal(0);
}).catch(() => {
error = true;
})
expect(error).to.equal(false);
});

PS:- 如果您不想返回 promise,那么第一个测试用例(使用 await 的那个)将通过,第二个将失败。

关于node.js - Mocha Chai Sinon 测试无法访问的 promise/async/event-emitter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43472844/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com