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 数据库?
将存储安全地连接到 Azure Data Lake Analytics 或数据工厂