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

Jest无法覆盖NestJS用例层insert参数中的回调函数

解决NestJS用例层回调函数Jest覆盖率统计问题

问题出在哪

Jest默认不会追踪那些作为参数传给依赖方法的匿名回调的覆盖率,除非这些回调被实实在在执行了,而且测试代码能覆盖到执行的路径。

具体解决办法

1. 先确认回调真的被执行了

首先得检查moduleRepository.insert方法有没有真的调用传入的callBeforeInsert和callAfterInsert。如果是你自己写的Repository,查内部逻辑有没有触发这俩回调;如果是Mock的Repository,得在测试里手动模拟调用这两个回调。

举个Mock的例子:

// 测试文件里这么写
const moduleRepository = {
  insert: jest.fn(async (data, callbacks) => {
    // 手动调用before回调
    await callbacks.callBeforeInsert(data);
    // 模拟插入操作
    const result = { id: 1, ...data };
    // 手动调用after回调
    await callbacks.callAfterInsert(result);
    return result;
  }),
};

2. 把回调抽成独立函数(推荐这么做)

别写匿名回调了,把它们改成独立的命名函数,Jest更容易追踪到执行路径,代码也更好维护。

改之前的代码:

// AddModuleUseCases.ts
async execute(data: ModuleDto) {
  const callBeforeInsert = async (moduleData: ModuleDto) => {
    // 内部逻辑
    moduleData.createdAt = new Date();
  };

  const callAfterInsert = async (savedModule: ModuleEntity) => {
    // 内部逻辑
    await this.eventEmitter.emit('module.created', savedModule);
  };

  return this.moduleRepository.insert(data, { callBeforeInsert, callAfterInsert });
}

改之后:

// AddModuleUseCases.ts
private async callBeforeInsert(moduleData: ModuleDto) {
  moduleData.createdAt = new Date();
}

private async callAfterInsert(savedModule: ModuleEntity) {
  await this.eventEmitter.emit('module.created', savedModule);
}

async execute(data: ModuleDto) {
  return this.moduleRepository.insert(data, {
    callBeforeInsert: this.callBeforeInsert.bind(this),
    callAfterInsert: this.callAfterInsert.bind(this),
  });
}

这样就算通过Mock Repository触发回调,Jest也能统计到这两个私有方法的覆盖率。

3. 调一下Jest配置(可选)

如果上面的方法没用,检查jest.config.js里的collectCoverageFrom配置,确保包含了你的用例层文件:

// jest.config.js
module.exports = {
  collectCoverageFrom: [
    'src/**/*.use-cases.ts', // 匹配你的用例层文件路径
    'src/**/*.service.ts',
    '!src/**/*.module.ts',
    '!src/main.ts',
  ],
};

同时注意别在coveragePathIgnorePatterns里把这些文件排除了。

4. 直接测试回调函数(针对私有方法)

如果回调是私有方法,可以用jest.spyOn来拿到并调用它:

// 测试文件
it('should run callBeforeInsert correctly', async () => {
  const useCase = new AddModuleUseCases(moduleRepository, eventEmitter);
  // 监听私有方法
  const beforeSpy = jest.spyOn(useCase as any, 'callBeforeInsert');
  
  const testData = { name: 'test module' };
  await useCase.execute(testData);
  
  expect(beforeSpy).toHaveBeenCalledWith(testData);
  expect(testData.createdAt).toBeInstanceOf(Date);
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 01:00:06