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

如何Mock被服务内方法调用、且被控制器触发的服务函数

如何Mock getLastPackageVersion方法?

问题背景

测试控制器中的getPackagesUpdatesToNotify函数时,始终无法Mock服务里的getLastPackageVersion方法,每次都会触发原函数的真实请求,不想使用rewire类工具。

现有代码

控制器代码(version-control.controller.ts)

import { InstalledPackages } from '../parser/parser.service';
import {
  getOutdatedPackages,
  InstalledPackageStatus,
} from './version-control.service';

interface OutdatedPackages {
  dependencies: InstalledPackageStatus[];
  devDependencies: InstalledPackageStatus[];
}

export async function getPackagesUpdatesToNotify(
  packages: InstalledPackages,
  type = 'package.json',
): Promise<OutdatedPackages> {
  return getOutdatedPackages(packages.dependencies, type);
}

服务代码(version-control.service.ts)

import { fetch } from "../common/http.service";

export async function getLastPackageVersion(
  packageName: string
): Promise<VersionType> {
  const url = `https://registry.npmjs.org/-/package/${packageName}/dist-tags`;
  return await (<Promise<VersionType>>fetch(url));
}

export async function getOutdatedPackages(
  installedPackages: PackagesVersion,
  type: string
): Promise<InstalledPackageStatus[]> {
  return Promise.all(
    Object.keys(installedPackages).map(async (packageName) =>
      getLastPackageVersion(packageName)
    )
  );
}

尝试过的方案

方案1:使用jest.spyOn

import * as myService from './my.service';

it('my test', async () => {
  const getLastPackageVersionSpy = jest.spyOn(myService, 'getLastPackageVersion').mockReturnValue(
    Promise.resolve(42),

    await getPackagesUpdatesToNotify(packages, type)
});

方案2:使用jest.mock

import { getLastPackageVersion } from './my.service';
import { getPackagesUpdatesToNotify } from './version-control.controller';

jest.mock('./myse.service', () => ({
  ...jest.requireActual('./myse.service'),
  getLastPackageVersion: jest.fn(),
}));

it('my test', async () => {
  (getLastPackageVersion as jest.Mock).mockResolvedValue(
    Promise.resolve(42),
  );

  await getPackagesUpdatesToNotify(packages, type)
});

问题原因

核心问题是模块内部直接调用的函数无法被外部Mock:服务中的getOutdatedPackages是直接调用同文件内的getLastPackageVersion函数本身,而非通过模块导出的引用调用。jest的Mock机制是替换模块导出对象上的方法引用,无法拦截这种内部直接调用。

正确解决方案

方案1:修改服务代码,通过模块引用调用内部函数

修改服务代码,让内部调用通过模块自身的导出引用,这样jest就能拦截到调用:

import { fetch } from "../common/http.service";
import * as self from './version-control.service'; // 导入自身模块

export async function getLastPackageVersion(
  packageName: string
): Promise<VersionType> {
  const url = `https://registry.npmjs.org/-/package/${packageName}/dist-tags`;
  return await (<Promise<VersionType>>fetch(url));
}

export async function getOutdatedPackages(
  installedPackages: PackagesVersion,
  type: string
): Promise<InstalledPackageStatus[]> {
  return Promise.all(
    Object.keys(installedPackages).map(async (packageName) =>
      self.getLastPackageVersion(packageName) // 通过模块引用调用
    )
  );
}

对应的测试代码:

import * as versionControlService from './version-control.service';
import { getPackagesUpdatesToNotify } from './version-control.controller';

it('should mock getLastPackageVersion correctly', async () => {
  // Mock getLastPackageVersion,替换为符合VersionType结构的返回值
  const mockSpy = jest.spyOn(versionControlService, 'getLastPackageVersion')
    .mockResolvedValue({ latest: '1.0.0' });

  const mockPackages = {
    dependencies: { 'test-pkg': '0.1.0' }
  } as InstalledPackages;

  await getPackagesUpdatesToNotify(mockPackages);

  // 验证Mock被调用
  expect(mockSpy).toHaveBeenCalledTimes(1);
  expect(mockSpy).toHaveBeenCalledWith('test-pkg');

  // 测试后恢复原函数
  mockSpy.mockRestore();
});

方案2:直接Mock控制器依赖的getOutdatedPackages函数

由于控制器直接调用的是getOutdatedPackages,可以跳过内部的getLastPackageVersion,直接Mock这个上层函数,更简洁:

import * as versionControlService from './version-control.service';
import { getPackagesUpdatesToNotify } from './version-control.controller';

it('should return outdated packages via mocked getOutdatedPackages', async () => {
  const mockOutdatedPackages: InstalledPackageStatus[] = [
    { name: 'test-pkg', current: '0.1.0', latest: '1.0.0' }
  ];

  // Mock getOutdatedPackages
  jest.spyOn(versionControlService, 'getOutdatedPackages')
    .mockResolvedValue(mockOutdatedPackages);

  const mockPackages = {
    dependencies: { 'test-pkg': '0.1.0' }
  } as InstalledPackages;

  const result = await getPackagesUpdatesToNotify(mockPackages);

  // 验证返回结果符合预期
  expect(result.dependencies).toEqual(mockOutdatedPackages);
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 03:55:28