【问题标题】:How to use value which returned from controller? Testing controllers on NestJs如何使用从控制器返回的值?在 NestJs 上测试控制器
【发布时间】:2020-01-27 20:46:38
【问题描述】:

控制器和测试方法:

import { Controller, Get, Response, HttpStatus, Param, Body, Post, Request, Patch, Delete, Res } from '@nestjs/common';
@Controller('api/parts')
export class PartController {
  constructor(private readonly partsService: partsService) { }

  @Get()
  public async getParts(@Response() res: any) {
    const parts = await this.partsService.findAll();
    return res.status(HttpStatus.OK).json(parts);
  }
}

这是单元测试,必须测试 getParts 方法:

describe('PartsController', () => {
  let partsController: PartsController;
  let partsService: partsService;

  beforeEach(async () => {
    partsService = new partsService(Part);
    partsController= new PartsController(partsService);
  });

  describe('findAll', () => {
    it('should return an array of parts', async () => {
      const result = [{ name: 'TestPart' }] as Part[];

      jest.spyOn(partsService, 'findAll').mockImplementation(async () => result);

      const response = {
        json: (body?: any) => {
          expect(body).toBe(result);
        },
        status: (code: number) => response,
      };

      await partsController.getParts(response);
    });
  });
});

这个测试工作正常,但我认为这是一个糟糕的解决方案。当我调查这个问题时,我看到了这个选项:

const response = {
  json: (body?: any) => {},
  status: (code: number) => response,
};
expect(await partsController.getParts(response)).toBe(result);

但是当我尝试它时,我的测试不起作用,导致 await partsController.getParts(response) // undefined 那么我应该怎么做才能让我的测试看起来不错呢?

在我使用的解决方案中:nodeJS sequelize、nestJS、typescript

【问题讨论】:

  • 您是否有任何理由想要注入响应并自行管理,而不是让 Nest 为您处理?

标签: node.js unit-testing testing nestjs sequelize-typescript


【解决方案1】:

好吧,我猜你的问题在于你实例化和使用你的控制器和服务的方式。
NestJs Testing utils 为您完成这项工作,如下所示:

describe('Parts Controller', () => {
    let partsController: PartsController;
    let partsService: PartsService;

    beforeEach(async () => {
        // magic happens with the following line
        const module = await Test.createTestingModule({
            controllers: [
                PartsController
            ],
            providers: [
                PartsService
                //... any other needed import goes here
            ]
        }).compile();

        partsService = module.get<PartsService>(PartsService);
        partsController = module.get<PartsController>(PartsController);
    });

    // The next 4 lines are optional and depends on whether you would need to perform these cleanings of the mocks or not after each tests within this describe section
    afterEach(() => {
        jest.restoreAllMocks();
        jest.resetAllMocks();
    });

    it('should be defined', () => {
        expect(partsController).toBeDefined();
        expect(partsService).toBeDefined();
    });

    describe('findAll', () => {
      it('should return an array of parts', async () => {
        const result: Part[] = [{ name: 'TestPart' }];

        jest.spyOn(partsService, 'findAll').mockImplementation(async (): Promise<Part[]> => Promise.resolve(result));

        const response = {
            json: (body?: any) => {},
            status: (code: number) => HttpStatus.OK,
        };

        expect(await partsController.getParts(response)).toBe(result);
      });
    }); 
});

我自己没有测试过代码,所以试一试(不太确定零件控制器中响应类型的响应模拟)。
顺便说一下,关于部件控制器,您应该利用 express 的响应类型 - 尝试重写代码如下:

import { Controller, Get, Response, HttpStatus, Param, Body, Post, Request, Patch, Delete, Res } from '@nestjs/common';
import { Response } from 'express';

@Controller('api/parts')
export class PartController {
  constructor(private readonly partsService: partsService) { }

  @Get()
  public async getParts(@Response() res: Response) { // <= see Response type from express being used here
    const parts = await this.partsService.findAll();
    return res.status(HttpStatus.OK).json(parts);
  }
}

最后看一下nest官方文档的这一部分,也许它可以让你对你想要实现的目标有所了解:
- Nest testing section
- Nest library approach

在第二个链接中,几乎在页面的开头,在https://docs.nestjs.com/controllers#request-object 部分中声明如下:

  • 为了与跨底层 HTTP 平台(例如 Express 和 Fastify)的类型兼容,Nest 提供了 @Res() 和 @Response() 装饰师。 @Res() 只是@Response() 的别名。两者都直接 暴露底层原生平台响应对象接口。什么时候 使用它们,您还应该导入底层的类型 库(例如,@types/express)以充分利用。请注意,当 你在方法处理程序中注入@Res() 或@Response(),你把 嵌套到该处理程序的特定于库的模式中,您将成为 负责管理响应。这样做时,您必须发出 通过调用响应对象(例如, res.json(...) 或 res.send(...)),否则 HTTP 服务器将挂起。

希望它有所帮助,不要犹豫发表评论,或分享您的解决方案,如果它有助于找到另一个解决方案! :)

顺便欢迎来到 StackOverflow 平台!

【讨论】:

  • 我正在关注您的解决方案,但我不断收到Type '{ json: (body?: User[]) =&gt; void; status: (code: number) =&gt; HttpStatus; }' is missing the following properties from type 'Response': sendStatus, links, send, jsonp, and 78 more。你将如何避免包含Response 的所有参数?
  • @asus 你有解决方案吗
  • 您是否尝试过使用 as Response 包装您的模拟对象,这样 TypeScript 就不会因为缺少您最终不需要用于测试目的的道具而哭泣?
  • 我也遇到过这种情况,如果您将部分输入为as any as Response,那么您将消除类型错误。来自stackoverflow.com/questions/57964299/…
猜你喜欢
  • 2021-02-03
  • 1970-01-01
  • 2021-08-23
  • 1970-01-01
  • 2023-03-15
  • 1970-01-01
  • 2012-02-21
  • 1970-01-01
  • 2021-11-22
相关资源
最近更新 更多