使用 Typescript 从 Jest 手动模拟中导入函数
Posted
技术标签:
【中文标题】使用 Typescript 从 Jest 手动模拟中导入函数【英文标题】:Import function from a Jest manual mock with Typescript 【发布时间】:2020-02-26 14:24:27 【问题描述】:我正在 Typescript 项目中使用 Jest 创建一个自定义模拟(ES6 类)。模拟创建了几个mock.fn()
的最终导出,以便可以在测试套件中监视它们。
一个例子可以是来自 Jest 文档 (https://jestjs.io/docs/en/es6-class-mocks#manual-mock) 的官方例子。在那里,SoundPlayer
类已被模拟,因为它是它唯一的方法playSoundFile
。该方法使用jest.fn()
模拟,导出以用于测试。
// soundPlayer.ts
export default class SoundPlayer
foo: string = 'bar';
playSoundFile(filename: string)
console.log(`Playing sound file $filename`);
// __mocks__/soundPlayer.ts
export const mockPlaySoundFile = jest.fn();
const mock = jest.fn().mockImplementation(() =>
return playSoundFile: mockPlaySoundFile ;
);
export default mock;
// __tests__/soundPlayer.ts
import SoundPlayer, mockPlaySoundFile from '../soundPlayer';
jest.mock('../soundPlayer');
beforeEach(() =>
mockPlaySoundFile.mockClear();
);
it('is called with filename', () =>
const filename = 'song.mp3';
const soundPlayer = new SoundPlayer();
soundPlayer.playSoundFile(filename);
expect(mockPlaySoundFile).toBeCalledWith(filename);
);
测试按预期工作,但 TS 在尝试导入模拟的 mockPlaySoundFile
函数时通知错误(这对我来说很有意义)。那是因为mockPlaySoundFile
显然不存在于soundPlayer.ts
中。但是由于 jest.mock('../soundPlayer');
模拟是在后台导入的,因此导出确实存在。
有没有办法通知 TS 在这种情况下查看模拟?
【问题讨论】:
这个线程有很多很好的例子来说明如何做到这一点:***.com/questions/48759035/… 你可以使用来自 ts-jest 的mocked
助手:github.com/kulshekhar/ts-jest/blob/master/docs/user/…
【参考方案1】:
我有同样的问题,我只有一个解决方法。我的问题是我从节点手动模拟 fs。
所以我有一个“fs”的手动模拟,大致如下:
const fs = jest.genMockFromModule("fs");
let mockFiles = ;
function __clearMocks()
mockFiles = ;
module.exports = fs;
很明显,当我的测试用例导入 fs 时它不起作用:
import * as fs from 'fs';
fs.__clearMocks();
为了让它工作,我创建了一个类型的扩展:
declare module 'fs'
export function __clearMocks(): void;
所以现在我可以像这样修改我的测试用例:
import * as fs from 'fs';
import 'fsExtension';
fs.__clearMocks();
希望对您有所帮助!
【讨论】:
【参考方案2】:解决此问题的最简单方法是使用ts-jest 的mocked()
助手。助手将确保您可以访问模拟测试方法。 __tests__/soundPlayer.ts
将如下所示:
// __tests__/soundPlayer.ts
import mocked from "ts-jest/utils";
import SoundPlayer from '../soundPlayer';
jest.mock('../soundPlayer');
const soundPlayer = mocked(new SoundPlayer());
beforeEach(() =>
soundPlayer.playSoundFile.mockClear();
);
it('is called with filename', () =>
const filename = 'song.mp3';
soundPlayer.playSoundFile(filename);
expect(soundPlayer.playSoundFile).toBeCalledWith(filename);
);
如果你真的想包含mockPlaySoundFile
,你可以通过告诉 Typescript 编译器抑制导入错误来做到这一点:
// @ts-ignore
import mockPlaySoundFile from '../soundPlayer';
另外,请查看我的仓库中的示例:https://github.com/tbinna/ts-jest-mock-examples,尤其是您的 soundPlayer
示例:https://github.com/tbinna/ts-jest-mock-examples/tree/master/sound-player
【讨论】:
以上是关于使用 Typescript 从 Jest 手动模拟中导入函数的主要内容,如果未能解决你的问题,请参考以下文章
在 Typescript 中使用 Jest + Supertest 进行模拟
使用正确类型使用 Jest 和 Typescript 模拟 Express 请求
如何避免 Typescript 转译 Jest __mocks__