MongooseError - 开玩笑地连接到 mongoosedb NestJS 测试用例时,操作 users.xxx() 缓冲在 10000 毫秒后超时

Posted

技术标签:

【中文标题】MongooseError - 开玩笑地连接到 mongoosedb NestJS 测试用例时,操作 users.xxx() 缓冲在 10000 毫秒后超时【英文标题】:MongooseError - Operation users.xxx() buffering timed out after 10000ms while connecting to mongoosedb NestJS test case in jest 【发布时间】:2021-08-11 18:44:54 【问题描述】:

我正在尝试为与 mongoosedb 交互的服务方法 create 编写测试用例。 Nest 无法连接到数据库,我注意到 MongooseError - Operation users.xxx() buffering timed out after 10000ms 。当我运行应用程序时,我没有看到错误。只有在执行测试用例时才会出现错误。

测试用例

我没有直接连接到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
        
    );




数据库服务

//import statements

@Injectable()
export class DbService 

    constructor(@InjectModel('id') private readonly idModel: Model<IdDocument>) 
    

    create(input: UserCreate) 
        return new Promise((resolve, reject) => 
            try 
                // create, save the doc and return doc to caller
                const userdoc = new this.idModel(input)
                const result = await userdoc.save( validateBeforeSave: true )
                resolve(userdoc)
             catch (error) 
                // send error to caller
                console.log('error while resolving promise' + JSON.stringify(error))
                reject(error)
            
        )
    

【问题讨论】:

不和谐链接discord.com/channels/520622812742811698/606125380817911828/… 【参考方案1】:

您似乎走在正确的轨道上,但是,您的代码存在一些问题,难以测试。

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

服务


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

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

  async create(input: UserCreate) 
    try 
      const userdoc = new this.idModel(input);
      return userdoc.save()
     catch (error) 
      console.log('error while resolving promise' + JSON.stringify(error));
      throw error;
    
  

更好的是,使用异常过滤器将服务的关注点分开,并将错误处理从服务中推开:

异常过滤器

服务:


@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)
  

然后,调整您的单元测试以使用模拟而不是真实的东西。您的集成 (e2e) 测试应确保使用真实的数据库。

测试


//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,
      );
    );
);

了解详情

    https://docs.nestjs.com/exception-filters https://docs.nestjs.com/pipes#the-built-in-validationpipe(推荐这个,验证完全远离数据库,那么数据库验证更像是一种健全性检查) https://docs.nestjs.com/fundamentals/testing#unit-testing https://docs.nestjs.com/fundamentals/testing#end-to-end-testing

注意

重新添加任何被剥离的类型。

【讨论】:

感谢您的详细建议,我也在考虑使用集成测试进行真正的数据库连接。我将重新访问/检查其他可用的嵌套选项。

以上是关于MongooseError - 开玩笑地连接到 mongoosedb NestJS 测试用例时,操作 users.xxx() 缓冲在 10000 毫秒后超时的主要内容,如果未能解决你的问题,请参考以下文章

如何从 AngularJS 站点安全地连接到 web api

如何使用 PHP 安全地连接到内部网络 SQLSRV 数据库?

如何使用 GUI 工具安全地连接到 GKE 中的数据库?

将存储安全地连接到 Azure Data Lake Analytics 或数据工厂

如何从无服务器应用程序安全地连接到 AWS DynamoDB 或其他 aws 数据库

MongooseError - 操作缓冲在 10000 毫秒后超时