使用mockingoose模拟Mongoose模型时测试冻结问题求助
问题背景
我定义了如下Mongoose Card模型:
export class Card extends Document { @Prop({ required: true, immutable: true}) id: string; @Prop({ required: true }) name: string; // 其他字段省略 } export const CardSchema = SchemaFactory.createForClass(Card);
在编写NestJS的API测试时,尝试用mockingoose模拟数据,但测试进程出现冻结情况。我的测试代码如下:
import { INestApplication } from '@nestjs/common'; import { Test } from '@nestjs/testing'; import * as request from 'supertest'; import { AppModule } from '../../../../src/app.module'; import { createAuthToken } from '../../../helpers/auth.helper'; import { Card } from '../../../../src/card/card.schema'; import { Model } from 'mongoose'; import { getModelToken } from '@nestjs/mongoose'; import mockingoose from 'mockingoose'; describe('GET /card:id', () => { let app: INestApplication; let cardModel: Model<Card>; beforeAll(async () => { // 模块初始化代码省略 }); it('Should receive card data', async () => { const _doc = { id: 'test', name: 'Test Card' }; // 模拟的卡片数据 mockingoose(cardModel).toReturn(_doc, 'findOne'); return request(app.getHttpServer()) .get('/card/test') .set('Content-Type', 'application/json') .set('Authorization', `Bearer ${createAuthToken(user)}`) .expect(200); }) // 其他测试用例省略 });
我已经实现了对应的Controller、DTO和Service用于加载实体,测试日志截图见:
现在需要排查测试进程冻结的原因及解决办法。
可能的原因及解决办法
1. mockingoose的使用姿势错误
mockingoose在NestJS环境下,需要直接针对模型类进行mock,而不是注入后的Model实例。你当前用mockingoose(cardModel)操作的是注入后的实例,这会导致mock完全不生效,Service查询时一直等待真实数据库响应,最终造成进程冻结。
修复方案:
直接用Card类来调用mockingoose:
// 替换原mock代码 mockingoose(Card).toReturn(_doc, 'findOne');
2. 测试模块未正确替换Mongoose模型
如果在测试模块初始化时,没有用mock提供者替换原始的Card模型,测试会尝试连接真实数据库,一旦数据库不可用或超时,就会导致进程挂起。
修复方案:
在beforeAll的模块配置中,显式覆盖Card模型的提供者:
beforeAll(async () => { const moduleFixture = await Test.createTestingModule({ imports: [AppModule], }) .overrideProvider(getModelToken(Card.name)) .useValue(mockingoose(Card)) .compile(); app = moduleFixture.createNestApplication(); await app.init(); });
3. 未处理的Promise或异步操作遗漏
如果Service中的查询逻辑存在未正确await的Promise,或者测试中存在未完成的异步操作,也会导致进程无法正常退出。
修复方案:
- 检查Service中
findOne相关逻辑,确保所有异步操作都用await处理 - 确保测试用例中所有异步操作都通过
return或await等待完成(你当前的return request(...)是正确的,但可以排查其他潜在异步代码)
4. 版本兼容性问题
mockingoose和Mongoose、NestJS的版本不匹配,可能导致mock逻辑失效或内部阻塞。
修复方案:
- 查看
package.json中的依赖版本,确保mockingoose版本与Mongoose版本匹配(例如mockingoose v8+对应Mongoose v6+) - 尝试升级或降级mockingoose到官方标注的兼容版本
5. 路由或认证的隐藏错误
如果日志中存在未捕获的错误(比如路由定义错误、认证失败),也可能导致请求挂起。比如你的路由写的是/card:id,正确的动态路由格式应该是/card/:id,冒号位置错误会导致路由匹配失败,请求一直等待响应。
修复方案:
- 在测试请求后添加错误捕获,查看具体问题:
return request(app.getHttpServer()) .get('/card/test') .set('Content-Type', 'application/json') .set('Authorization', `Bearer ${createAuthToken(user)}`) .expect(200) .catch(err => console.error('测试错误:', err)); - 检查Controller中的路由定义,确保动态参数格式正确
内容的提问来源于stack exchange,提问作者Vlad Krokh

