[英]Get sinon to resolve a promise when stubbed function is called
I have a set of integration tests for message queueing code (over a real RabbitMQ).我有一组消息队列代码的集成测试(通过真正的 RabbitMQ)。 The tests are verifying that the correct use case is triggered when a specific message arrives.测试正在验证当特定消息到达时是否触发了正确的用例。
it("should trigger the use case", () => {
const stub = sinon.stub(app, 'useCaseToTrigger').resolves();
await publishMessage({ id: "SOME_ID" })
// FAIL - Message isn't processed yet.
stub.should.have.been.calledWith(match({id: "SOME_ID" }))
})
This doesn't work.这行不通。 The await
statement waits for the message to be published, but says nothing of when the message is processed. await
语句等待消息被发布,但没有说明消息何时被处理。
I can add a delay, but that quickly becomes a huge waste of time (if there are multiple tests).我可以添加一个延迟,但这很快就会浪费大量时间(如果有多个测试)。
it("should trigger the use case", () => {
const stub = sinon.stub(app, 'useCaseToTrigger').resolves();
await publishMessage({ id: "SOME_ID" })
await new Promise(r => setTimeout(r, 100));
// PASS - the message has been processed before the verification
stub.should.have.been.calledWith(match({id: "SOME_ID" }))
})
But if I make the stubbed function resolve a promise when called, I can get my test to work without any undue delay.但是,如果我让存根函数在调用时解决一个承诺,我可以让我的测试工作而不会出现任何不当延迟。
it("should trigger the use case", () => {
const promise = new Promise(r => {
sinon.stub(app, "useCaseToTrigger").callsFake(() => {
setImmediate(() => { r(); }) // Push to the end of the event loop
return Promise.resolve();
})
})
await publishMessage({ id: "SOME_ID" })
await promise;
// PASS - Message processed before continuing test
app.useCaseToTrigger.should.have.been.calledWith(match({id: "SOME_ID" }))
})
This does become a bit cumbersome to deal with (and probably not the easiest to read either).处理起来确实有点麻烦(而且可能也不是最容易阅读的)。 But it also gives eslint floating promises warnings.但它也给出了 eslint 浮动承诺警告。 So to avoid those warnings, I need to rewrite it to:因此,为了避免这些警告,我需要将其重写为:
it("should trigger the use case", () => {
await Promise.all([
new Promise(r => {
sinon.stub(app, "useCaseToTrigger").callsFake(() => {
setImmediate(() => { r(); }) // Push to the end of the event loop
return Promise.resolve();
})
}),
publishMessage({ id: "SOME_ID" })
]);
// PASS - Message processed before continuing test
app.useCaseToTrigger.should.have.been.calledWith(match({id: "SOME_ID" }))
})
Is there a way to make this cleaner.有没有办法让这个更干净。
I think you can use an empty promise to await, so the app logic eventually resolves that promise when it is called.我认为您可以使用空承诺来等待,因此应用程序逻辑最终会在调用时解决该承诺。 Sinon provides a promise fake that makes this a bit easier than creating a new Promise
with an external reference to the resolve
function. Sinon 提供了一个假的 promise ,这使得这比使用对resolve
函数的外部引用创建一个new Promise
更容易。
const p = sinon.promise()
const stub = sinon.stub(app, 'useCaseToTrigger').callsFake(p.resolve)
await publishMessage({ id: "SOME_ID" })
await p
sinon.assert.calledWith(stub, { id: "SOME_ID" })
It looks like sinon .resolves()
uses Promise.resolve
at the time of the stub call, so it doesn't have a reference to the eventual promise at stub creation, otherwise a stub.promise
type of reference might have been useful here to avoid the additional promise setup.看起来 sinon .resolves()
在存根调用时使用Promise.resolve
,因此它在存根创建时没有对最终承诺的引用,否则stub.promise
类型的引用可能在这里有用避免额外的承诺设置。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.