Node.js 如何仅对基类方法而不是重写的方法使用jest.spyOn
正在尝试为我的nestjs应用程序编写测试脚本 我有一个控制器/服务框架,如下所示: 控制器:Node.js 如何仅对基类方法而不是重写的方法使用jest.spyOn,node.js,jestjs,nestjs,Node.js,Jestjs,Nestjs,正在尝试为我的nestjs应用程序编写测试脚本 我有一个控制器/服务框架,如下所示: 控制器: import { Controller, Get } from '@nestjs/common'; ... @Controller() export class MyController { ... } 现在,显然findAll的mock实现在MyService上模拟findAll,因此测试失败,因为从未调用spy_缓存集 我想做的是只模拟DbService中的基本方法findAll,以便维
import { Controller, Get } from '@nestjs/common';
...
@Controller()
export class MyController {
...
}
现在,显然findAll的mock实现在MyService上模拟findAll,因此测试失败,因为从未调用spy_缓存集
我想做的是只模拟DbService中的基本方法findAll,以便维护MyService中存在的额外功能
有没有一种方法可以做到这一点,而不只是重命名MyService中的方法,我宁愿避免这样做
编辑以添加:
感谢@Jonatan lenco提供如此全面的回复,我已经采纳并实施了这一回复。
我还有一个问题。CacheService、DbService和许多其他东西,其中一些我想模仿,另一些我不想模仿的东西在一个外部库项目中,共享
cache.service.ts
导出类缓存服务{…}
索引
然后将其编译并作为包包含在node_模块中
在我编写测试的项目中:
import { CacheService, DocumentService, OtherStuff } from "shared";
我是否仍可以仅对CacheService使用jest.mock,而不模拟整个共享项目?在这种情况下,由于您希望监视抽象类DbService,因此可以监视prototype方法:
jest.spyOn(DbService.prototype, 'findAll').mockImplementation(async () => {
return [testPerson];
});
这里还有一些关于使用NestJS和Jest进行单元测试的建议:
在本例中,使用jest.mock简化对CacheService的模拟。看
当您执行jest.spyOn时,您可以断言方法的执行,而不需要spy对象。而不是:
你可以做:
jest.spyOn(DbService.prototype, 'findAll').mockImplementation(async () => {
return [testPerson];
});
...
expect(DbService.prototype.findAll).toBeCalledTimes(1);
如果您正确地模拟了一个类,那么如果您不想模拟它的实现,就不需要监视该方法
使用NestJS中的测试实用程序,当您有复杂的依赖项注入时,它将特别帮助您。看
下面是一个将这4条建议应用于单元测试的示例:
import { Test } from '@nestjs/testing';
import { CacheService } from './cache.service';
import { DbService } from './db.service';
import { MyController } from './my.controller';
import { MyService } from './my.service';
import { Person } from './person';
jest.mock('./cache.service');
describe('MyController', async () => {
let myController: MyController;
let myService: MyService;
let cacheService: CacheService;
const testPerson = new Person();
beforeAll(async () => {
const module = await Test.createTestingModule({
controllers: [MyController],
providers: [
MyService,
CacheService,
],
}).compile();
myService = module.get<MyService>(MyService);
cacheService = module.get<CacheService>(CacheService);
myController = module.get<MyController>(MyController);
jest.spyOn(DbService.prototype, 'findAll').mockImplementation(async () => {
return [testPerson];
});
});
beforeEach(async () => {
jest.clearAllMocks();
});
describe('getAll', () => {
it('Should return an array of one person', async () => {
const r = await myController.getAll();
expect(r).toHaveLength(1);
expect(DbService.prototype.findAll).toBeCalledTimes(1);
expect(cacheService.setValue).toBeCalledTimes(1);
expect(r).toEqual([testPerson]);
});
});
});
关于模拟另一个包的特定项,而不是模拟整个包,您可以执行以下操作:
在等级库文件中创建一个类,也可以在导入的另一个文件中创建,甚至在共享模块中创建,该模块具有不同的名称,但具有相同的公共方法名称。请注意,我们使用jest.fn,因为我们不需要提供实现,并且已经在该方法中进行了间谍操作的人员以后不需要执行jest.spyOn,除非您必须模拟该实现。
设置测试模块的提供程序时,告诉它您提供的是原始类,但实际上提供的是模拟类:
有关提供商的更多信息,请参见Nest遵循相同的Angular理念。非常感谢您的详细回复。如果您有几分钟的时间,我将非常感谢您快速查看我编辑中的问题。再次感谢!谢谢你的好意。我已经编辑了回复,为您的最后一个问题添加了答案。
import { CacheService, DocumentService, OtherStuff } from "shared";
jest.spyOn(DbService.prototype, 'findAll').mockImplementation(async () => {
return [testPerson];
});
spy_findall = jest.spyOn(myService, "findAll").mockImplementation(async () => {
return [testPerson];
});
...
expect(spy_findall).toBeCalledTimes(1);
jest.spyOn(DbService.prototype, 'findAll').mockImplementation(async () => {
return [testPerson];
});
...
expect(DbService.prototype.findAll).toBeCalledTimes(1);
import { Test } from '@nestjs/testing';
import { CacheService } from './cache.service';
import { DbService } from './db.service';
import { MyController } from './my.controller';
import { MyService } from './my.service';
import { Person } from './person';
jest.mock('./cache.service');
describe('MyController', async () => {
let myController: MyController;
let myService: MyService;
let cacheService: CacheService;
const testPerson = new Person();
beforeAll(async () => {
const module = await Test.createTestingModule({
controllers: [MyController],
providers: [
MyService,
CacheService,
],
}).compile();
myService = module.get<MyService>(MyService);
cacheService = module.get<CacheService>(CacheService);
myController = module.get<MyController>(MyController);
jest.spyOn(DbService.prototype, 'findAll').mockImplementation(async () => {
return [testPerson];
});
});
beforeEach(async () => {
jest.clearAllMocks();
});
describe('getAll', () => {
it('Should return an array of one person', async () => {
const r = await myController.getAll();
expect(r).toHaveLength(1);
expect(DbService.prototype.findAll).toBeCalledTimes(1);
expect(cacheService.setValue).toBeCalledTimes(1);
expect(r).toEqual([testPerson]);
});
});
});
import { Controller, Get } from '@nestjs/common';
...
@Controller()
export class MyController {
...
}
class CacheServiceMock {
setValue = jest.fn();
}
const module = await Test.createTestingModule({
controllers: [MyController],
providers: [
MyService,
{ provide: CacheService, useClass: CacheServiceMock },
],
}).compile();