【问题标题】:How to test async function with Sinon JS?如何用 Sinon JS 测试异步功能?
【发布时间】:2020-08-11 06:56:35
【问题描述】:

下面是我想要实现的一个最小示例:我想测试 fn3() 是否被调用,如果异步函数 fn2() 已解决(当调用 fn1 时)。但是我不知何故未能使用sinon 的存根语法做到这一点。我想知道我误解了什么。

// System Under Test

export function fn1() {
    fn2().then(() => {
        fn3();
    });
}

export async function fn2() {
    return new Promise((resolve, reject) => {
        // expensive work
        resolve();
    });
}

export function fn3() {
    console.log("fn3");
}

// Test

import * as Page from "xxx";

it("test async", () => {
    // stub this async to isolate the SUT
    sinon.stub(Page, "fn2").resolves();
    const stub = sinon.stub(Page, "fn3");

    Page.fn1();

    sinon.assert.calledOnce(stub);
});


/*

    AssertError: expected fn3 to be called once but was called 0 times

      276 |         Page.fn1();
      277 |
    > 278 |         sinon.assert.calledOnce(stub);
          |                      ^
      279 |     });
      280 | });

      at Object.fail (node_modules/sinon/lib/sinon/assert.js:107:21)
      at failAssertion (node_modules/sinon/lib/sinon/assert.js:66:16)
      at Object.calledOnce (node_modules/sinon/lib/sinon/assert.js:92:13)
      at Object.<anonymous> (src/test.test.tsx:278:22)
*/

【问题讨论】:

  • 你在存根上断言 before 可能已经执行了 promise 回调。
  • 你的意思是当程序在fn1()里面遇到async函数时,它会在main函数中fork并继续进行断言,因此它在promise执行之前就断言了?跨度>
  • 有点,我不会将其描述为“分叉”,但承诺回调被添加到任务队列中,立即执行,而断言在立即执行的调用堆栈。
  • 感谢您的解释!我想我可以想出一个解决方案。

标签: javascript node.js asynchronous sinon


【解决方案1】:

正如@jonrsharpe 所建议的,您的sinon.assert.calledOnce(stub); 将在Page.fn1 中的fn2 承诺被解析之前被调用(即.then(() =&gt; { fn3(); }) 被调用),基于JavaScript“单线程,事件循环”性质。这里有一篇文章供参考:https://dev.to/lydiahallie/javascript-visualized-promises-async-await-5gke.

您可以尝试将代码更改为:

    ...

    return Page.fn1().then(() => {
      sinon.assert.calledOnce(stub);
    });
    
    ...

it("test async", async () => {
    // stub this async to isolate the SUT
    sinon.stub(Page, "fn2").resolves();
    const stub = sinon.stub(Page, "fn3");

    await Page.fn1();

    sinon.assert.calledOnce(stub);
});

这样sinon.assert.calledOnce(stub); 将在Page.fn1() 被解析后被调用。

【讨论】:

  • 谢谢,它有效!供其他人参考,也将fn1改为export async function fn1() { return fn2().then(...); };
猜你喜欢
  • 1970-01-01
  • 2021-01-18
  • 2021-02-18
  • 1970-01-01
  • 1970-01-01
  • 2021-12-29
  • 2019-11-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多