开玩笑嘲笑测试之间出血,重置并不能解决问题

Ada*_*tle 5 javascript testing jestjs

测试两个模块,helper其中使用render. 有可能render抛出,所以我在 中处理它helper,并且我希望进行测试以确保其按预期工作。

当我最初编写测试时,我在测试本身中编写了该测试所需的内容,包括模拟,使用jest.doMock. 一旦所有测试通过,我想重构以尽可能共享模拟。

所以这段代码效果很好:

test('throws', async () => {
    jest.doMock('./render', () => jest.fn(async () => { throw new Error('mock error'); }));

    const helper = require('./helper');

    expect(async () => { helper(); }).rejects.toThrow('mock error');
    expect(log_bug).toHaveBeenCalled();
});

test('succeeds', async () => {
    jest.doMock('./render', () => jest.fn(async () => 'rendered result'));

    const helper = require('./helper');

    expect(await helper()).toEqual(true); //helper uses rendered result but doesn't return it
    expect(log_bug).not.toHaveBeenCalled();
});
Run Code Online (Sandbox Code Playgroud)

然而,这些并不是唯一的两个测试,到目前为止,模拟渲染的大多数其他测试都希望它返回成功状态。我尝试将成功用例重构为文件,如下__mocks__/render.js所示:

// __mocks__/render.js
module.exports = jest.fn(async () => 'rendered result');
Run Code Online (Sandbox Code Playgroud)

然后将我的测试重构为更干燥:

//intention: shared reusable "success" mock for render module
jest.mock('./render');

beforeEach(() => {
    jest.resetModules();
    jest.resetAllMocks();
});

test('throws', async () => {
    //intention: overwrite the "good" render mock with one that throws
    jest.doMock('./render', () => jest.fn(async () => { throw new Error('mock error'); }));

    const helper = require('./helper');

    expect(async () => { await helper(); }).rejects.toThrow('mock error');
    expect(log_bug).toHaveBeenCalled();
});

test('succeeds', async () => {
    //intention: go back to using the "good" render mock
    const helper = require('./helper');
    expect(await helper()).toEqual(true); //helper uses rendered result but doesn't return it
    expect(log_bug).not.toHaveBeenCalled();
});
Run Code Online (Sandbox Code Playgroud)

使用此更新的测试代码,错误记录测试仍然按预期工作 - 模拟被覆盖以导致其抛出 - 但对于下一个测试,错误会再次抛出。

如果我颠倒这些测试的顺序,使模拟覆盖放在最后,那么失败就不会发生,但这显然不是正确的答案。

我究竟做错了什么?为什么我在用 覆盖它后无法让我的模拟正确重置doMock?doMock 文档确实说明了我正在尝试做的事情,但它们没有显示将其与正常的手动模拟混合。

Ada*_*tle 1

啊哈!我不断挖掘并发现这个有点类似的 Q+A,这促使我尝试这种方法,而不是使用jest.doMock在测试内部覆盖:

//for this one test, overwrite the default mock to throw instead of succeed
const render = require('./render');
render.mockImplementation(async () => {
    throw new Error('mock error');
});
Run Code Online (Sandbox Code Playgroud)

这样,无论运行顺序如何,测试都会通过!