我如何使用 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 拒绝的。您可以测试以确保拒绝导致包含函数以相同的错误拒绝,如果那个特定的承诺不是 awaited.

,那将是不可能的
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)可能有一种方法可以清除那里对去糖承诺的使用。我不想过多地假设您正在使用的工具,只是试图确保这个想法得到理解。