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

使用mockingoose模拟Mongoose模型时测试冻结问题求助

NestJS测试中使用mockingoose模拟Card模型时进程冻结的排查与解决

问题背景

我定义了如下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用于加载实体,测试日志截图见:![测试日志截图](test log screen)

现在需要排查测试进程冻结的原因及解决办法。


可能的原因及解决办法

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 17:47:37