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

Jest中Mock注入的HTTP类实例方法失效问题及最佳实践咨询

Jest中Mock注入的HTTP类实例方法失效问题及最佳实践咨询

嗨,我来帮你分析下问题所在,以及给出几种靠谱的解决办法~

为什么你的Mock没生效?

看你的报错信息,代码还是走到了http.request里的fetch调用,说明你Mock的http.prototype.get并没有真正替换掉原始的get方法。可能的原因有这几点:

  1. 直接修改类原型的方式容易受Jest的模块隔离/缓存机制干扰,导致Mock没有覆盖到Core实际使用的那个类方法;
  2. 虽然Typescript类方法默认挂载在原型上,但偶尔会因为编译选项或其他因素,导致Mock没有正确绑定到实例的方法上。

不过更关键的是:既然你已经用了依赖注入的设计(Core的构造函数接收http实例),完全可以用更简单、更可靠的方式来Mock依赖,没必要去碰原型链~

方案一:直接注入Mock的HTTP实例(推荐)

这是最符合依赖注入设计初衷的方式——直接给Core传一个我们自己造的Mock实例,完全绕开原始的http类,自然不会有调用原始方法的问题。

修改后的测试代码如下:

import { Core } from '.'
import http from '../http'
import type { IDomainNameEntry } from './types' // 替换成你实际的类型导入路径

it('Domain Name Entry Test', async () => {
    // 1. 造一个Mock的http实例,完全自定义get方法的返回
    const mockHttp = {
        get: jest.fn(async () => 
            Promise.resolve({
                ok: true,
                status: 200,
                json: async () => ({ 
                    name: 'javierhersan.stw', 
                    urls: [], 
                    ips: [] 
                } as IDomainNameEntry),
            } as Response)
        )
    } as unknown as http; // 类型断言满足Core的参数类型要求

    // 2. 把Mock实例注入Core
    const core = new Core(mockHttp);
    const domainNameEntry = await core.getUserDomainNameEntry(
        'javierhersan.stw',
        'http://localhost:3000',
    )

    // 3. 验证逻辑和调用
    // 先确认http.get被调用了正确的URL
    expect(mockHttp.get).toHaveBeenCalledWith(
        'http://localhost:3000/api/v1/dns/search/username/javierhersan.stw'
    );
    
    // 再验证返回结果符合预期
    expect(domainNameEntry).toBeDefined();
    if (domainNameEntry) {
        expect(domainNameEntry.name).toBe('javierhersan.stw');
        expect(domainNameEntry.urls).toEqual([]);
        expect(domainNameEntry.ips).toEqual([]);
    }
})

方案二:用Jest Mock整个HTTP模块

如果你希望Mock整个http模块的导出(而不是单个实例),可以用Jest的jest.mock语法来批量Mock:

import { Core } from '.'
import http from '../http'

// 全局Mock整个http模块,让它返回一个会生成Mock实例的构造函数
jest.mock('../http', () => {
    return jest.fn().mockImplementation(() => ({
        get: jest.fn(async () => 
            Promise.resolve({
                ok: true,
                status: 200,
                json: async () => ({ 
                    name: 'javierhersan.stw', 
                    urls: [], 
                    ips: [] 
                }),
            } as Response)
        )
    }))
})

it('Domain Name Entry Test', async () => {
    const core = new Core(new http());
    const domainNameEntry = await core.getUserDomainNameEntry(
        'javierhersan.stw',
        'http://localhost:3000',
    )

    // 验证http实例的get方法被正确调用
    const mockHttpInstance = http.mock.instances[0];
    expect(mockHttpInstance.get).toHaveBeenCalledWith(
        'http://localhost:3000/api/v1/dns/search/username/javierhersan.stw'
    );

    // 业务逻辑断言
    expect(domainNameEntry).toBeDefined();
    if (domainNameEntry) {
        expect(domainNameEntry).toHaveProperty('name');
        expect(domainNameEntry).toHaveProperty('urls');
        expect(domainNameEntry).toHaveProperty('ips');
    }
})

额外补充:如果要Mock全局Fetch

如果你有时候需要测试原始http类的逻辑(而不是Core的业务逻辑),可以用jest-fetch-mock库全局Mock fetch API:

  1. 先安装依赖:npm install jest-fetch-mock --save-dev
  2. 在测试文件开头启用Mock:
import fetchMock from 'jest-fetch-mock'

fetchMock.enableMocks()

beforeEach(() => {
    fetchMock.resetMocks()
})

it('测试http类的get方法', async () => {
    fetchMock.mockResponseOnce(JSON.stringify({ 
        name: 'javierhersan.stw', 
        urls: [], 
        ips: [] 
    }), { status: 200, ok: true })

    const httpInstance = new http()
    const response = await httpInstance.get('http://test.url')
    const data = await response.json()

    expect(fetchMock).toHaveBeenCalledWith('http://test.url', { method: 'GET' })
    expect(data.name).toBe('javierhersan.stw')
})

总结

既然你已经用了依赖注入,优先选直接注入Mock实例的方案——代码更清晰,逻辑更直观,完全不会有原型Mock的各种坑,也完美契合依赖注入“面向抽象编程”的设计思路~

备注:内容来源于stack exchange,提问作者javierhersan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 08:34:32