Jest 如何 mock 掉子模块中的函数?

前言

在前端开发中,我们常常需要对一些外部依赖进行模拟,比如一些接口请求或者第三方库的逻辑。为了解决这个问题,我们经常会使用 Jest 来进行单元测试,并使用其提供的 mock 功能进行模拟。但是,当我们需要模拟一个子模块中的函数时,会遇到一些问题。在本篇文章中,我们将会介绍如何使用 Jest 来 mock 掉一个子模块中的函数。

示例

我们假设有以下代码结构:

// foo.js
import { bar } from './bar';

export function foo() {
  return bar();
}

// bar.js
export function bar() {
  return 'original';
}

其中,foo.js 中的 foo 函数引用了 bar.js 中的 bar 函数。现在我们的目标是对 bar 函数进行模拟。

使用 jest.mock

Jest 提供了 jest.mock 方法来进行模拟。我们可以在 foo.test.js 中使用它来对 bar.js 进行模拟:

// foo.test.js
import { foo } from './foo';
jest.mock('./bar', () => ({
  bar: jest.fn(() => 'mocked'),
}));

describe('foo', () => {
  it('should return mocked', () => {
    const result = foo();
    expect(result).toBe('mocked');
  });
});

jest.mock 方法中,我们传入了一个模拟对象,其中包含了对 bar 函数的模拟。我们使用 jest.fn 来创建一个空的 mock 函数并将其赋给 bar 函数,进而控制其返回值为 'mocked'

接下来,我们在测试中调用 foo 函数并检查其返回值是否为 'mocked'

使用 jest.requireActual

在某些情况下,我们需要保留子模块的原始实现并仅对其中的部分函数进行模拟。为了实现这个目标,我们可以使用 jest.requireActual 方法来加载子模块的原始实现。

// foo.test.js
import { foo } from './foo';
import * as barModule from './bar';

jest.mock('./bar', () => ({
  ...jest.requireActual('./bar'),
  bar: jest.fn(() => 'mocked'),
}));

describe('foo', () => {
  it('should return mocked', () => {
    const result = foo();
    expect(result).toBe('mocked');
  });
});

首先,我们使用 import * as barModule from './bar' 来加载 bar 子模块。接着,我们在 jest.mock 方法中使用 ...jest.requireActual('./bar') 来加载子模块的原始实现,再通过 bar: jest.fn(() => 'mocked') 来重新实现 bar 函数并使其返回值为 'mocked'

使用 jest.doMock

如果我们需要在测试中动态地模拟子模块函数的行为,可以使用 jest.doMock 方法。它和 jest.mock 方法的用法类似,但是可以在运行时动态地进行模拟。

// foo.test.js
import { foo } from './foo';
import * as barModule from './bar';

describe('foo', () => {
  it('should return mocked', () => {
    jest.doMock('./bar', () => ({
      ...barModule,
      bar: jest.fn(() => 'mocked'),
    }));

    const result = foo();
    expect(result).toBe('mocked');
  });

  it('should return original', () => {
    jest.doMock('./bar', () => ({
      ...barModule,
      bar: jest.fn(() => 'mocked'),
    }));

    jest.resetModules();
    const { foo } = require('./foo');
    const result = foo();
    expect(result).toBe('original');
  });
});

在第一个测试中,我们使用 jest.doMock 方法动态地模拟了 bar 函数的行为并检查其返回值是否为 'mocked'

而在第二个测试中,我们在 jest.resetModules 方法的帮助下重载了 foo.jsbar.js 子模块。这样一来,我们就能够得到原始实现中的 bar 函数并检查其返回值是否为 'original'

总结

在本篇文章中,我们介绍了如何使用 Jest 来 mock 掉一个子模块中的函数。我们使用了 Jest 提供的 jest.mockjest.requireActual,和 jest.doMock 方法,并展示了它们的使用场景和示例。通过本文的学习,希望读者们能够更好地理解 Jest 的使用技巧,并能够灵活地运用到实际的项目中去。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65a12d4badd4f0e0ff94c70c


纠错反馈