Jest运行NestJS e2e测试时Prisma与PostgreSQL连接过多如何解决
问题原因
你当前的测试代码存在两个致命问题,直接导致数据库连接泄漏:
- 每个
beforeEach钩子中手动new PrismaService()创建的实例,和测试模块编译时自动初始化的PrismaService是完全独立的两个对象。你在afterEach中调用$disconnect()释放的只是自己手动创建的实例,真正被业务逻辑调用、由Nest依赖注入容器管理的Prisma实例从来没有被断开连接。 - 每个测试用例执行完成后没有调用
app.close()销毁应用实例,模块持有的数据库连接、上下文资源都没有被正常回收。每个用例重建一次应用就会新建一组数据库连接,累计下来很快就会触发PostgreSQL的连接数上限。
修复方案
推荐写法:单测试套件共享应用实例
端到端测试不需要每个用例都重建整个Nest应用,整个describe块只初始化一次应用和Prisma连接即可,用例之间通过清理业务数据实现隔离,性能更好也不会产生连接泄漏。
修正后的测试代码:
import { Test, TestingModule } from '@nestjs/testing'; import { INestApplication } from '@nestjs/common'; import { AppModule } from '../src/app.module'; import { PrismaService } from '../src/prisma.service'; describe('Users', () => { let app: INestApplication; const gql = '/graphql'; let prisma: PrismaService; beforeAll(async () => { const moduleFixture: TestingModule = await Test.createTestingModule({ imports: [AppModule], }).compile(); app = moduleFixture.createNestApplication(); // 从Nest依赖注入容器获取已经完成初始化的PrismaService实例,禁止手动new prisma = app.get(PrismaService); await app.init(); }); afterAll(async () => { // 销毁顺序不能错:先关闭应用释放所有资源,再断开Prisma连接 await app.close(); await prisma.$disconnect(); }); // 用例之间的数据清理放在beforeEach,不需要重建连接 beforeEach(async () => { // 按需清理测试表数据,避免用例间状态污染,例如: // await prisma.user.deleteMany(); }); it('Query - Users', async () => { // 测试逻辑直接复用上面初始化的prisma实例即可 }); });
强隔离场景写法(不推荐,性能较低)
如果你确实需要每个用例都使用完全独立的应用上下文,必须保证每个用例执行完后正确销毁所有资源,且全程不要手动实例化PrismaService:
beforeEach(async () => { const moduleFixture: TestingModule = await Test.createTestingModule({ imports: [AppModule], }).compile(); app = moduleFixture.createNestApplication(); prisma = app.get(PrismaService); await app.init(); }); afterEach(async () => { // 必须先关闭应用,再断开Prisma连接,不能漏掉app.close() await app.close(); await prisma.$disconnect(); });
额外优化配置
- 测试环境下调小Prisma连接池大小,串行测试场景下连接池最大连接数设为1就足够使用,从根源减少连接占用。修改PrismaService构造函数:
import { INestApplication, Injectable, OnModuleInit } from '@nestjs/common'; import { PrismaClient } from '@prisma/client'; @Injectable() export class PrismaService extends PrismaClient implements OnModuleInit { constructor() { super({ ...(process.env.NODE_ENV === 'test' ? { connectionLimit: 1, log: ['error'], } : {}) }); } async onModuleInit() { await this.$connect(); } async enableShutdownHooks(app: INestApplication) { this.$on('beforeExit', async () => { await app.close(); }); } }
- 在e2e测试脚本中添加
--forceExit参数,避免测试执行完成后还有挂起的连接占用进程导致资源泄漏:
{ "scripts": { "test:e2e": "jest --config ./test/jest-e2e.json --forceExit" } }
核心注意点:所有PrismaService实例都必须从Nest依赖注入容器获取,不要在测试代码中手动调用new创建实例,重复实例化PrismaClient是连接数暴涨的最常见原因。
内容的提问来源于stack exchange,提问作者Louis Charles
相关产品推荐
相关产品推荐

