发布于 2026-01-06 0 阅读
0

如何使用 Jest 模拟导入的 TypeScript 类

如何使用 Jest 模拟导入的 TypeScript 类

在单元测试中,迟早会遇到需要导入类并进行模拟的情况,以保持良好的测试习惯。Jest 的文档中提供了相当不错的ES6 类配置指南,但如果你直接尝试将这些指南应用于 TypeScript,就会遇到类型转换的问题。本文将快速指导你如何在使用 Jest 的情况下让 TypeScript 正常工作。如果你是 Angular 开发者,并且还没有配置 Jest,可以参考 Amadou Sall 的这篇优秀教程,它还会同时配置其他组件jest-preset-angular,这在后续工作中会很有帮助。

SoundPlayer 类

假设这是你的sound-player.ts文件:


export class SoundPlayer {
  constructor() {
    this.foo = 'bar';
  }

  playSoundFile(fileName) {
    console.log('Playing sound file ' + fileName);
  }
}
Enter fullscreen mode Exit fullscreen mode

请注意,这不是默认导出。这一点很重要,因为如果您遵循 Jest 文档,他们的示例会假设您使用的是默认导出,这在后续的模拟中会很重要。

SoundPlayer 模拟

假设你正在为另一个类(比如 `SoundPlayer`)编写单元测试,SoundPlayerConsumer并且你想模拟 `SoundPlayer` 类。如果你还没有安装ts-jest,我强烈建议你现在就把它添加到你的 Jest 配置中。

yarn add --dev ts-jest @types/jest
Enter fullscreen mode Exit fullscreen mode

正如我之前提到的,如果你使用的是 jest-preset-angular,它已经“捆绑”了 ts-jest。

有了 ts-jest,用 Jest 模拟 TypeScript 类就变得非常简单:

import { mocked } from 'ts-jest/utils';
import { SoundPlayer } from './sound-player';

jest.mock('./sound-player', () => {
  return {
    SoundPlayer: jest.fn().mockImplementation(() => {
      return {
        playSoundFile: () => {},
      };
    })
  };
});

describe('SoundPlayerConsumer', () => {
  const MockedSoundPlayer = mocked(SoundPlayer, true);

  beforeEach(() => {
   // Clears the record of calls to the mock constructor function and its methods
   MockedSoundPlayer.mockClear();

  });

  it('We can check if the consumer called the class constructor', () => {
    const soundPlayerConsumer = new SoundPlayerConsumer();
    expect(MockedSoundPlayer).toHaveBeenCalledTimes(1);
  });

}

Enter fullscreen mode Exit fullscreen mode

这其实很容易理解,但这里还有几点需要说明:

  • 与 Jest 文档的说明相反,由于我们没有使用默认导出,因此我们必须反映导出的类模块的命名空间:
return {
    SoundPlayer: jest.fn().mockImplementation(() => {
      return {
        playSoundFile: () => {},
      };
    }
Enter fullscreen mode Exit fullscreen mode

如果这是一个默认模块,我们可以简单地这样写:

  return jest.fn().mockImplementation(() => {
    return {playSoundFile: mockPlaySoundFile};
  });
Enter fullscreen mode Exit fullscreen mode

如果在运行测试时遇到“TypeError: ”X“.default 不是一个构造函数。”错误,那是因为你没有正确反映导出的命名空间。

  • 这里的神奇之处在于使用了模拟方法,根据文档:

模拟测试辅助工具会根据源代码的类型,为模拟模块及其深层方法提供类型信息。它利用了最新的 TypeScript 特性,因此您甚至可以在 IDE 中获得参数类型自动补全功能(与 jest.MockInstance 不同)。

你的设置不正确的第一个明显迹象是,你会收到类型为 X 的错误,error TS2339: Property 'mockClear' does not exist on type X其中 X 是你试图模拟的类。

希望这能帮助你编写更好的单元测试。

文章来源:https://dev.to/codedivoire/how-to-mock-an-imported-typescript-class-with-jest-2g7j