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

TypeScript函数式编程中单元测试依赖自动Mock工具函数实现

实现自动Mock函数依赖的createDeps工具函数

完整实现代码

import type { Mock } from 'jest';

// 从目标函数中提取其第一个参数(依赖对象)的类型
type ExtractDeps<Fn> = Fn extends (deps: infer D, ...args: any[]) => any ? D : never;

// 定义所有属性均为jest.Mock的依赖类型
type MockedDeps<D> = {
  [K in keyof D]: Mock;
};

export function createDeps<Fn extends (deps: any, ...args: any[]) => any>(
  customMocks?: Partial<MockedDeps<ExtractDeps<Fn>>>
): MockedDeps<ExtractDeps<Fn>> {
  const deps = {} as MockedDeps<ExtractDeps<Fn>>;
  const depKeys = Object.keys({} as ExtractDeps<Fn>) as Array<keyof ExtractDeps<Fn>>;

  depKeys.forEach(key => {
    deps[key] = customMocks?.[key] ?? jest.fn();
  });

  return deps;
}

使用示例

假设你有如下函数和依赖类型:

type BreakfastDeps = {
  scrambleEggs: () => Promise<string>;
  makeToast: () => string;
  personMakingTheToast: (name: string) => void;
};

async function createBreakfast(deps: BreakfastDeps) {
  await deps.scrambleEggs();
  const toast = deps.makeToast();
  deps.personMakingTheToast('Alice');
  return `Breakfast ready: ${toast}`;
}

在单元测试中使用createDeps:

test('createBreakfast 正常工作', async () => {
  // 仅自定义需要特殊配置的mock
  const makeToast = jest.fn().mockReturnValueOnce("It's ready");

  // 自动生成所有依赖,自定义mock会覆盖默认值
  const deps = createDeps<typeof createBreakfast>({ makeToast });

  const result = await createBreakfast(deps);

  expect(result).toBe("Breakfast ready: It's ready");
  expect(deps.scrambleEggs).toHaveBeenCalled();
  expect(deps.personMakingTheToast).toHaveBeenCalledWith('Alice');
});

核心特性说明

  • 类型自动推导:通过ExtractDeps泛型自动提取目标函数的依赖类型,无需手动重复声明依赖结构。
  • 按需自定义Mock:仅需传入需要特殊配置(如返回值、实现逻辑)的mock,其余依赖自动生成默认的jest.fn()。
  • 类型安全:MockedDeps确保所有依赖属性都是jest.Mock类型,避免类型不匹配问题。
  • 通用性:适用于任何接收依赖对象作为第一个参数的函数,无需针对不同函数修改工具代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 14:17:27