使用Jest重置单个模块

45

jest.resetModules()可以清除所有模块的require缓存,但有没有一种方法可以仅清除单个模块的缓存?无法使用require.cache,因为Jest似乎会绕过它。

我正在测试一个有状态的Node模块(即它依赖于多次调用require返回相同的实例)。为了进行测试,我需要重置模块的状态以测试不同的场景。 jest.resetModules()可以工作,但是我需要重新require一些其他不需要重置的模拟模块。


7
目前来看,在源代码中这是不可能的。resetModules 完全清空了 _moduleRegistry 并且你无法从测试环境内部访问它。我建议在上下文中添加一个新的方法,可以从模块注册表中删除单个模块。我建议在 repo 上开启一个问题,希望他们能够更新 Jest 以支持这个功能。 - Arcath
如果有意义的话,您可以将具有状态的模块隔离并使用 resetModules() 进行单独测试。 - Gabriel Bleu
也许你可以像这样加载单个模块:jest.mock( '../moduleName', () => { const myModule = importFresh('/path/to/module') }, {virtual: true}, );?这将允许您加载模块的新副本,从而有效地重置模块以进行测试。 importFresh 来自 https://github.com/sindresorhus/import-fresh - Mrchief
根据这个帖子 https://github.com/facebook/jest/issues/6174,似乎这仍然是一个未解决的问题/改进。此外,有一个用于范围模块初始化的开放式 PR。请在此处检查:https://github.com/facebook/jest/pull/6701 然而,目前还没有成熟并且可以使用的东西... - Rick
Jest创建了自己的require钩子,主要用于保持全局require缓存的清洁和避免副作用。从你所做的事情来看,听起来你只需要模拟你想要使用的模块,然后确保在describe块结束时清除它,你永远不应该让模拟模块留在那里供其他测试使用。如果你正确地设置和撤销你的模拟,你就不会遇到这个问题。你能提供一个更好的例子吗? - icirellik
2个回答

19

如问题所述,jest.resetModules() 会重置模块缓存,在你的模块保留一些本地状态且需要在测试之间清除该状态时非常有用。

然而,resetModules 的问题在于它会重置所有内容,但有时您只想重置其中一些模块。

从 Jest 24 开始,您现在可以使用 jest.isolateModules 来实现此目的。

假设您有一个保留状态的模块:

module.js

exports.a = 1
exports.add = function (a) {
  return exports.a += a;
}

模块.测试.js

test('adds 1 to counter', () => {
  jest.isolateModules(() => {
    const myModule = require('./module');
    expect(myModule.add(1)).toBe(2);
    expect(myModule.add(1)).toBe(3);
  });
});

test('adds 2 to counter', () => {
  jest.isolateModules(() => {
    const myModule = require('./module');
    expect(myModule.add(2)).toBe(3);
    expect(myModule.add(2)).toBe(5);
  });
});

基本上,在每次jest.isolateModules()调用之后,下一次要求该模块时,它将具有全新的状态。


19
我们能否得到一个更详细的例子?这类似于Jest文档,我认为它没有清楚地说明正在发生什么或如何使用它。 - ElFik
同意@ElFik的观点。有人可以进一步阐述这个答案吗? - CoryDorning
1
用更好的例子扩展了答案。 - Farid Nouri Neshat
有趣的一点是,当使用 jest.isolateModules()jest.resetModules() 时,测试文件不会被视为从测试文件直接引用的模块的 module.parent。其他文件仍然具有正确的 module.parent - Garrett Motzner

9

这是一个关于在测试文件中使用模块(包括工厂)进行模拟和还原的示例

describe("some tests", () => {
  let subject;

  describe("with mocks", () => {
    beforeAll(() => {
      jest.isolateModules(() => {
        jest.doMock("some-lib", () => ({ someFn: jest.fn() })); // .doMock doesnt hoist like .mock does when using babel-jest
        subject = require('./module-that-imports-some-lib');
      });
    });

    // ... tests when some-lib is mocked
  });

  describe("without mocks - restoring mocked modules", () => {
    beforeAll(() => {
      jest.isolateModules(() => {
        jest.unmock("some-lib");
        subject = require('./module-that-imports-some-lib');
      });
    });

    // ... tests when some-lib is NOT mocked

  });
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接