如何使用从控制器返回的值?在NestJs上测试控制器

5

测试控制器和方法:

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。


1
你想要注入响应并自己管理它,而不是让Nest来处理它,有什么原因吗? - Jay McDoniel
1个回答

9

好的,我想你的问题在于您实例化和使用控制器和服务的方式上。
NestJs测试工具来为您完成这项工作,像这样:

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);
      });
    }); 
});

我自己没有测试过这段代码,所以你可以试一下(但是对于Parts Controller中响应模拟的Response类型,我不太确定)。

顺便提一下,关于Parts Controller,你应该利用express的Response类型——尝试按以下方式重写代码:

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 测试部分
- Nest 库的方法
在第二个链接中,在页面的开头几乎就声明了以下内容:在 https://docs.nestjs.com/controllers#request-object 部分中表示:
引用:
  • 为了与底层 HTTP 平台(例如 Express 和 Fastify)的 typings 兼容,Nest 提供了 @Res() 和 @Response() 装饰器。@Res() 只是 @Response() 的别名。它们直接暴露了底层本机平台响应对象接口。使用它们时,您还应导入底层库的 typings(例如 @types/express),以充分利用。请注意,当您在方法处理程序中注入 @Res() 或 @Response() 时,您将把 Nest 置于库特定模式下的处理程序,并且您将负责管理响应。在这样做时,您必须通过对响应对象进行调用(例如,res.json(...) 或 res.send(...))发出某种响应,否则 HTTP 服务器将挂起。
希望这能有所帮助,如果有评论或分享您的解决方案,欢迎留言! :)
顺便说一句,欢迎来到 StackOverflow 平台!

1
我正在跟随您的解决方案,但是我一直收到 Type '{ json: (body?: User[]) => void; status: (code: number) => HttpStatus; }' is missing the following properties from type 'Response': sendStatus, links, send, jsonp, and 78 more 的错误信息。您如何避免包含 Response 的所有参数? - asus
@asus你有关于那个的解决方案吗? - Seba M
你尝试过用 as Response 包装你的模拟对象吗?这样 TypeScript 就不会因为缺少最终测试目的不需要的属性而报错了。 - A. Maitre
1
我也遇到了同样的问题,如果你把部分代码键入为as any as Response,那么类型错误就会消失。这个答案来自于 https://dev59.com/UFMH5IYBdhLWcg3w10B_ - zmanc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接