如何使用 Sinon JS 测试异步函数?
How to test async function with Sinon JS?
下面是我想要实现的最小示例:我想测试如果异步函数 fn2()
已解析(调用 fn1
时),将调用 fn3()
。但不知何故,我没能用 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)
*/
正如@jonrsharpe 所建议的那样,您的 sinon.assert.calledOnce(stub);
将在 Page.fn1
内的 fn2
承诺解决之前被调用(即 .then(() => { 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);
});
以便在 Page.fn1()
解决后调用 sinon.assert.calledOnce(stub);
。
下面是我想要实现的最小示例:我想测试如果异步函数 fn2()
已解析(调用 fn1
时),将调用 fn3()
。但不知何故,我没能用 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)
*/
正如@jonrsharpe 所建议的那样,您的 sinon.assert.calledOnce(stub);
将在 Page.fn1
内的 fn2
承诺解决之前被调用(即 .then(() => { 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);
});
以便在 Page.fn1()
解决后调用 sinon.assert.calledOnce(stub);
。