问题描述
在下面的例子中,我有两个函数 doTask 和 doSubTask。两者都是异步的,但由于某些业务需要,我需要使用不同的参数两次触发并忘记 doSubTask
const wait = ms => new Promise(resolve => setTimeout(resolve,ms))
const doTask = async (taskId) => {
await wait(taskId)
doSubTask(taskId * 3)
doSubTask(taskId * 5)
console.log('end task :' + taskId)
}
const doSubTask = async (subTaskId) => {
await wait(subTaskId)
console.log('end subTask :' + subTaskId)
}
doTask(2000)
如何为 doTask 编写测试用例,并断言 doSubTask 已被调用两次?
这是一个代码示例,您可以在 runkit.com
上运行它require("@fatso83/mini-mocha").install()
const sinon = require("sinon@7.5.0")
const referee = require("@sinonjs/referee")
const chai = require('chai')
chai.use(require('sinon-chai'))
const expect = chai.expect
const wait = ms => new Promise(resolve => setTimeout(resolve,ms))
const doTask = async (taskId) => {
await wait(taskId)
doSubTask(taskId * 3)
doSubTask(taskId * 5)
console.log('end task :' + taskId)
}
const doSubTask = async (subTaskId) => {
await wait(subTaskId)
console.log('end subTask :' + subTaskId)
}
const app = {
doTask,doSubTask,}
describe("stub",function () {
it("doSubTask should be called twice",async function () {
const doSubTaskSpy = sinon.spy(app,'doSubTask')
await doTask(2000)
expect(doSubTaskSpy).to.be.calledTwice()
})
})
stub
end task :2000
❌ doSubTask should be called twice (Failed with: "expecte…e been called exactly twice,but it was called 0 times")
end subTask :6000
end subTask :10000
解决方法
我们应该使用 rewire 包来要求模块和存根 doSubTask
函数。此外,我们应该使用this way来使用假定时器,并在您同时使用promise
和setTimeout
时提前。
例如
index.js
:
const wait = (ms) => new Promise((resolve) => setTimeout(resolve,ms));
const doTask = async (taskId) => {
await wait(taskId);
doSubTask(taskId * 3);
doSubTask(taskId * 5);
console.log('end task :' + taskId);
};
const doSubTask = async (subTaskId) => {
await wait(subTaskId);
console.log('end subTask :' + subTaskId);
};
const app = {
doTask,doSubTask,};
module.exports = app;
index.test.js
:
const rewire = require('rewire');
const sinon = require('sinon');
describe('stub',function () {
let clock;
before(() => {
clock = sinon.useFakeTimers();
});
after(() => {
clock.restore();
});
it('doSubTask should be called twice',async function () {
const doSubTaskStub = sinon.stub();
const mod = rewire('./');
mod.__set__('doSubTask',doSubTaskStub);
const promise = mod.doTask(2000);
clock.tick(2010);
await promise;
sinon.assert.calledTwice(doSubTaskStub);
sinon.assert.calledWithExactly(doSubTaskStub,6000);
sinon.assert.calledWithExactly(doSubTaskStub,10000);
});
});
测试结果:
stub
end task :2000
✓ doSubTask should be called twice (738ms)
1 passing (743ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 84.62 | 100 | 75 | 81.82 |
index.js | 84.62 | 100 | 75 | 81.82 | 11-12
----------|---------|----------|---------|---------|-------------------