首页 > web前端 > js教程 > 用 Jest 和 typescript 进行嘲笑 - 备忘单

用 Jest 和 typescript 进行嘲笑 - 备忘单

Barbara Streisand
发布: 2024-12-22 22:31:11
原创
548 人浏览过

Mocking with Jest and typescript - a cheatsheet

Jest 非常擅长在 javascript/typescript 中模拟导入,但我发现很难记住实现细节。

函数和对象需要以不同的方式进行模拟,默认导出的模拟与命名导出略有不同,并且 Jest 与打字稿的配合效果不佳。将所有这些事情结合起来,可能很难找出甚至搜索适合您的模拟场景的正确方法。

我创建本指南是为了回答这个问题“如何模拟我的导入?”无论导入是什么。默认或命名、函数或对象。

我的环境

我已经使用以下版本的软件测试了所有这些方法:

  • 节点 v22.11.0
  • 笑话 v29.7.0
  • ts-jest v29.2.5
  • @types/jest v29.5.14

使用默认的最小 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中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板