首页 > 解决方案 > 开玩笑嘲笑测试之间流血,重置并没有解决它

问题描述

测试两个模块,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();
});

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

// __mocks__/render.js
module.exports = jest.fn(async () => 'rendered result');

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

//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();
});

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

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

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

标签: javascripttestingjestjs

解决方案


啊哈!我不断挖掘并发现这个有点相似的 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');
});

有了这个,无论它们运行什么顺序,测试都通过了!


推荐阅读