如何为@Injectable()mongodb服务编写Nestjs单元测试
有人能给我引路吗。我正在学习Nestjs并做一个小项目,但我无法让依赖于database.module的控制器和服务的单元测试工作。如何在product.service.ts中模拟database.module?我们将非常感谢您的帮助 数据库.module.ts如何为@Injectable()mongodb服务编写Nestjs单元测试,mongodb,unit-testing,jestjs,nestjs,Mongodb,Unit Testing,Jestjs,Nestjs,有人能给我引路吗。我正在学习Nestjs并做一个小项目,但我无法让依赖于database.module的控制器和服务的单元测试工作。如何在product.service.ts中模拟database.module?我们将非常感谢您的帮助 数据库.module.ts try { const client = await MongoClient.connect(process.env.MONGODB, { useNewUrlParser: true, useUnifiedTopology:
try {
const client = await MongoClient.connect(process.env.MONGODB, { useNewUrlParser: true, useUnifiedTopology: true });
return client.db('pokemonq')
} catch (e) {
console.log(e);
throw e;
}
};
@Module({
imports: [],
providers: [
{
provide: 'DATABASE_CONNECTION',
useFactory: setupDbConnection
},
],
exports: ['DATABASE_CONNECTION'],
})
export class DatabaseModule {}
@Injectable()
export class ProductService {
protected readonly appConfigObj: EnvConfig;
constructor(
private readonly appConfigService: AppConfigService,
@Inject('DATABASE_CONNECTION') => **How to mock this injection?**
private db: Db,
) {
this.appConfigObj = this.appConfigService.appConfigObject;
}
async searchBy (){}
async findBy (){}
}
describe('ProductService', () => {
let service: ProductService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [],
providers: [
ConfigService,
DatabaseModule,
AppConfigService,
ProductService,
{
provide: DATABASE_CONNECTION,
useFactory: () => {}
}
],
}).compile();
service = module.get< ProductService >(ProductService);
});
afterAll(() => jest.restoreAllMocks());
}
产品.服务.ts
try {
const client = await MongoClient.connect(process.env.MONGODB, { useNewUrlParser: true, useUnifiedTopology: true });
return client.db('pokemonq')
} catch (e) {
console.log(e);
throw e;
}
};
@Module({
imports: [],
providers: [
{
provide: 'DATABASE_CONNECTION',
useFactory: setupDbConnection
},
],
exports: ['DATABASE_CONNECTION'],
})
export class DatabaseModule {}
@Injectable()
export class ProductService {
protected readonly appConfigObj: EnvConfig;
constructor(
private readonly appConfigService: AppConfigService,
@Inject('DATABASE_CONNECTION') => **How to mock this injection?**
private db: Db,
) {
this.appConfigObj = this.appConfigService.appConfigObject;
}
async searchBy (){}
async findBy (){}
}
describe('ProductService', () => {
let service: ProductService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [],
providers: [
ConfigService,
DatabaseModule,
AppConfigService,
ProductService,
{
provide: DATABASE_CONNECTION,
useFactory: () => {}
}
],
}).compile();
service = module.get< ProductService >(ProductService);
});
afterAll(() => jest.restoreAllMocks());
}
产品.服务.规范ts
try {
const client = await MongoClient.connect(process.env.MONGODB, { useNewUrlParser: true, useUnifiedTopology: true });
return client.db('pokemonq')
} catch (e) {
console.log(e);
throw e;
}
};
@Module({
imports: [],
providers: [
{
provide: 'DATABASE_CONNECTION',
useFactory: setupDbConnection
},
],
exports: ['DATABASE_CONNECTION'],
})
export class DatabaseModule {}
@Injectable()
export class ProductService {
protected readonly appConfigObj: EnvConfig;
constructor(
private readonly appConfigService: AppConfigService,
@Inject('DATABASE_CONNECTION') => **How to mock this injection?**
private db: Db,
) {
this.appConfigObj = this.appConfigService.appConfigObject;
}
async searchBy (){}
async findBy (){}
}
describe('ProductService', () => {
let service: ProductService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [],
providers: [
ConfigService,
DatabaseModule,
AppConfigService,
ProductService,
{
provide: DATABASE_CONNECTION,
useFactory: () => {}
}
],
}).compile();
service = module.get< ProductService >(ProductService);
});
afterAll(() => jest.restoreAllMocks());
}
description('ProductService',()=>{
让服务:产品服务;
beforeach(异步()=>{
常量模块:TestingModule=等待测试。createTestingModule({
进口:[],
供应商:[
配置服务,
数据库模块,
AppConfigService,
产品服务,
{
提供:数据库连接,
useFactory:()=>{}
}
],
}).compile();
服务=模块。获取(ProductService);
});
毕竟(()=>jest.restoreAllMocks());
}
product.controller.spec.ts
describe('ProductController', () => {
let app: TestingModule;
let ProductController: ProductController;
let ProductService: ProductService;
const response = {
send: (body?: any) => {},
status: (code: number) => response,
json: (body?: any) => response
}
beforeEach(async () => {
app = await Test.createTestingModule({
imports: [
ConfigModule.forRoot({
load: [appConfig],
isGlobal: true,
expandVariables: true
}),
ProductModule,
],
providers: [
AppConfigService,
ProductService,
],
controllers: [ProductController]
}).compile();
productController = app.get< ProductController >(ProductController);
productService = app.get< ProductService >(ProductService);
});
afterAll(() => jest.restoreAllMocks());
}
description('ProductController',()=>{
let-app:测试模块;
让ProductController:ProductController;
让产品服务:产品服务;
常数响应={
发送:(body?:any)=>{},
状态:(代码:编号)=>响应,
json:(body?:any)=>响应
}
beforeach(异步()=>{
app=wait Test.createTestingModule({
进口:[
ConfigModule.forRoot({
加载:[appConfig],
isGlobal:没错,
可扩展变量:true
}),
产品模块,
],
供应商:[
AppConfigService,
产品服务,
],
控制器:[ProductController]
}).compile();
productController=app.get(productController);
productService=app.get(productService);
});
毕竟(()=>jest.restoreAllMocks());
}
任何没有在单元测试中直接测试的东西理论上都应该被模拟。在这种情况下,您有两个依赖项,AppConfigService
adnDATABASE\u CONNECTION
。您的单元测试应该提供模拟对象,这些对象看起来像注入的依赖项,但是已经定义并易于修改行为。在这种情况下凯斯,像这样的东西可能就是你要找的
beforeach(异步()=>{
const modRef=wait Test.createTestingModule({
供应商:[
产品服务,
{
提供:AppConfigService,
使用价值:{
appConfigObject:mockConfigObject
}
},
{
提供:“数据库连接”,
使用价值:{
:jest.fn()
}
]
}).compile();
//假设这些是在顶层中定义的,请描述
prodService=modRef.get(ProductionService);
conn=modRef.get('DATABASE_CONNECTION');
config=modRef.get(AppConfigService);
});
在控制器测试中,您不应该担心模拟除ProdctService
之外的任何东西
如果你需要更多的帮助
编辑日期:2020年4月9日
在处理Mongo之类的东西时,模拟链式方法是一个主要的难点。有几种方法可以做到这一点,但最简单的方法可能是创建一个类似Mongo的模拟对象
const mockModel={
find:jest.fn().mockReturnThis(),
更新:jest.fn().mockReturnThis(),
排序规则:jest.fn().mockReturnThis(),
等
}
在链中的最后一个调用中,让它返回预期的结果,以便您的服务可以继续运行其余的代码
const value=model.find().collation().skip().limit().exec()
您需要设置exec()
方法来返回您希望它返回的值,可能需要使用
jest.spyOn(mockModel,'exec').mockResolvedValueOnce(queryReturn);
任何没有在单元测试中直接测试的东西理论上都应该被模拟。在这种情况下,您有两个依赖项,AppConfigService
adnDATABASE\u CONNECTION
。您的单元测试应该提供模拟对象,这些对象看起来像注入的依赖项,但是已经定义并易于修改行为。在这种情况下凯斯,像这样的东西可能就是你要找的
beforeach(异步()=>{
const modRef=wait Test.createTestingModule({
供应商:[
产品服务,
{
提供:AppConfigService,
使用价值:{
appConfigObject:mockConfigObject
}
},
{
提供:“数据库连接”,
使用价值:{
:jest.fn()
}
]
}).compile();
//假设这些是在顶层中定义的,请描述
prodService=modRef.get(ProductionService);
conn=modRef.get('DATABASE_CONNECTION');
config=modRef.get(AppConfigService);
});
在控制器测试中,您不应该担心模拟除ProdctService
之外的任何东西
如果你需要更多的帮助
编辑日期:2020年4月9日
在处理Mongo之类的东西时,模拟链式方法是一个主要的难点。有几种方法可以做到这一点,但最简单的方法可能是创建一个类似Mongo的模拟对象
const mockModel={
find:jest.fn().mockReturnThis(),
更新:jest.fn().mockReturnThis(),
排序规则:jest.fn().mockReturnThis(),
等
}
在链中的最后一个调用中,让它返回预期的结果,以便您的服务可以继续运行其余的代码
const value=model.find().collation().skip().limit().exec()
您需要设置exec()
方法来返回您希望它返回的值,可能需要使用
jest.spyOn(mockModel,'exec').mockResolvedValueOnce(queryReturn);
您当前的解决方案出了什么问题?您当前的解决方案出了什么问题?我确实遇到了您的示例,并了解了其设置和功能