MongooseError-Operation users.xxx()在连接mongoosedb NestJS测试用例时,10000毫秒后缓冲超时

MongooseError-Operation users.xxx()在连接mongoosedb NestJS测试用例时,10000毫秒后缓冲超时,mongoose,jestjs,nestjs,Mongoose,Jestjs,Nestjs,我正在尝试为创建与mongoosedb交互的服务方法编写测试用例。Nest无法连接到db,我注意到MongooseError-Operation users.xxx()缓冲在10000毫秒后超时。我在运行应用程序时没有看到错误。只有在执行测试用例时才能看到错误 测试用例 我没有直接连接到mongoose,而是编译了一个模块 //import statements describe('user DB Service - Sample', () => { let service: D

我正在尝试为创建与mongoosedb交互的服务方法编写测试用例。Nest无法连接到db,我注意到
MongooseError-Operation users.xxx()缓冲在10000毫秒后超时。我在运行应用程序时没有看到错误。只有在执行测试用例时才能看到错误

测试用例 我没有直接连接到mongoose,而是编译了一个模块

//import statements

describe('user DB Service - Sample', () => {
    let service: DbService;
    let userConnection: Connection;
    const userModel = model('User', UserSchema);
    beforeEach(async () => {
        const module: TestingModule = await Test.createTestingModule({
            imports: [
                MongooseModule.forRoot('mongodb://127.0.0.1:27017/nest?readPreference=primary&appname=MongoDB%20Compass&ssl=false', { connectionName: 'users', useNewUrlParser: true }),
            ],
            providers: [
                DbService,
                {
                    provide: getModelToken('User'),
                    useValue: userModel,
                },
            ],
        }).compile();

        service = module.get<DbService>(DbService);
        userConnection = await module.get(getConnectionToken('users'))
        jest.setTimeout(30000)

    });

    /**
     * create user
     */
    it('Create user with null input should return Invalid Input exception', async () => {
        try {

            let createRequest = {
                // user input object
            }
            idConnection.on('connect', () => {
                console.log('connected')
            })
            const result = await service.create(createRequest
            // validate result
        } catch (error) {
            console.log('error creating', error)
            // error validation
        }
    });
}



//导入语句
描述('用户数据库服务-示例',()=>{
let服务:DbService;
让userConnection:Connection;
const userModel=model('User',UserSchema);
beforeach(异步()=>{
常量模块:TestingModule=等待测试。createTestingModule({
进口:[
MongooseModule.forRoot('mongodb://127.0.0.1:27017/nest?readPreference=primary&appname=MongoDB%20Compass&ssl=false“,{connectionName:'users',useNewUrlParser:true}),
],
供应商:[
DbService,
{
提供:getModelToken(“用户”),
useValue:userModel,
},
],
}).compile();
service=module.get(DbService);
userConnection=wait module.get(getConnectionToken('users'))
jest.setTimeout(30000)
});
/**
*创建用户
*/
它('使用空输入创建用户应返回无效输入异常',异步()=>{
试一试{
让createRequest={
//用户输入对象
}
idConnection.on('connect',()=>{
console.log('已连接')
})
const result=wait service.create(createRequest
//验证结果
}捕获(错误){
console.log('创建错误',错误)
//错误验证
}
});
}
数据库服务
//导入语句
@可注射()
导出类DbService{
构造函数(@InjectModel('id')私有只读idModel:Model){
}
创建(输入:UserCreate){
返回新承诺((解决、拒绝)=>{
试一试{
//创建、保存文档并将文档返回给调用方
const userdoc=newthis.idModel(输入)
const result=await userdoc.save({validateBeforeSave:true})
解析(userdoc)
}捕获(错误){
//向呼叫方发送错误
console.log('解析承诺时出错'+JSON.stringify(错误))
拒绝(错误)
}
})
}

您似乎在正确的轨道上,但是,您的代码存在一些问题,这使得测试变得困难

首先,在进行单元测试时,您无需担心数据库连接。如果您只需要确保您的服务方法调用模型方法,那么您可以执行以下操作:

服务

@可注射()
导出类dService {//考虑命名此用户服务
构造函数(@InjectModel('id')私有只读idModel:Model){}
异步创建(输入:UserCreate){
试一试{
const userdoc=newthis.idModel(输入);
返回userdoc.save()
}捕获(错误){
log('解析承诺时出错'+JSON.stringify(错误));
投掷误差;
}
}
}
更好的方法是,使用异常过滤器分离服务的关注点,并将错误处理从服务中分离出来:

例外过滤器 服务:


@Injectable()
export class DbService { // consider naming this UserService

  constructor(@InjectModel('id') private readonly idModel: Model) {}

  async create(input: UserCreate) {
    return new this.idModel(input).save();
  }
}

@可注射()
导出类dService {//考虑命名此用户服务
构造函数(@InjectModel('id')私有只读idModel:Model){}
异步创建(输入:UserCreate){
返回新的this.idModel(input.save();
}
}
过滤器:


@Catch(MongooseValidationError)
export class ValidationExceptionFilter extends BaseExceptionFilter {
  catch (exception: MongooseValidationError, host: ArgumentsHost) {
    const customError = new YourCustomError('Invalid!', 'you gave me invalid details!');
    super.catch(customError, host)
  }
}

@捕获(MongooseValidationError)
导出类ValidationExceptionFilter扩展BaseExceptionFilter{
捕获(异常:MongooseValidationError,主机:ArgumentsHost){
const customError=new YourCustomError('Invalid!','your给了我无效的详细信息!');
super.catch(自定义错误,主机)
}
}
然后,调整单元测试以使用模拟而不是真实的东西。您的集成(e2e)测试应该确保使用真实的数据库

测验

//导入语句
常数数据={
//…模拟对象
}
类模型{
构造函数(公共数据?:any){}
保存(){
返回此.data;
}
静态findOne({u id}){
返回数据;
}
}
描述('用户数据库服务-示例',()=>{
let服务:DbService;
let模型:模型;
beforeach(异步()=>{
常量模块:TestingModule=等待测试。createTestingModule({
供应商:[
DbService,
{
提供:getModelToken(“用户”),
useClass:mockModel//如果抛出错误,请使用useValue
},
],
}).compile();
service=module.get(DbService);
model=module.get(getModelToken('User');//添加您的类型
});
/**
*创建用户
*/
它('使用空输入创建用户应返回无效输入异常',异步()=>{
//失败的请求
常量createRequest={
// ...
}
//提供所需的响应(例如ValidationError)
spyOn(model,'save').mockImplementationOnce(jest.fn(async()=>{
抛出新错误();//抛出ValidationError或mongoose将抛出的任何错误
}));
expect(service.create(createRequest)).rejects.toThrow();//引发验证错误
//…将调用验证方法
expect(model.save).tohavebeencall();
期望(model.save).已被调用({
验证保存:true
});
});
它('创建具有良好输入的用户应返回用户',异步()=>{
//好的要求
常量createRequest={
// ...

@Injectable()
export class DbService { // consider naming this UserService

  constructor(@InjectModel('id') private readonly idModel: Model) {}

  async create(input: UserCreate) {
    return new this.idModel(input).save();
  }
}

@Catch(MongooseValidationError)
export class ValidationExceptionFilter extends BaseExceptionFilter {
  catch (exception: MongooseValidationError, host: ArgumentsHost) {
    const customError = new YourCustomError('Invalid!', 'you gave me invalid details!');
    super.catch(customError, host)
  }
}

//import statements

const data = {
  // ... a mock object
}

class mockModel {

     constructor(public data?: any) {}

     save() {
         return this.data;
     }

     static findOne({ _id }) {
         return data;
     }
}


describe('user DB Service - Sample', () => {
    let service: DbService;
    let model: Model;
    beforeEach(async () => {
        const module: TestingModule = await Test.createTestingModule({
            providers: [
                DbService,
                {
                    provide: getModelToken('User'),
                    useClass: mockModel // if it throws error use useValue
                },
            ],
        }).compile();


        service = module.get(DbService);
        model = module.get(getModelToken('User')); // add your types
    });

    /**
     * create user
     */
    it('Create user with null input should return Invalid Input exception', async () => {
      // the failing request
      const createRequest = {
        // ...
      }

      // provide the response you want (ValidationError for example)
      jest.spyOn(model, 'save').mockImplementationOnce(jest.fn(async () => {
        throw new Error(); // throw ValidationError or whatever error mongoose would throw
      }));

      expect(service.create(createRequest)).rejects.toThrow(); // validate error is thrown

      // ... validate method is called
      expect(model.save).toHaveBeenCalled();
      expect(model.save).toHaveBeenCalledWith({
        validateOnSave: true
      });
    });

    it('Create user with good input should return User', async () => {
      // the good request
      const createRequest = {
        // ...
      };

      // provide the response you want (ValidationError for example)
      jest.spyOn(model, 'save').mockImplementationOnce(
        jest.fn(async () => data)
      );

      const result = await service.create(createRequest);
      expect(result).toStrictEqual(data); // or whatever mock object you provide

      // ... validate method is called
      expect(model.save).toHaveBeenCalled();
      expect(model.save).toHaveBeenCalledWith({
        validateOnSave: true,
      });
    });
});