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

如何测试PrismaService中enableShutdownHooks的app.close()调用

PrismaService单元测试:覆盖beforeExit回调中的app.close()

问题场景

我的PrismaService代码如下:

import { INestApplication, Injectable } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';

@Injectable()
export class PrismaService extends PrismaClient {
  async enableShutdownHooks(app: INestApplication) {
    this.$on('beforeExit', async () => {
      await app.close();
    });
  }
}

当前的单元测试代码无法覆盖第8行的await app.close()——要么mock$on时自己手动调用了app.close()(测的是mock逻辑而非原代码),要么不mock的话beforeExit事件永远不会触发,导致这行代码没执行。

解决方案

核心思路是捕获$on注册的回调函数,手动触发它,这样就能让原代码里的app.close()执行,从而覆盖到目标代码。

修改后的测试代码如下:

import { INestApplication } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import { PrismaService } from './prisma.service';

const MockApp = jest.fn<Partial<INestApplication>, []>(() => ({
  close: jest.fn(),
}));

describe('PrismaService', () => {
  let service: PrismaService;
  let app: Partial<INestApplication>;

  beforeEach(async () => {
    app = MockApp();
    const module: TestingModule = await Test.createTestingModule({
      providers: [PrismaService],
    }).compile();

    service = module.get<PrismaService>(PrismaService);
  });

  it('should be defined', () => {
    expect(service).toBeDefined();
  });

  describe('enableShutdownHooks', () => {
    it('should register beforeExit hook and call app.close when triggered', async () => {
      // 监听$on方法,保留原实现
      const onSpy = jest.spyOn(service, '$on').mockImplementation(jest.fn());

      await service.enableShutdownHooks(app as INestApplication);

      // 验证$on被正确调用,事件名为beforeExit
      expect(onSpy).toHaveBeenCalledWith('beforeExit', expect.any(Function));
      
      // 取出注册的回调函数
      const beforeExitCallback = onSpy.mock.calls[0][1] as () => Promise<void>;
      
      // 手动触发回调
      await beforeExitCallback();

      // 验证原代码中的app.close被调用
      expect(app.close).toHaveBeenCalledTimes(1);

      onSpy.mockRestore();
    });
  });
});

关键说明

  • 不再mock$on的实现,而是用jest.spyOn监听调用,通过mock.calls获取到注册的beforeExit回调函数。
  • 手动执行这个回调,就能触发原代码里的await app.close(),自然覆盖到目标行。
  • 既验证了$on的调用逻辑,又验证了回调函数的实际执行效果,完全贴合原代码逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 13:50:26