【问题标题】:Unit testing NestJS controller with injection使用注入对 NestJS 控制器进行单元测试
【发布时间】: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);
    });
  });
});

非常感谢您的帮助。

【问题讨论】:

    标签: typescript unit-testing testing dependency-injection nestjs


    【解决方案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
      • 感谢您提供链接和此存储库。会有帮助的!
      猜你喜欢
      • 2022-08-09
      • 2013-07-27
      • 2016-11-14
      • 2012-01-31
      • 1970-01-01
      • 2017-04-26
      • 2020-05-03
      • 1970-01-01
      • 2013-05-01
      相关资源
      最近更新 更多