如何重置Jest中测试之间的模拟调用记录?

时间:2019-12-28 16:37:29

标签: javascript jestjs

我正在学习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 runOne 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用语中的“清除”和“重置”是不同的-清除只是重置计数,重置也删除了模拟实现。因此,很明显,我想要这样做,但是不幸的是,这没有什么区别。

我还能尝试什么?

1 个答案:

答案 0 :(得分:1)

您可以尝试添加:

afterEach(() => {
    jest.restoreAllMocks()
});

同样好的做法是使用beforeEach定义要重用的测试变量/模​​拟,以便为每个测试分别定义它们。