You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Jest中监视构造函数中实例化的类

问题描述

我有一段异步业务代码:

async function(paramA?: string): Promise<void> {
    if (paramA === undefined) {
      paramA = this.randomString();
    }
    this.funnel.loginFunnel(Status.Pending);
    await this.tracker.flush();
    this.service.call(this.name, paramA, code);
  }

其中tracker和service是在类的构造函数中初始化的:

constructor(params: Params) {
    this.tracker = new Tracker(params);
    this.service = new Service(params, this.tracker);
  }

这是纯JS代码,非React等框架。我需要验证两个逻辑:

  1. loginFunnel是否确实以Status.Pending为参数被调用
  2. service.call是否传入了正确的paramA参数

我尝试用Jest的jest.mock导入Tracker类做测试:

jest.mock('../tracker');
service.call();
expect(Tracker).toHaveBeenCalledTimes(1);

但测试抛出错误:

expect(received).toHaveBeenCalledTimes(expected)

    Matcher error: received value must be a mock or spy function

    Received has type:  function
    Received has value: [Function Tracker]
解决方法

1. 正确Mock依赖类并获取实例

jest.mock会自动替换目标类为Mock,但要验证实例方法的调用,得先拿到Mock类创建的实例。同时因为Service也是在构造函数中实例化的,需要一起Mock。

第一步:Mock所有依赖类

// 自动Mock Tracker和Service类,Jest会生成对应的Mock构造函数
jest.mock('../tracker');
jest.mock('../service');

第二步:创建被测实例并提取Mock对象

// 准备测试用参数
const testParams = { /* 填写你的测试参数 */ };
// 创建被测类的实例
const testInstance = new YourClassName(testParams);

// 提取Tracker的Mock实例(构造函数调用后,实例会存在mock.instances里)
const mockTracker = Tracker.mock.instances[0];
// 提取Service的Mock实例
const mockService = Service.mock.instances[0];
// 给funnel手动创建Mock(如果funnel不是构造函数初始化的,直接替换成Spy)
testInstance.funnel = {
  loginFunnel: jest.fn()
};
// 让tracker的flush返回resolved Promise,避免异步阻塞
mockTracker.flush.mockResolvedValue(undefined);

2. 验证loginFunnel的调用

调用被测方法后,直接断言loginFunnel的调用参数:

// 调用被测的异步方法
await testInstance.yourAsyncMethodName();

// 验证loginFunnel以Status.Pending为参数调用
expect(testInstance.funnel.loginFunnel).toHaveBeenCalledWith(Status.Pending);

3. 验证service.call的参数

分两种场景测试:传入paramA和不传paramA的情况:

// 场景1:传入自定义paramA
const testParamA = 'custom-test-value';
await testInstance.yourAsyncMethodName(testParamA);
// 断言call方法的参数是否正确
expect(mockService.call).toHaveBeenCalledWith(testInstance.name, testParamA, code);

// 场景2:不传入paramA,此时会调用randomString生成值
// 先mock randomString返回固定值,避免随机结果影响测试
testInstance.randomString = jest.fn().mockReturnValue('random-generated-value');
await testInstance.yourAsyncMethodName();
expect(mockService.call).toHaveBeenCalledWith(testInstance.name, 'random-generated-value', code);

关于你之前的报错原因

你直接断言Tracker构造函数的调用次数时出错,是因为jest.mock生成的Mock构造函数,需要确保你导入的是Mock后的类。正确的构造函数调用断言应该是:

// 验证Tracker构造函数被调用了1次,参数是testParams
expect(Tracker).toHaveBeenCalledTimes(1);
expect(Tracker).toHaveBeenCalledWith(testParams);

如果还是报错,检查是否在测试文件中正确导入了Tracker类,或者是否有其他地方重新导入了原始类导致Mock失效。

内容的提问来源于stack exchange,提问作者Juanma Perez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 17:15:37