【问题标题】:How can I test that a promise have been waited for (and not just created) using Sinon?如何使用 Sinon 测试是否已等待(而不仅仅是创建)承诺?
【发布时间】:2019-10-03 13:10:57
【问题描述】:

假设我有一个函数:

const someAction = async(): Promise<string> => {
    /* do stuff */
};

我有一些代码只需要运行此操作,而忽略结果。但我有一个错误 - 我不想让操作完成:

someAction();

相反,它应该是这样的:

await someAction();

现在,我可以检查此操作是否已运行:

const actionStub = sinon.stub(someAction);
expect(actionStub).to.have.been.calledWith();

但是,检查此承诺是否已被等待的最简洁方法是什么?

我知道如何自己实现,但我怀疑它一定已经在 sinon 或 sinon-chai 中实现了,我找不到任何东西。

【问题讨论】:

    标签: node.js sinon sinon-chai


    【解决方案1】:

    我可以肯定地说,在 sinon 或 sinon-chai 中不存在这样的东西。

    这是测试任何未使用结果的基于 Promise 的函数所固有的困难。如果使用结果,您知道必须先解决承诺,然后再继续处理所述结果。如果不是这样,事情就会变得更加复杂,并且超出了 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;
    

    当然,这里的问题是等待 any 承诺,不一定是这个特定的承诺,将通过这个测试,因为变量将在事件循环的下一步被设置,不管是什么让你等待下一步。

    例如,您可以在被测代码中使用类似这样的内容来通过:

    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)可能有一种方法可以清除那里使用的脱糖承诺。我不想对你使用的工具做太多假设,只是想确保这个想法得到传达。

    【讨论】:

    • 这是一个令人惊讶的详细答案,非常感谢!我喜欢拒绝方法,似乎它可以非常有效(并且易于实施)来防止这样的错误。感谢您提醒我在快乐路径之外测试输入的重要性。
    猜你喜欢
    • 1970-01-01
    • 2021-10-03
    • 2021-11-18
    • 2021-10-10
    • 1970-01-01
    • 1970-01-01
    • 2015-09-22
    • 2017-09-14
    • 1970-01-01
    相关资源
    最近更新 更多