用Jest测试NestJs API控制器

时间:2020-10-20 09:45:22

标签: api jestjs nestjs

我正在使用NestJs和mysql创建一个API。 我创建新实体的控制器功能运行良好,但是,我无法测试响应为400错误的用例。

这是控制器功能:

@Controller('pubs')
export class PubsController {
   constructor(private readonly pubsService: PubsService) {}
   @Post()
   async create(@Body() createPubDto: CreatePubDto, @Res() res: Response): Promise<void> {
     this.pubsService.create(createPubDto)
       .then(() => res.status(201).json())
       .catch(err => res.status(401).json({ err }));
   }
}

这是测试文件:

describe('PubsController', () => {
  let controller: PubsController;
  let service: PubsService;
  const mockResponse = () => {
    const res: any = {};
    res.status = jest.fn().mockReturnValue(res);
    res.json = jest.fn().mockReturnValue(res);
    return res;
  };

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      controllers: [PubsController],
      providers: [PubsService, {
        provide: getRepositoryToken(Pub),
        useValue: {},
      }],
    }).compile();

    controller = module.get<PubsController>(PubsController);
    service = module.get<PubsService>(PubsService);
  });

  afterEach(() => {
    jest.resetAllMocks();
    jest.clearAllMocks();
  });

  describe('create success', () => {
    const res = mockResponse();
    it('Should create a pub', async () => {
      const req = mockedPub;
      jest.spyOn(service, 'create').mockResolvedValue(mockedPub);
      await controller.create(req, res);
      expect(res.status).toHaveBeenCalledWith(201);
    });
    it('Should return 400 if the body is not correct', async () => {
      const req: any = {};
      jest.spyOn(service, 'create').mockResolvedValue(req);
      await controller.create(req, res);
      expect(res.status).toHaveBeenCalledWith(400);
    });
  }) 
});

“应该创建一个酒吧”运行良好,但是当我给create函数一个空对象时,测试会给我一个201 res.status。

    expect(jest.fn()).toHaveBeenCalledWith(...expected)

    Expected: 400
    Received: 201

有人知道为什么吗?

1 个答案:

答案 0 :(得分:0)

首先,您是否在代码中的任何地方使用任何验证管道来验证传入的CreatePubDto,例如在您的main.ts文件中或pubService中?

第二,在应该失败的测试中,您编写了jest.spyOn(service, 'create').mockResolvedValue(req);可以解决问题,因此您不会在控制器级别捕获任何错误,这意味着您可以进入自己的.then(() => res.status(201).json())控制器逻辑。

您应该将测试重构为:

it('Should return 400 if the body is not correct', async () => {
    const error: any = { message: 'bad DTO provided', code: 400 }; // <== this is where you mock the logic of your service to throw an error
    jest.spyOn(service, 'create').mockRejectedValue(error);
    await controller.create(req, res);
    expect(res.status).toHaveBeenCalledWith(400);
});

这样,您将告诉Jest在调用create方法时引发错误。我放置了可能抛出的错误示例,但可以随意使用将要抛出的错误格式。

也不要忘记将控制器中返回的错误代码与测试中期望的错误代码对齐。我猜在这种用例中,400会更合适。