Jest 非常擅长在 javascript/typescript 中模拟导入,但我发现很难记住实现细节。
函数和对象需要以不同的方式进行模拟,默认导出的模拟与命名导出略有不同,并且 Jest 与打字稿的配合效果不佳。将所有这些事情结合起来,可能很难找出甚至搜索适合您的模拟场景的正确方法。
我创建本指南是为了回答这个问题“如何模拟我的导入?”无论导入是什么。默认或命名、函数或对象。
我已经使用以下版本的软件测试了所有这些方法:
使用默认的最小 jest.config.js 文件:
export default { testEnvironment: 'node', transform: { '^.+.tsx?$': ['ts-jest', {}], }, testMatch: ['**/*.test.ts'], };
广泛常见的导入分为我们可能想要模拟的两类:
我们将从函数开始依次解决这两个问题。
从模块导出的函数可以命名或默认。我们会看看两者。第一:
这应该用于模拟模块中的命名导出函数,如下所示:
// ./path/to/module.ts export function doSomething(...) { ... }
可以像这样嘲笑:
import { doSomething } from './path/to/module'; // note: This should be the path to the module from the test file, // NOT from the module that contains the doSomething function itself. jest.mock('./path/to/module', () => ({ doSomething: jest.fn(), })); ... it('should do something', () => { // We need to assert that the function is a jest.Mock // so that typescript will allow us to call mock methods. (doSomething as jest.Mock).mockReturnValue(mockValue); // run your test here expect(doSomething).toHaveBeenCalledTimes(1); // etc. });
这应该用于模拟模块默认导出的函数,如下所示:
// ./path/to/module.ts export default function doSomething(...) { ... }
它的模拟方式与命名导出类似:
import doSomething from './path/to/module' jest.mock('./path/to/module', () => ({ __esModule: true, default: jest.fn() })) ... it('should do something', () => { (doSomething as jest.Mock).mockResolvedValue(mockData); // Run your test here expect(doSomething).toHaveBeenCalledTimes(5); });
模拟导出的对象(可以是类、json 对象或其他对象)时需要考虑一些变化。
如果您只需要模拟属性(例如配置文件),而不是方法,那么具体做法如下:
import config from '../config'; jest.mock('../config', () => ({ __esModule: true, default: { apiKey: '123MockKey', ... }, })); ... it('Should do something', () => { ... });
如果每次测试需要改变模拟属性:
import config from '../config'; const mockConfig = { apiKey: '123MockKey', ... }; jest.mock('../config', () => ({ __esModule: true, default: mockConfig, })); ... beforeEach(() => { // restore defaults before each test mockConfig.apiKey = '123MockKey'; ... }); it('Should do something', () => { mockConfig.apiKey = 'new value'; // rest of the test }); // more tests
与模拟默认导出对象非常相似:
import { config } from '../config'; const mockConfig = { apiKey: '123MockKey', ... }; jest.mock('../config', () => ({ config: mockConfig, })); // the rest is exactly the same as when mocking a default export object.
当从模块导出(命名或默认)带有方法的对象时,我们需要模拟这些方法的输出,方法略有不同。
上课:
// ./path/to/module.ts class ComplicatedThing { // properties, fields, constructor etc. go here getData() { ... } ... } // note: I don't necessarily recommend exporting an instance // of a class like this - purely illustrative for testing purposes. // https://medium.com/@lazlojuly/are-node-js-modules-singletons-764ae97519af export const complicatedThing = new ComplicatedThing(...);
并模拟我们导出的对象:
export default { testEnvironment: 'node', transform: { '^.+.tsx?$': ['ts-jest', {}], }, testMatch: ['**/*.test.ts'], };
模拟默认导出对象是完全相同的,除了我们定义模拟时:
// ./path/to/module.ts export function doSomething(...) { ... }
这是为了模拟一个对象,该对象不是直接导入到您正在测试的模块中,而是作为参数传递给类/函数。
注意:如果您正在模拟一个类,您可能希望创建一个接口并创建该接口的模拟实现以传递到您的函数/类中。这将使您无需进行如下不优雅的类型断言恶作剧。
import { doSomething } from './path/to/module'; // note: This should be the path to the module from the test file, // NOT from the module that contains the doSomething function itself. jest.mock('./path/to/module', () => ({ doSomething: jest.fn(), })); ... it('should do something', () => { // We need to assert that the function is a jest.Mock // so that typescript will allow us to call mock methods. (doSomething as jest.Mock).mockReturnValue(mockValue); // run your test here expect(doSomething).toHaveBeenCalledTimes(1); // etc. });
// ./path/to/module.ts export default function doSomething(...) { ... }
import doSomething from './path/to/module' jest.mock('./path/to/module', () => ({ __esModule: true, default: jest.fn() })) ... it('should do something', () => { (doSomething as jest.Mock).mockResolvedValue(mockData); // Run your test here expect(doSomething).toHaveBeenCalledTimes(5); });
我希望这对你有用,也对我未来的自己有用,当我下次努力记住如何在打字稿中模拟导入的细节时。
我希望它能够满足您所有简单的模拟需求,并为您在模拟更复杂的导入时提供一个起点。
感谢您的阅读。
以上是用 Jest 和 typescript 进行嘲笑 - 备忘单的详细内容。更多信息请关注PHP中文网其他相关文章!