【问题标题】:unit test service with external api带有外部 api 的单元测试服务
【发布时间】:2021-10-27 17:28:36
【问题描述】:

有人可以指导我对此控制器和查询外部api的服务进行单元测试,我已经做了一些我见过的事情,但我不知道它是否正确,感谢您的帮助。

photos.service.ts

import { HttpService } from '@nestjs/axios';
import { Injectable } from '@nestjs/common';

@Injectable()
export class PhotosService {
  constructor(private httpService: HttpService) {}

  async getPhotos() {
    return this.httpService.axiosRef.get(
      `https://jsonplaceholder.typicode.com/photos`,
    );
  }
}

photos.controller.ts

import { Controller, Get } from '@nestjs/common';
import { PhotosService } from './photos.service';

@Controller('photos')
export class PhotosController {
  constructor(private api: PhotosService) {}

  @Get()
  async getPhotos() {
    return this.api.getPhotos();
  }
}

photos.controller.spec.ts

import { HttpModule } from '@nestjs/axios';
import { HttpStatus } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import { AxiosResponse } from 'axios';
import { PhotosController } from './photos.controller';
import { PhotosService } from './photos.service';

describe('PhotosController', () => {
  let photosController: PhotosController;
  let photosService: PhotosService;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      controllers: [PhotosController],
      providers: [PhotosService],
      imports: [HttpModule],
    }).compile();

    photosController = module.get<PhotosController>(PhotosController);
    photosService = module.get<PhotosService>(PhotosService);
  });

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

  describe('getPhotos', () => {
    it('should return a user', async () => {
      const data = ['test'];
      const response: AxiosResponse<any> = {
        data,
        headers: {},
        config: { url: 'http://localhost:3000/mockUrl' },
        status: 500,
        statusText: 'OK',
      };
      jest
        .spyOn(photosService, 'getPhotos')
        .mockImplementation(async () => response);

      expect(await photosController.getPhotos()).toEqual(response);
    });
  });
});

【问题讨论】:

  • 错误是什么?

标签: typescript unit-testing jestjs nestjs


【解决方案1】:

我要说的第一件事是我将在 photos.service.spec.ts 内部而不是在控制器内部测试 getPhotos()

所以您的控制器测试代码如下所示:

photos.controller.spec.ts

describe('PhotosController', () => {
  let photosController: PhotosController;
  let photosService: PhotosService;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      controllers: [PhotosController],
      providers: [PhotosService],
      imports: [HttpModule],
    }).compile();

    photosController = module.get<PhotosController>(PhotosController);
    photosService = module.get<PhotosService>(PhotosService);
  });

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

  describe('getPhotos', () => {
    it('should call service.getPhotos()', async () => {
      const spy = jest.spyOn(photosService, 'getPhotos');
      await photosController.getPhotos();
      expect(spy).toHaveBeenCalled();
    });
  });
});

虽然您的服务测试代码看起来像您最初编写的那样:

photos.service.spec.ts

describe('PhotosService', () => {
  let photosService: PhotosService;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      controllers: [PhotosController],
      providers: [PhotosService],
      imports: [HttpModule],
    }).compile();

    photosService = module.get<PhotosService>(PhotosService);
  });

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

  describe('getPhotos', () => {
    it('should return a user', async () => {
      const data = ['test'];
      const response: AxiosResponse<any> = {
        data,
        headers: {},
        config: { url: 'http://localhost:3000/mockUrl' },
        status: 500,
        statusText: 'OK',
      };
      jest
        .spyOn(photosService, 'getPhotos')
        .mockImplementation(async () => response);

      expect(await photosService.getPhotos()).toEqual(response);
    });
  });
});

这样可以确保控制器逻辑和服务逻辑之间的分离更加清晰,并且随着代码的增长,它会变得更好。

另外,为了更清楚,您可以像这样在 Jest 中轻松地模拟 Promises:

jest
  .spyOn(photosService, 'getPhotos')
  .mockResolvedValue(response);

如果它应该解决,或者像这样测试拒绝:

jest
  .spyOn(photosService, 'getPhotos')
  .mockRejectedValue(errorResponse);

最后一个无关紧要的细节是你的response 模拟有一个状态代码500 和一个状态'OK',但它显然并不重要;)

我希望这是一个明确的答案,祝你项目的其余部分好运。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-27
    相关资源
    最近更新 更多