如何使用 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);
}
}
请注意,这不是默认导出。这一点很重要,因为如果您遵循 Jest 文档,他们的示例会假设您使用的是默认导出,这在后续的模拟中会很重要。
SoundPlayer 模拟
假设你正在为另一个类(比如 `SoundPlayer`)编写单元测试,SoundPlayerConsumer并且你想模拟 `SoundPlayer` 类。如果你还没有安装ts-jest,我强烈建议你现在就把它添加到你的 Jest 配置中。
yarn add --dev ts-jest @types/jest
正如我之前提到的,如果你使用的是 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);
});
}
这其实很容易理解,但这里还有几点需要说明:
- 与 Jest 文档的说明相反,由于我们没有使用默认导出,因此我们必须反映导出的类模块的命名空间:
return {
SoundPlayer: jest.fn().mockImplementation(() => {
return {
playSoundFile: () => {},
};
}
如果这是一个默认模块,我们可以简单地这样写:
return jest.fn().mockImplementation(() => {
return {playSoundFile: mockPlaySoundFile};
});
如果在运行测试时遇到“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