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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 16:30:05