Jest测试Google Maps服务函数失败:Mock未生效问题修复
问题:Jest Mock Google Maps Client 未生效,返回结果为 undefined
我有一个 map.service 文件,通过 @googlemaps/google-maps-services-js 的 Client 实例实现了 getGeocodeResult 函数。用 Jest 为该函数写测试时,Mock 始终不生效,返回的 result 一直是 undefined,附上服务代码和测试代码,求解决方法?
服务代码
import { Client } from '@googlemaps/google-maps-services-js'; import logger from '@common/utils/logger'; interface TimezoneObj { timezone: string; timezoneName: string; } // 顶层实例化 Google Maps 客户端 const client = new Client({}); export const getGeocodeResult = async (address: string) => { const fN = 'getGeocodeResult'; logger.info(`${fN} - Getting geo code data for address: ${address}`); const result = await client.geocode({ params: { address, key: process.env.GOOGLE_MAPS_API || '' } }); console.log(result); return result.data.results[0]; };
测试代码
import { mockGeocodeResponse } from '@mocks/google-maps'; import * as mapService from './map.service'; import { Client, GeocodeResponse } from '@googlemaps/google-maps-services-js'; jest.mock('@googlemaps/google-maps-services-js'); describe('Map Service', () => { let client: Client; beforeEach(() => { client = new Client({}) as jest.Mocked<Client>; jest.clearAllMocks(); }); describe('getGeocodeResult', () => { it.only('should use the API key from the environment variable', async () => { process.env.GOOGLE_MAPS_API = 'test-api-key'; jest.spyOn(client, 'geocode').mockResolvedValueOnce(mockGeocodeResponse); const result = await mapService.getGeocodeResult('123 Test St, Test City, TX'); expect(client.geocode).toHaveBeenCalledWith({ params: { address: '123 Test St, Test City, TX', key: 'test-api-key' } }); expect(result.formatted_address).toBe('Test Address'); }); }); });
问题原因及解决方法
核心问题
测试里新建的 client 实例和服务文件顶层创建的 client 实例不是同一个对象,因此对测试实例的 Mock 不会作用到服务中实际调用的实例上,导致返回 undefined。
修复步骤
直接 Mock Client 类的原型方法
无需在测试中新建 Client 实例,而是针对@googlemaps/google-maps-services-js导出的Client类的原型方法做 Mock,这样服务里的顶层实例会继承这个 Mock 后的方法。调整后的测试代码
import { mockGeocodeResponse } from '@mocks/google-maps'; import * as mapService from './map.service'; import { Client } from '@googlemaps/google-maps-services-js'; // 自动 Mock 整个谷歌地图服务模块 jest.mock('@googlemaps/google-maps-services-js'); // 类型断言,让 TypeScript 识别 Mock 后的类类型 const MockClient = Client as jest.MockedClass<typeof Client>; describe('Map Service', () => { beforeEach(() => { // 重置所有 Mock 状态 MockClient.mockClear(); MockClient.prototype.geocode.mockClear(); }); describe('getGeocodeResult', () => { it.only('should use the API key from the environment variable', async () => { process.env.GOOGLE_MAPS_API = 'test-api-key'; // 给 geocode 方法设置预设的 Mock 返回值 MockClient.prototype.geocode.mockResolvedValueOnce(mockGeocodeResponse); const result = await mapService.getGeocodeResult('123 Test St, Test City, TX'); // 验证 Client 类被实例化过 expect(MockClient).toHaveBeenCalledTimes(1); // 验证 geocode 方法的调用参数是否符合预期 expect(MockClient.prototype.geocode).toHaveBeenCalledWith({ params: { address: '123 Test St, Test City, TX', key: 'test-api-key' } }); // 验证返回结果是否正确 expect(result.formatted_address).toBe('Test Address'); }); }); });
关键说明
jest.mock('@googlemaps/google-maps-services-js')会自动生成模块的 Mock 版本,包含Client类的 Mock 实现。- 通过类型断言
jest.MockedClass<typeof Client>可以避免 TypeScript 类型报错,方便操作 Mock 方法。 - 服务中的顶层
client实例基于 Mock 后的Client类创建,因此它的geocode方法会使用你设置的 Mock 逻辑,返回预设的响应数据。
内容的提问来源于stack exchange,提问作者Attiq Ahmed
相关产品推荐
相关产品推荐

