如何解决如何为@Injectablemongodb服务编写Nestjs单元测试 编辑9/04/2020
有人可以指导我吗?我正在学习Nestjs并正在做一个小项目,但我无法使单元测试适用于依赖于database.module的控制器和服务。我该如何模拟product.service.ts中的database.module?任何帮助将不胜感激。
database.module.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 {}
product.service.ts
@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 (){}
}
product.service.spec.ts
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());
}
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,controllers: [ProductController]
}).compile();
productController = app.get< ProductController >(ProductController);
productService = app.get< ProductService >(ProductService);
});
afterAll(() => jest.restoreAllMocks());
}
解决方法
任何未经单元测试直接测试的理论上都应该被嘲笑。在这种情况下,您有两个依赖项,AppConfigService
和DATABASE_CONNECTION
。您在单元测试中应该提供模拟对象,它们看起来像注入的依赖项,但具有定义且易于修改的行为。在这种情况下,您可能正在寻找类似的东西
beforeEach(async () => {
const modRef = await Test.createTestingModule({
providers: [
ProductService,{
provide: AppConfigService,useValue: {
appConfigObject: mockConfigObject
}
},{
provide: 'DATABASE_CONNECTION',useValue: {
<databaseMethod>: jest.fn()
}
]
}).compile();
// assuming these are defined in the top level describe
prodService = modRef.get(ProductionService);
conn = modRef.get('DATABASE_CONNECTION');
config = modRef.get(AppConfigService);
});
在控制器测试中,您不必担心ProdctService
以外的其他任何事物。
如果您需要更多帮助,there's a large repository of examples here
编辑9/04/2020
模拟链接方法是处理Mongo之类的主要难题。有几种方法可以解决,但最简单的方法可能是创建一个像
这样的模拟对象const mockModel = {
find: jest.fn().mockReturnThis(),update: jest.fn().mockReturnThis(),collation: jest.fn().mockReturnThis(),...etc
}
并在链中的最后调用中,使其返回预期结果,以便您的服务可以继续运行其余代码。这意味着如果您有类似的电话
const value = model.find().collation().skip().limit().exec()
您可能需要设置exec()
方法以返回期望的值,可能使用类似的方法
jest.spyOn(mockModel,'exec').mockResolvedValueOnce(queryReturn);
,
我也在探索将原生 Mongodb 与 NestJS 结合使用。下面是我对 db 中 cron 作业服务更新值的工作测试。
src/cron/cron.service.ts
import { Inject,Injectable } from '@nestjs/common';
import { Cron,CronExpression } from '@nestjs/schedule';
import { Db } from 'mongodb';
import { Order } from 'src/interfaces/order.interface';
@Injectable()
export class CronService {
constructor(
@Inject('DATABASE_CONNECTION')
private db: Db,) {}
@Cron(CronExpression.EVERY_30_SECONDS)
async confirmOrderEveryMinute() {
console.log('Every 30 seconds');
await this.db
.collection<Order>('orders')
.updateMany(
{
status: 'confirmed',updatedAt: {
$lte: new Date(new Date().getTime() - 30 * 1000),},{ $set: { status: 'delivered' } },)
.then((res) => console.log('Orders delivered...',res.modifiedCount));
}
}
src/cron/cron.service.spec.ts
import { Test,TestingModule } from '@nestjs/testing';
import { Db } from 'mongodb';
import { CronService } from './cron.service';
describe('CronService',() => {
let service: CronService;
let connection: Db;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
CronService,{
provide: 'DATABASE_CONNECTION',useFactory: () => ({
db: Db,collection: jest.fn().mockReturnThis(),updateMany: jest.fn().mockResolvedValue({ modifiedCount: 1 }),}),],}).compile();
service = module.get<CronService>(CronService);
connection = module.get('DATABASE_CONNECTION');
});
it('should be defined',async () => {
expect(service).toBeDefined();
});
it('should confirmOrderEveryMinute',async () => {
await service.confirmOrderEveryMinute();
expect(connection.collection('orders').updateMany).toHaveBeenCalled();
});
});
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。