使用注入对 NestJS 控制器进行单元测试
Posted
技术标签:
【中文标题】使用注入对 NestJS 控制器进行单元测试【英文标题】:Unit testing NestJS controller with injection 【发布时间】:2020-08-27 04:36:54 【问题描述】:我需要为使用 NestJS 注入的控制器进行单元测试。
我不知道如何模拟和监视此服务 (MyEmitter)。 我需要在 beforeEach() 内部的 test.controller.spec.ts 中声明它,但是如何声明呢?
test.controller.ts
import
Controller,
Body,
Post,
from '@nestjs/common';
import
WebhookDto,
from './dto/webhook.dto';
import MyEmitter from './test.events';
import InjectEventEmitter from 'nest-emitter';
@Controller()
export class TestController
constructor(
@InjectEventEmitter() private readonly myEmitter: MyEmitter,
)
@Post('webhook')
public async postWebhook(
@Body() webhookDto: WebhookDto,
): Promise<void>
...
this.myEmitter.emit('webhook', webhookDto);
test.controller.spec.ts
import Test, TestingModule from '@nestjs/testing';
import TestController from './test.controller';
import EventEmitter = require('events');
import EVENT_EMITTER_TOKEN from 'nest-emitter';
import MyEmitter from './test.events';
describe('Test Controller', () =>
let testController: TestController;
beforeEach(async () =>
const module: TestingModule = await Test.createTestingModule(
imports: [],
providers: [
provide: EVENT_EMITTER_TOKEN,
useValue:
emit: jest.fn(),
,
,
],
controllers: [TestController],
).compile();
testController = module.get<TestController>(TetsController);
);
describe('postWebhook', () =>
it('should send the event', async () =>
const myEmitterSpy = jest.spyOn(myEmitter, 'emit');
const result = await testController.postWebhook(...);
expect(myEmitterSpy).toBeCalledTimes(1);
);
);
);
非常感谢您的帮助。
【问题讨论】:
【参考方案1】:与其注入每个依赖项(应单独测试),不如使用 jest.spyOn 更好,因为控制器具有服务依赖项或可能具有其他依赖项的依赖项。
我们应该模拟将在当前测试中调用的方法。
这是示例控制器测试。
import SampleController from './sample.controller';
import SampleService from './sample.service';
describe('SampleController', () =>
let sampleController: SampleController;
let sampleService: SampleService;
beforeEach(() =>
// SampleService depends on a repository class
// Passing null becasue SampleService will be mocked
// So it does not need any dependencies.
sampleService = new SampleService(null);
// SampleController has one dependency SampleService
sampleController = new SampleController(sampleService);
);
it('should be defined', async () =>
expect(sampleController).toBeDefined();
);
describe('findAll', () =>
it('should return array of samples', async () =>
// Response of findAllByQuery Method
// findAllByQUeryParams is a method of SampleService class.
// I want the method to return an array containing 'test' value'.
const expectedResult = ['test'];
// Creating the mock method
// The method structure is the same as the actual method structure.
const findAllByQueryParamsMock = async (query: any) => expectedResult;
// I am telling jest to spy on the findAllByQueryParams method
// and run the mock method when the findAllByQueryParams method is called in the controller.
jest
.spyOn(sampleService, 'findAllByQueryParams')
.mockImplementation(findAllByQueryParamsMock);
const actualResult = await sampleController.findAll();
expect(actualResult).toBe(expectedResult);
);
);
);
【讨论】:
【参考方案2】:使用您当前的设置,最简单的方法是使用module.get()
,就像您已经用于控制器一样,并传入EVENT_EMITTER_TOKEN
常量,然后将其保存到@987654324 中声明的值@block,就像let testController: TestController
的工作原理一样。这样的事情就足够了:
import Test, TestingModule from '@nestjs/testing';
import TestController from './test.controller';
import EventEmitter = require('events');
import EVENT_EMITTER_TOKEN from 'nest-emitter';
import MyEmitter from './test.events';
describe('Test Controller', () =>
let testController: TestController;
let myEmitter: MyEmitter;
beforeEach(async () =>
const module: TestingModule = await Test.createTestingModule(
imports: [],
providers: [
provide: EVENT_EMITTER_TOKEN,
useValue:
emit: jest.fn(),
,
,
],
controllers: [TestController],
).compile();
testController = module.get<TestController>(TetsController);
myEmitter = module.get<MyEmitter>(EVENT_EMITTER_TOKEN);
);
describe('postWebhook', () =>
it('should send the event', async () =>
const myEmitterSpy = jest.spyOn(myEmitter, 'emit'); // you can also add on mockResponse type functions here like mockReturnValue and mockResolvedValue
const result = await testController.postWebhook(...);
expect(myEmitterSpy).toBeCalledTimes(1);
);
);
);
【讨论】:
非常感谢!!您的解决方案效果很好。终于这么简单了:) 如果您正在寻找更多示例,您可以查看I've got an entire repository 感谢您提供链接和此存储库。会有帮助的!以上是关于使用注入对 NestJS 控制器进行单元测试的主要内容,如果未能解决你的问题,请参考以下文章