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

NestJS如何Mock作用域包?E2E测试Mock失效求助

自定义Jest Mock作用域包不生效问题排查

问题描述

我有一个作用域包@my-company/common,包含多个模块(如@my-company/common/dist/services/aws/s3、@my-company/common/dist/services/mongodb/atlas),其中既有@Injectable类也有非可注入类。在控制器的E2E测试中,我需要Mock这些模块。

示例业务代码MyAwsService:

import { MyS3Service } from '@my-company/common/dist/services/aws/s3';

@Injectable()
export class MyAwsService{
  private s3: MyS3Service;

  constructor(private config: ConfigService) {
    const configuration = {
      region: config.get('region'),
      credentials: {
        accessKeyId: config.get('key'),
        secretAccessKey: config.get('secret'),
      },
    };
    this.s3 = new MyS3Service(configuration);
  }
}

测试时我不想提供真实凭证,只想Mock整个MyS3Service。按照Jest文档,我在测试文件顶部添加了:

jest.mock('../node_modules/@my-company/common/dist/services/aws/s3/s3.service.js');

同时创建了__mocks__/@my-company/common.js文件,内容如下:

export const getListOfFilesFn = jest.fn().mockImplementation(() => Promise.resolve({ status: 'OK' }));

export const MyS3Service = jest.fn().mockImplementation(function () {
  return {
    getListOfFiles: () => {
      console.log(`mock getListOfFiles called`);
      return getListOfFilesFn;
    },
  };
});

现在的问题是:移除jest.mock时,测试会因S3需要凭证失败;保留后测试能运行,但自定义Mock的MyS3Service没有返回值,也不打印日志,所有响应都是undefined。想知道为什么自定义Mock不生效,当前实际运行的是什么?


问题原因

  1. Mock路径不匹配:你指定的jest.mock路径是物理文件路径../node_modules/@my-company/common/dist/services/aws/s3/s3.service.js,但Jest匹配Mock的逻辑是基于模块的导入路径,而非物理文件路径。这种情况下,Jest不会关联到你在__mocks__下创建的作用域包Mock文件。

  2. Mock模块结构不匹配:原模块的导出路径是@my-company/common/dist/services/aws/s3(通常是从该目录的index文件导出MyS3Service),但你的Mock文件直接放在__mocks__/@my-company/common.js,和原模块的导出结构不对应,导致导入时找不到你定义的Mock成员。


解决方案

步骤1:修正jest.mock调用

直接使用模块的导入路径进行Mock,而非物理文件路径:

jest.mock('@my-company/common/dist/services/aws/s3');

这样Jest会自动按照模块路径去查找__mocks__下对应的Mock文件。

步骤2:调整Mock文件结构

按照原模块的路径层级创建Mock目录:

  • 在项目根目录下创建__mocks__/@my-company/common/dist/services/aws/s3目录
  • 在该目录下创建index.ts(或.js,根据项目文件类型),内容如下:
export const getListOfFilesFn = jest.fn().mockResolvedValue({ status: 'OK' });

export const MyS3Service = jest.fn().mockImplementation(() => ({
  getListOfFiles: () => {
    console.log(`mock getListOfFiles called`);
    return getListOfFilesFn;
  },
}));

这种结构和原模块的导出路径完全匹配,Jest能正确加载你定义的Mock逻辑。

步骤3:验证Mock是否生效

在测试文件中可以添加验证代码,确认Mock已被正确加载:

import { MyS3Service } from '@my-company/common/dist/services/aws/s3';

test('Mock is correctly loaded', () => {
  expect(MyS3Service).toBeDefined();
  expect(jest.isMockFunction(MyS3Service)).toBe(true);
});

额外说明

当前测试能运行但Mock不生效,是因为Jest在找不到对应自定义Mock的情况下,自动生成了一个空Mock——所有导出成员都是默认的jest.fn(),没有任何自定义逻辑,所以调用后返回undefined,也不会执行你写的日志和返回值逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 11:48:16