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

如何在Jest中正确模拟外部函数调用并返回自定义虚拟结果

Jest 模拟指定函数的实现方案

前置说明

你要模拟的三个函数如果是从其他模块导入的,可直接按下方方案操作;如果是和generateSalamWelcome定义在同一个文件内,需要先调整原函数的调用方式:将三个函数的调用改为从当前文件的导出对象上调用,示例如下:

// templeate.ts 调整示例
import * as currentModule from './templeate';

// 原有三个函数的导出保持不变
export const getRestaurantQueriesMultiple = async () => {/* 原有逻辑 */}
export const getMode = () => {/* 原有逻辑 */}
export const generateTextTemplate = () => {/* 原有逻辑 */}

export const generateSalamWelcome = async function (
  actionSource: IActionSource,
  actionDetails: IActionDetails
): Promise<IReplyTemplate[] | undefined> {
  try {
    const { pageId } = actionSource;
    const { actionExt } = actionDetails;
    // 调用时加上currentModule前缀
    const restaurantData = await currentModule.getRestaurantQueriesMultiple(pageId, []);
    if (restaurantData) {
      const replyTemplates: IReplyTemplate[] = [];
      const { enOnly, bnOnly } = restaurantData;
      // 调用时加上currentModule前缀
      const mode = currentModule.getMode(enOnly, bnOnly, actionExt || languageModes.EN);
      replyTemplates.push(
        // 调用时加上currentModule前缀
        currentModule.generateTextTemplate(
          selectTextEnBn(mode, strings.salamWelcomeEn, strings.salamWelcomeBn)
        )
      );
      return replyTemplates;
    }
  } catch (err) {
    logger.error(err);
  }
};

完整测试代码示例

假设三个函数统一从./common-utils模块导入,测试文件templeate.test.ts写法如下:

import { generateSalamWelcome } from './templeate';
// 导入三个函数所在的模块
import * as utilsModule from './common-utils';
// 导入用到的类型定义
import type { IActionSource, IActionDetails, IReplyTemplate } from './type-defs';

// 全局模拟整个工具模块
jest.mock('./common-utils');

describe('generateSalamWelcome 函数测试', () => {
  // 每次测试前清空模拟的调用记录与自定义返回值,避免用例间互相影响
  beforeEach(() => {
    jest.clearAllMocks();
  });

  it('拿到餐厅数据时返回正确的欢迎模板', async () => {
    // 1. 自定义getRestaurantQueriesMultiple的返回值
    const mockRestaurantData = {
      enOnly: false,
      bnOnly: true,
      // 补全其他restaurantData需要的字段
    };
    // 异步函数用mockResolvedValue定义返回值
    jest.mocked(utilsModule.getRestaurantQueriesMultiple).mockResolvedValue(mockRestaurantData);

    // 2. 自定义getMode的返回值,比如返回孟加拉语模式
    const mockLangMode = 'BN';
    // 同步函数用mockReturnValue定义返回值
    jest.mocked(utilsModule.getMode).mockReturnValue(mockLangMode);

    // 3. 自定义generateTextTemplate的返回值
    const mockReplyTemplate: IReplyTemplate = {
      type: 'text',
      content: 'আসসালামু আলাইকুম! আমাদের রেস্তোরাঁয় স্বাগতম',
      // 补全其他IReplyTemplate需要的字段
    };
    jest.mocked(utilsModule.generateTextTemplate).mockReturnValue(mockReplyTemplate);

    // 构造入参
    const mockActionSource = { pageId: 'test_page_001' } as IActionSource;
    const mockActionDetails = { actionExt: 'BN' } as IActionDetails;

    // 调用待测函数
    const result = await generateSalamWelcome(mockActionSource, mockActionDetails);

    // 断言结果符合预期
    expect(result).toEqual([mockReplyTemplate]);
    // 可选:断言模拟函数的调用参数符合预期,验证传参逻辑是否正确
    expect(utilsModule.getRestaurantQueriesMultiple).toHaveBeenCalledWith('test_page_001', []);
    expect(utilsModule.getMode).toHaveBeenCalledWith(false, true, 'BN');
  });
});

补充说明

如果测试时出现TS类型报错,可以用as jest.Mock手动断言函数类型,更推荐用Jest内置的jest.mocked工具函数,会自动保留函数的类型提示。

内容的提问来源于stack exchange,提问作者Al Imran Hossain

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 20:24:04