我正在学习Jest和现代JavaScript,并试图测试一段代码。我的测试分组在describe()
容器中,我想在测试之间重置模拟(和模拟计数)。在Stack Overflow上似乎存在一些有关重置或清除模拟数据的问题,但对于我来说似乎不起作用,而且我对JS还是太陌生,无法理解可能存在的差异。
这是我的SUT(在source.js
中):
module.exports = async function(delay) {
let query;
let ok;
for (let i = 0; i < 5; i++) {
query = context.functions.execute('getNextQuery');
if (query) {
ok = context.functions.execute('runQuery', query);
if (ok) {
context.functions.execute('markQueryAsRun', query.id);
}
} else {
break;
}
// Be nice to the API
await sleep(delay);
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
};
这是测试:
const findAndRunQueries = require('./source');
describe('Some tests for findAndRunQueries', () => {
let globalMocks = {};
// context.functions.execute() becomes a mock
global.context = {
functions: {
execute: jest.fn((funcName, ...params) => {
// This calls a mock that we set up per test
return globalMocks[funcName](...params);
})
}
};
test('No queries need to be run', async () => {
// Don't need to mock other funcs if this one is falsey
setGlobalMock('getNextQuery', () => {
return null;
});
await findAndRunQueries(0);
// Ensure only getNextQuery is called
expect(getNthMockFunctionCall(0)[0]).toBe('getNextQuery');
expect(countMockFunctionCalls()).toBe(1);
});
test('One query needs to be run', async () => {
let callCount = 0;
// Return an object on the first run, null on the second
setGlobalMock('getNextQuery', () => {
if (callCount++ === 0) {
return {
something: 'fixme'
};
} else {
return null;
}
});
setGlobalMock('runQuery', (query) => {
return true;
});
setGlobalMock('markQueryAsRun', (queryId) => {
// Does not need to return anything
});
await findAndRunQueries(0);
// Ensure each func is called
expect(getNthMockFunctionCall(0)[0]).toBe('getNextQuery');
expect(getNthMockFunctionCall(1)[0]).toBe('runQuery');
expect(getNthMockFunctionCall(2)[0]).toBe('markQueryAsRun');
// We have a 4th call here, which returns null to terminate the loop early
expect(getNthMockFunctionCall(3)[0]).toBe('getNextQuery');
// Ensure there is no extra calls
expect(countMockFunctionCalls()).toBe(4);
});
function setGlobalMock(funcName, func) {
globalMocks[funcName] = func;
}
function getNthMockFunctionCall(n) {
return global.context.functions.execute.mock.calls[n];
}
function countMockFunctionCalls() {
return global.context.functions.execute.mock.calls.length;
}
});
这里有两个测试,No queries need to be run
和One query needs to be run
。错误发生在第二个错误中,我怀疑发生的情况是模拟记录在第一个测试中仍然存在,并且破坏了结果。
我已经通过单独运行此测试来确认这一点:
node node_modules/jest/bin/jest.js -t 'One query needs to be run'
但是,如果我同时运行两个测试,则:
node node_modules/jest/bin/jest.js functions/findAndRunQueries
然后我失败了:
● Some tests for findAndRunQueries › One query needs to be run
expect(received).toBe(expected) // Object.is equality
Expected: "runQuery"
Received: "getNextQuery"
53 | // Ensure each func is called
54 | expect(getNthMockFunctionCall(0)[0]).toBe('getNextQuery');
> 55 | expect(getNthMockFunctionCall(1)[0]).toBe('runQuery');
| ^
56 | expect(getNthMockFunctionCall(2)[0]).toBe('markQueryAsRun');
57 |
58 | // We have a 4th call here, which returns null to terminate the loop early
at Object.test (functions/findAndRunQueries/findAndRunQueries.test.js:55:46)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 passed, 2 total
Snapshots: 0 total
Time: 0.637s, estimated 1s
Ran all test suites matching /functions\/findAndRunQueries/i.
当我期望getNthMockFunctionCall(1)[0]
时,它表示第二项测试(getNextQuery
)中第二次调用的第一个参数是runQuery
。我认为这表明第一个测试的模拟结果仍然存在。
我尝试添加此内容:
beforeAll(() => {
jest.clearAllMocks();
});
我相信Jest用语中的“清除”和“重置”是不同的-清除只是重置计数,重置也删除了模拟实现。因此,很明显,我想要这样做,但是不幸的是,这没有什么区别。
我还能尝试什么?
答案 0 :(得分:1)
您可以尝试添加:
afterEach(() => {
jest.restoreAllMocks()
});
同样好的做法是使用beforeEach
定义要重用的测试变量/模拟,以便为每个测试分别定义它们。