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

Jest中使用setTimeout运行回调报错:this.userService.sendEmail不是函数

问题原因与解决方案

核心问题分析

你遇到的报错本质是测试环境中this.userService的上下文或mock状态异常,和runSafelyAsync的实现逻辑无关,具体原因可能有以下几点:

  • Nest.js测试中UserService未被正确mock注入,导致this.userService为undefined
  • 你对runSafelyAsync的mock未处理异步回调的Promise,引发测试时序问题
  • 测试中类实例的this上下文未正确初始化

针对性解决方案

1. 确保UserService被正确mock注入

在Nest.js单元/E2E测试中,必须通过测试模块明确mock依赖,不能依赖自动注入:

import { Test } from '@nestjs/testing';
import { YourService } from './your.service';
import { UserService } from './user.service';

describe('YourService', () => {
  let yourService: YourService;
  let userService: UserService;

  beforeEach(async () => {
    const moduleRef = await Test.createTestingModule({
      providers: [
        YourService,
        // 明确mock UserService
        {
          provide: UserService,
          useValue: { sendEmail: jest.fn().mockResolvedValue(undefined) },
        },
      ],
    }).compile();

    yourService = moduleRef.get(YourService);
    userService = moduleRef.get(UserService);
  });

  it('should send email via runSafelyAsync', async () => {
    await yourService.yourMethodThatCallsRunSafelyAsync();
    
    expect(userService.sendEmail).toHaveBeenCalled();
  });
});

2. 修正runSafelyAsync的mock实现

原函数的回调是异步Promise,mock时必须等待回调完成,避免时序错误:

jest.spyOn(asyncUtils, 'runSafelyAsync').mockImplementation(async (callback) => {
  await callback();
});

3. 不mockrunSafelyAsync的替代方案

如果想保留原函数的setTimeout逻辑,可以用Jest的fake timers手动触发:

it('should handle delayed email sending', async () => {
  jest.useFakeTimers();

  yourService.yourMethodThatCallsRunSafelyAsync();
  
  // 触发所有延迟执行的定时器
  jest.runAllTimers();
  // 等待异步操作完成
  await Promise.resolve();

  expect(userService.sendEmail).toHaveBeenCalled();
  jest.useRealTimers();
});

内容的提问来源于stack exchange,提问作者Filip Szymański

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 18:27:35