我如何使用 Sinon 测试一个承诺是否已被等待(而不仅仅是创建)?
How can I test that a promise have been waited for (and not just created) using Sinon?
假设我有一个函数:
const someAction = async(): Promise<string> => {
/* do stuff */
};
我有一些代码只需要 运行 这个动作,忽略结果。但我有一个错误 - 我不想让操作完成:
someAction();
相反,应该看起来像这样:
await someAction();
现在,我可以检查这个动作是 运行:
const actionStub = sinon.stub(someAction);
expect(actionStub).to.have.been.calledWith();
但是检查这个 promise 是否已经等待的最简洁的方法是什么?
我知道如何自己实现,但我怀疑它一定已经在 sinon 或 sinon-chai 中实现了,我就是找不到任何东西。
我可以肯定地说,sinon 或 sinon-chai 中没有这样的东西。
这是在不使用结果的情况下测试任何基于承诺的函数所固有的困难。如果使用结果,您知道在继续处理所述结果之前必须解决承诺。如果不是,事情会变得更加复杂,超出 sinon 使用简单存根可以为您做的范围。
一个天真的方法是用一个假的来存根这个动作,这个假的设置一些变量(本地测试)来跟踪状态。像这样:
let actionComplete = false;
const actionStub = sinon.stub(someAction).callsFake(() => {
return new Promise((resolve) => {
setImmediate(() => {
actionComplete = true;
resolve();
});
});
});
expect(actionStub).to.have.been.calledWith();
expect(actionComplete).to.be.true;
当然,这里的问题是等待任何承诺,不一定是这个特定的承诺,将通过这个测试,因为变量将在事件循环,无论是什么原因导致您等待下一步。
例如,您可以在被测代码中使用类似这样的内容使此通过:
someAction();
await new Promise((resolve) => {
setImmediate(() => resolve());
});
一种更可靠的方法是创建两个单独的测试。一种是 promise 解决的,另一种是 promise 拒绝的。您可以测试以确保拒绝导致包含函数以相同的错误拒绝,如果那个特定的承诺不是 await
ed.
,那将是不可能的
const actionStub = sinon.stub(someAction).resolves();
// In one test
expect(actionStub).to.have.been.calledWith();
// In another test
const actionError = new Error('omg bad error');
actionStub.rejects(actionError);
// Assuming your test framework supports returning promises from tests.
return functionUnderTest()
.then(() => {
throw new Error('Promise should have rejected');
}, (err) => {
expect(err).to.equal(actionError);
});
一些断言库和扩展(可能是 chai-as-promised)可能有一种方法可以清除那里对去糖承诺的使用。我不想过多地假设您正在使用的工具,只是试图确保这个想法得到理解。
假设我有一个函数:
const someAction = async(): Promise<string> => {
/* do stuff */
};
我有一些代码只需要 运行 这个动作,忽略结果。但我有一个错误 - 我不想让操作完成:
someAction();
相反,应该看起来像这样:
await someAction();
现在,我可以检查这个动作是 运行:
const actionStub = sinon.stub(someAction);
expect(actionStub).to.have.been.calledWith();
但是检查这个 promise 是否已经等待的最简洁的方法是什么?
我知道如何自己实现,但我怀疑它一定已经在 sinon 或 sinon-chai 中实现了,我就是找不到任何东西。
我可以肯定地说,sinon 或 sinon-chai 中没有这样的东西。
这是在不使用结果的情况下测试任何基于承诺的函数所固有的困难。如果使用结果,您知道在继续处理所述结果之前必须解决承诺。如果不是,事情会变得更加复杂,超出 sinon 使用简单存根可以为您做的范围。
一个天真的方法是用一个假的来存根这个动作,这个假的设置一些变量(本地测试)来跟踪状态。像这样:
let actionComplete = false;
const actionStub = sinon.stub(someAction).callsFake(() => {
return new Promise((resolve) => {
setImmediate(() => {
actionComplete = true;
resolve();
});
});
});
expect(actionStub).to.have.been.calledWith();
expect(actionComplete).to.be.true;
当然,这里的问题是等待任何承诺,不一定是这个特定的承诺,将通过这个测试,因为变量将在事件循环,无论是什么原因导致您等待下一步。
例如,您可以在被测代码中使用类似这样的内容使此通过:
someAction();
await new Promise((resolve) => {
setImmediate(() => resolve());
});
一种更可靠的方法是创建两个单独的测试。一种是 promise 解决的,另一种是 promise 拒绝的。您可以测试以确保拒绝导致包含函数以相同的错误拒绝,如果那个特定的承诺不是 await
ed.
const actionStub = sinon.stub(someAction).resolves();
// In one test
expect(actionStub).to.have.been.calledWith();
// In another test
const actionError = new Error('omg bad error');
actionStub.rejects(actionError);
// Assuming your test framework supports returning promises from tests.
return functionUnderTest()
.then(() => {
throw new Error('Promise should have rejected');
}, (err) => {
expect(err).to.equal(actionError);
});
一些断言库和扩展(可能是 chai-as-promised)可能有一种方法可以清除那里对去糖承诺的使用。我不想过多地假设您正在使用的工具,只是试图确保这个想法得到理解。