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

使用Jest+TypeScript测试类静态方法时,Mock依赖静态方法遇ClassB未定义问题

Jest Mock静态方法时ClassB未定义问题解决

场景代码

ClassA 实现代码:

import { ClassB } from './classB'

export class ClassA {
    public static async staticMethodA() {
        return await ClassB.staticMethodB();
    }
}

问题描述

编写staticMethodA的单元测试时,尝试MockClassB.staticMethodB以隔离测试逻辑,但运行时触发ClassB未定义错误。断点调试发现,代码中存在classB_1变量,但找不到预期的ClassB变量。

原测试代码:

describe('staticMethodA', () => {
    let classA;

    const mockStaticMethodB = jest.fn().mockResolvedValue({}); // 返回空对象

    beforeAll(() => {

        // Mocking ClassB
        jest.mock('../src/classB', () => () => ({

            ClassB: { 
                staticMethodB: mockStaticMethodB
            }

        }))};

        // 在Mock后导入ClassA,使其引用Mock
        classA = require('../src/classA');
    }

    it('should call mockStaticMethodB', async () => {

        // require返回的是包含ClassA的对象
        const actual = await classA.ClassA.staticMethodA();

        expect(actual).toBe({}); // 断言返回空对象
    }

    afterAll(() => {
        jest.unmock('../src/classB');
    });
}

问题原因

原jest.mock的工厂函数写法错误:返回了一个模拟类构造函数的函数,但实际我们需要模拟的是直接导出的静态类对象——因为ClassA是通过import { ClassB } from './classB'直接导入静态类,而非通过实例化类得到对象。

解决方案

1. 修正Jest Mock写法

将jest.mock的工厂函数改为直接返回包含ClassB的导出对象,而非构造函数:

describe('staticMethodA', () => {
    let ClassA;
    const mockStaticMethodB = jest.fn().mockResolvedValue({});

    beforeAll(() => {
        // 正确模拟classB模块的导出结构
        jest.mock('../src/classB', () => ({
            ClassB: {
                staticMethodB: mockStaticMethodB
            }
        }));

        // 解构导入ClassA,简化后续调用
        ({ ClassA } = require('../src/classA'));
    });

    it('should call mockStaticMethodB and return the mock value', async () => {
        const actual = await ClassA.staticMethodA();
        
        // 断言Mock方法被调用
        expect(mockStaticMethodB).toHaveBeenCalled();
        // 对象断言用toEqual(递归比较属性),而非toBe(比较引用)
        expect(actual).toEqual({});
    });

    afterAll(() => {
        jest.unmock('../src/classB');
    });
});

2. 额外注意事项

  • 避免模块缓存问题:如果测试中多次导入模块,可使用jest.isolateModules包裹导入逻辑,确保每次测试都使用全新的Mock:
beforeAll(() => {
    jest.isolateModules(() => {
        jest.mock('../src/classB', () => ({
            ClassB: {
                staticMethodB: mockStaticMethodB
            }
        }));
        ({ ClassA } = require('../src/classA'));
    });
});
  • 断言对象时必须用toEqual:toBe仅比较对象引用,无法匹配两个内容相同但内存地址不同的对象。
  • 增加Mock调用断言:通过expect(mockStaticMethodB).toHaveBeenCalled()验证逻辑的执行路径是否符合预期。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 22:57:21