如何将导入的函数模拟到 NestJs 的测试套件中?

How to mock an imported function into a test suite in NestJs?

我想为我的支付服务编写单元测试,但我收到此错误:

source.subscribe is not a function
 at ./node_modules/rxjs/src/internal/lastValueFrom.ts:60:12

这是我的服务

import { HttpService } from '@nestjs/axios';
import { Injectable } from '@nestjs/common';
import { lastValueFrom } from 'rxjs';
import { PaymentInfo } from 'src/utils/types/paymentInfo';

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

  private createHeaderWithAuth(auth, contentType = 'application/json') {
    return {
      headers: {
        authorization: auth.replace('Bearer', '').trim(),
        'Content-Type': contentType,
      },
    };
  }

  async makePayment(auth: string, paymentInfo: PaymentInfo) {
    const configs = this.createHeaderWithAuth(auth);
    const response = await lastValueFrom(
      await this.httpService.post(
        `${process.env.PAYMENT_URL}/transaction/pay`,
        paymentInfo,
        configs
      )
    ).catch((error) => {
      console.log(error);
      throw new Error(error.response.data.message);
    });

    return response.data;
  }
}

所以经过一些搜索和修改发现这是由于我导入了一个 rxjs 函数来解析 axios 设置的可观察对象造成的。 我已经搜索了模拟此功能的方法,以便我可以正确地测试我的服务。但是他们 none 给了我一个解决方案,我发现的问题只围绕模块的功能,但是这些有 none 因为是从第三方库导入的。

这是我的测试套件:

describe('Payments Service', () => {
  let service: PaymentsService;

  let mockedHttpService = {
    post: jest
      .fn()
      .mockImplementation(
        async (
          url: string,
          paymentInfo: PaymentInfo,
          header = mockedHeader
        ) => {
          return { mockedSuccessfulResponse };
        }
      ),
    get: jest
      .fn()
      .mockImplementation(async (url: string, header = mockedHeader) => {
        return { ...mockedSuccessfulResponse, data: mockedUserCards };
      }),
  };
  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        PaymentsService,
        {
          provide: HttpService,
          useValue: mockedHttpService,
        },
      ],
    }).compile();
    service = module.get<PaymentsService>(PaymentsService);
  });

  
  describe('Initialize', () => {
    it('should define service', () => {
      expect(service).toBeDefined();
  });

  describe('makePayment', () => {
    it('should make a payment', async () => {
      const payment = await service.makePayment(mockedAuth, mockedPaymentInfo);
      expect(mockedHttpService.post).toHaveBeenCalledWith(
        `${process.env.PAYMENT_URL}/transaction/pay`,
        mockedPaymentInfo,
        mockedHeader
      );

      expect(payment).toBe(mockedSuccessfulResponse);
    });
  });
  });

Ps.: 我删除了模拟对象以减少要读取的代码量

您应该使用 rxjs 中的 of 运算符,并删除 async 关键字。喜欢:

      .mockImplementation(
        (
          url: string,
          paymentInfo: PaymentInfo,
          header = mockedHeader
        ) => {
          return of({ mockedSuccessfulResponse });
        }

否则lastValueFrom将不会收到可观察对象。