mongodb - 如何为 @Injectable() mongodb 服务编写 Nestjs 单元测试
问题描述
有人可以指导我。我正在学习 Nestjs 并做一个小项目,但我无法让单元测试适用于依赖于 database.module 的控制器和服务。如何在 product.service.ts 中模拟 database.module?任何帮助将不胜感激。
数据库.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 {}
产品.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,
ProductService,
],
controllers: [ProductController]
}).compile();
productController = app.get< ProductController >(ProductController);
productService = app.get< ProductService >(ProductService);
});
afterAll(() => jest.restoreAllMocks());
}
解决方案
理论上,任何没有在单元测试中直接测试的东西都应该被嘲笑。在这种情况下,您有两个依赖AppConfigService
项 adn 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
.
如果您需要更多帮助,这里有大量示例
编辑 2020 年 9 月 4 日
在使用像 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);
推荐阅读
- angular - ngb popover不呈现html编码
- python - 使用networkx获取最短路径,但通过路径应该经过的额外站点
- firebase - events_* 表 bigquery 中的“privacy_info”是什么?
- xml - 如何通过批处理文件命令检查 xml 元素/属性是否存在
- amazon-web-services - 条件表达式中的 zipmap 函数给出真假结果表达式必须具有一致的类型错误
- uniwebview - UniWebView OnMessageReceived 在场景更改后不起作用
- azure-devops - 为什么我不能使用变量在 Azure Pipeline YAML 配置文件中定义环境属性?
- javascript - 创建动态线,每端都有圆圈,线的宽度高度和旋转参数 - javascript
- git - SourceTree 不会使用自定义的 .git 文件夹名称来调整 Git 存储库
- javascript - Django分页表后所有页面的搜索框