如何在NestJS的Jest测试用例中使用UserDocument/UserModel连接真实数据库
问题解决方案
你当前的问题核心是混淆了类型定义和运行时实例的区别,且集成测试引入Mongoose模型的方式错误,按以下步骤修改即可实现直连真实数据库测试:
核心修改逻辑
- UserDocument是TS类型,仅用于编译期类型校验,不能作为运行时的值传入DI容器获取实例
- 做直连数据库的集成测试时,不需要手动提供Model的token,直接复用Nest/Mongoose的注册逻辑即可
- 不需要单独声明获取UserDocument实例,所有数据库操作已经封装在UsersService中
完整修改后的users.service.spec.ts代码
import { Test, TestingModule } from '@nestjs/testing' import { UsersService } from './users.service' import { AppConfigModule } from '../config/app-config.module' import { AppConfigService } from '../config/app-config.service' import { ConfigModule } from '@nestjs/config' import { MongooseModule, getModelToken } from '@nestjs/mongoose' import { User, UserSchema } from './entities/user.entity' import { Model } from 'mongoose' describe('UsersService', () => { let service: UsersService let userModel: Model<User> // 可选,需要直接操作表清理数据时声明 beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ imports: [ ConfigModule.forRoot({ isGlobal: true, cache: true }), MongooseModule.forRootAsync({ imports: [AppConfigModule], inject: [AppConfigService], useFactory: (config: AppConfigService) => ({ uri: `mongodb://${config.TESTDATABASE_HOST}:${config.TESTDATABSE_PORT}`, dbName: config.TESTDATABASE_NAME }) }), // 新增:注册User的Schema,自动生成对应Model注入DI容器 MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]) ], // 移除手动写的Model提供逻辑,Service直接由DI容器实例化 providers: [UsersService] }).compile() service = module.get<UsersService>(UsersService) // 如需要直接操作Model清理数据可以加这行,不需要就删掉 userModel = module.get<Model<User>>(getModelToken(User.name)) }) // 每次测试后清空users表,避免测试数据互相干扰 afterEach(async () => { await userModel.deleteMany({}) }) it('should be defined', () => { expect(service).toBeDefined() }) it('create test data', async () => { // 注意:入参字段要和你定义的User实体匹配,原测试用例中的name、email、role都不在实体中 const createResult = await service.create({ username: 'demouser', age: 20, password: 'demo@123' }) expect(createResult.username).toBe('demouser') expect(createResult.age).toBe(20) expect(createResult._id).toBeDefined() // 验证数据库实际写入成功 const allUsers = await service.findAll() expect(allUsers.length).toBe(1) expect(allUsers[0].username).toBe('demouser') }) })
额外注意事项
你原测试用例中的预期返回结构(带statusCode、message)是Controller层的全局响应拦截器返回的,Service层只返回原始的数据库实体,所以要对应修改预期值。如果需要测试Controller层的完整响应,要写Controller的集成测试,而非Service测试。
内容的提问来源于stack exchange,提问作者Keshavi Bhalani
相关产品推荐
相关产品推荐

