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

使用 Jest 模拟 ES6 类方法!前提条件

使用 Jest 模拟 ES6 类方法!

先决条件

先决条件

在开始本教程之前,我假设你已经有一个正在开发的 JavaScript 项目,并且已经了解一些关于测试的基础知识以及编写测试的原因。听起来有点熟悉?太好了,让我们开始吧!

我们为什么要嘲讽?

编写单元测试时,务必隔离当前测试的特定组件(或单元)。如果隔离得不够有效,就可能测试到目标代码之外的其他部分。为了避免这种情况,我们可以模拟代码的外部部分,以模拟代码可能运行的特定环境。这样可以确保代码在不同条件下始终按预期运行。

以玩笑嘲讽

幸运的是,Jest 让模拟代码的不同部分变得相当简单(一旦你弄清楚它是如何实现的)。接下来,我将介绍几种我们目前可以使用的基本方法!

设置

我假设我们有两个类。一个是“ProductManager”类,这是我们目前正在测试的类;另一个是“ProductClient”类,用于从 API 获取产品。

ProductsClient 可能类似于以下示例。

export class ProductsClient {
  async getById(id) {
    const url = `http://localhost:3000/api/products/{id}`;
    const response = await fetch(url);
    return await response.json();
  }
}

产品经理的界面可能看起来像这样。

export class ProductManager {
  async getProductToManage(id) {
    const productsClient = new ProductsClient();
    const productToManage = await productsClient.getById(id)
      .catch(err => alert(err));
    return productToManage;
  }
}

所以,ProductManager 会获取产品并返回其值,如果获取过程中出现错误,则会发出警报。看起来很简单,对吧?好的,让我们看看如何使用 Jest 模拟 ProductsClient 来对 ProductManager 进行单元测试。

编写测试

我要展示的第一种方法是使用 Jest 的自动模拟功能。只需导入要模拟的模块,然后调用 jest.mock(),就像这样。

import { ProductsClient } from './ProductsClient';

jest.mock('./ProductsClient');

现在,ProductsClient 类中的所有方法(例如 getById())都会被自动模拟并返回 'undefined'。这对于很多应用场景来说可能完全没问题。但对于我们的情况来说,这存在一些问题。首先,如果 ProductClient 始终返回 'undefined',我们如何测试 ProductManager 是否返回了正确的值?更重要的是,如果调用 getById() 返回 'undefined',我们的 .catch() 语句会抛出错误,因为我们无法对 'undefined' 调用方法!

嘲笑我们的回报价值

那么,我们该如何解决这个问题呢?我们可以模拟函数的返回值。假设我们现有的测试用例如下所示。

it('should return the product', async () => {
  const expectedProduct = {
    id: 1,
    name: 'football',
  };
  const productManager = new ProductManager();
  const result = await productManager.getProductToManage(1); // Will throw error!

  expect(result.name).toBe('football');
});

我们需要确保在 ProductManager 类中调用 ProductClient 的 `getById` 方法时返回一个解析为 `expectedProduct` 的 Promise。为此,我们需要将一个模拟函数赋值给 ProductClient 的 `getById` 方法。然而,由于我们使用的是 ES6 类语法,所以不能简单地将其赋值给 `ProductsClient.getById`,而是需要将其赋值给对象的原型。

const mockGetById = jest.fn();
ProductsClient.prototype.getById = mockGetById;

完成这一步后,我们就可以添加模拟函数应该返回的内容了。

const mockGetById = jest.fn();
ProductsClient.prototype.getById = mockGetById;
mockGetById.mockReturnValue(Promise.resolve(expectedProduct));

现在我们完成的测试文件应该如下所示。

import { ProductsClient } from './ProductsClient';
import { ProductManager } from './ProductManager';

jest.mock('./ProductsClient');

it('should return the product', async () => {
  const expectedProduct = {
    id: 1,
    name: 'football',
  };
  const productManager = new ProductManager();
  const mockGetById = jest.fn();
  ProductsClient.prototype.getById = mockGetById;
  mockGetById.mockReturnValue(Promise.resolve(expectedProduct));

  const result = await productManager.getProductToManage(1); 

  expect(result.name).toBe('football'); // It passes!
});

结论

希望这篇文章能帮助你更好地了解如何使用 Jest 模拟类方法!如果你喜欢这篇文章,欢迎留言分享你的想法和建议,告诉我你还想看到哪些其他内容。感谢阅读!

文章来源:https://dev.to/jackcaldwell/mocking-es6-class-methods-with-jest-bd7