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

NestJS使用Jest测试嵌套异步函数,Delete调用验证失败

问题分析与解决方案

问题描述

在为NestJS的UpdateService编写Jest测试时遇到异常:服务实际运行可正常删除数据,测试覆盖率也显示Delete相关代码已执行,但测试断言HolidayDatesService.Delete的调用次数始终为0,而HolidayIdsService.GetOne的调用次数断言正常通过。

核心业务逻辑:RemoveInvalidHolidayDateEntriesForAYear方法遍历指定年份的假期记录,调用ValidateHolidayIdActive_验证有效性,无效则调用DeleteOneHolidayDateRecord_执行删除。

核心原因

问题出在RemoveInvalidHolidayDateEntriesForAYear方法中的forEach循环使用了异步回调函数:

  • forEach本身不支持异步等待,它会立即遍历完所有元素,不会等待每个回调里的await ValidateHolidayIdActive_和await DeleteOneHolidayDateRecord_执行完成。
  • 这导致RemoveInvalidHolidayDateEntriesForAYear方法会提前返回,测试代码中的await service.RemoveInvalidHolidayDateEntriesForAYear(2022)会在所有Delete操作实际执行前结束,此时断言Delete的调用次数自然为0。但后续异步任务仍会执行,所以控制台能看到Delete的日志,实际运行也能删除数据。

解决方案

需要确保RemoveInvalidHolidayDateEntriesForAYear方法等待所有异步删除操作完成后再返回,有两种可行方式:

方式一:使用for...of循环替代forEach

for...of支持异步等待,能确保每个迭代的异步操作完成后再进入下一次循环:

async RemoveInvalidHolidayDateEntriesForAYear(Year: number): Promise<void> {
    let ExistingHolidayDates: Array<HolidayDatesResponseDTO>;

    try {
        ExistingHolidayDates = await this.HolidayDateDataService_.GetAllRecordsByYear(Year);
    } catch (Exception) {
        return;
    }

    // 替换forEach为for...of
    for (const OneDateEntry of ExistingHolidayDates) {
        const HolidayIdIsActive: boolean = await this.ValidateHolidayIdActive_(OneDateEntry.HolidayId);
        if (!HolidayIdIsActive) {
            await this.DeleteOneHolidayDateRecord_(OneDateEntry);
        }
    }
    return;
}

方式二:使用Promise.all批量等待异步任务

将所有异步回调包装成Promise数组,通过Promise.all等待全部完成:

async RemoveInvalidHolidayDateEntriesForAYear(Year: number): Promise<void> {
    let ExistingHolidayDates: Array<HolidayDatesResponseDTO>;

    try {
        ExistingHolidayDates = await this.HolidayDateDataService_.GetAllRecordsByYear(Year);
    } catch (Exception) {
        return;
    }

    // 收集所有异步任务并等待完成
    await Promise.all(ExistingHolidayDates.map(async (OneDateEntry: HolidayDatesResponseDTO) => {
        const HolidayIdIsActive: boolean = await this.ValidateHolidayIdActive_(OneDateEntry.HolidayId);
        if (!HolidayIdIsActive) {
            await this.DeleteOneHolidayDateRecord_(OneDateEntry);
        }
    }));
    return;
}

修改后,测试代码中的await service.RemoveInvalidHolidayDateEntriesForAYear(2022)会等待所有Delete操作执行完毕,此时断言HolidayDatesService.Delete的调用次数就能得到正确结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 09:41:00