为什么Jest仍然需要一个模拟模块?

mfpqipee  于 12个月前  发布在  Jest
关注(0)|答案(2)|浏览(147)

我使用Jest模拟一个模块,因为它包含不应该在测试中运行的代码。但是,我可以从输出中看到模块中的代码正在运行。

// foo.js
console.log('Hello')

// test.js
jest.mock('./foo')
const foo = require('./foo')

test.todo('write some tests')

控制台输出

PASS  test.js
  ✎ todo 1 test

console.log foo.js:1
Hello

这是怎么回事

g6baxovj

g6baxovj1#

这让我犯了好几次错。
如果你没有为jest.mock提供一个mock实现,它将返回一个对象,该对象镜像了mocked模块的导出,但每个函数都被mock jest.fn()替换。这是相当整洁的,因为它往往是你想要的。但是为了确定模块的导出,它必须先require它。这就是导致console.log运行的原因。
两种可能的解决方案:

  • 不要在模块的顶层运行代码:而是导出运行代码的函数。
  • 提供您自己的模拟实现,这样它就不需要内省模块jest.mock('./foo', () => {})
brc7rcf0

brc7rcf02#

Jest仍然执行自动锁的模块,因为这就是自动锁的工作方式。
它尝试执行模块脚本并分析结果对象属性,而不是静态代码分析。
结果对象属性(通常是函数)被用作“蓝图”,以创建具有相同属性但具有模拟值的模拟模块。
看看Jest的模拟生成代码:

_generateMock(from, moduleName) {
const modulePath =
  this._resolver.resolveStubModuleName(from, moduleName) ||
  this._resolveModule(from, moduleName, {
    conditions: this.cjsConditions
  });

if (!this._mockMetaDataCache.has(modulePath)) {
  // This allows us to handle circular dependencies while generating an
  // automock
  this._mockMetaDataCache.set(
    modulePath,
    this._moduleMocker.getMetadata({}) || {}
  ); // In order to avoid it being possible for automocking to potentially
  // cause side-effects within the module environment, we need to execute
  // the module in isolation. This could cause issues if the module being
  // mocked has calls into side-effectful APIs on another module.

  const origMockRegistry = this._mockRegistry;
  const origModuleRegistry = this._moduleRegistry;
  this._mockRegistry = new Map();
  this._moduleRegistry = new Map();
  const moduleExports = this.requireModule(from, moduleName); // Restore the "real" module/mock registries

  this._mockRegistry = origMockRegistry;
  this._moduleRegistry = origModuleRegistry;

  const mockMetadata = this._moduleMocker.getMetadata(moduleExports);

  if (mockMetadata == null) {
    throw new Error(
      `Failed to get mock metadata: ${modulePath}\n\n` +
        'See: https://jestjs.io/docs/manual-mocks#content'
    );
  }

  this._mockMetaDataCache.set(modulePath, mockMetadata);
}

在这段代码中,'真实的'模块代码将在线执行

const moduleExports = this.requireModule(from, moduleName);

正如Tamlyn的回答中所提到的,可以通过手动模拟实现来避免自动锁。

相关问题