首页 > 解决方案 > Nestjs单元测试添加第二个服务模块手动模拟不起作用

问题描述

我使用 Nest 开发应用程序后端,当我编写单元测试时,我发现如果我只添加一个服务模块手动模拟,模拟工作正常。但是,如果我为第二个服务模块添加手动模拟,则测试出错并出现错误“...不是函数”,当只有一个服务模块模拟时,它工作得很好。测试框架是 Jest,有人知道为什么会这样吗?

下面是一个例子,在阅读器控制器单元测试中,原来只是在mocks文件夹中使用 readerService 手动模拟,所有测试用例都通过了。然后我需要添加一个 tokenService 依赖项,所以我也在mocks文件夹中添加了 tokenService 手动模拟,然后所有测试用例(之前都通过)没有通过,因为“this.readerService.*** is not a function”,看起来就像添加第二个手动模拟导致第一个手动模拟在某处失败。以下是单元测试代码的一部分:

import { ReaderController } from './reader.controller';
import { ReaderService } from './reader.service';
import { TokenService } from './token.service';

jest.mock('./reader.service').mock('./token.service');

describe('ReaderController', () => {
  let readerController: ReaderController;
  let readerService: ReaderService;
  let tokenService: TokenService;

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

    readerController = module.get<ReaderController>(ReaderController);
    readerService = module.get<ReaderService>(ReaderService);
    tokenService = module.get<TokenService>(TokenService);
    jest.clearAllMocks();
  });

describe('getProfile', () => {
    describe('when getProfile is called', () => {
      let reader: Reader;

      beforeEach(async () => {
        reader = await readerController.getProfile(readerStub()._id);
      });

      test('then it should call readerService', () => {
        expect(readerService.getProfile).toHaveBeenCalledWith(readerStub()._id);
      });

      test('then it should return a reader object', () => {
        expect(reader).toEqual(readerStub());
      });
    });
  });

以下是 ReaderService 的手动模拟:

export const ReaderService = jest.fn().mockReturnValue({
  register: jest.fn().mockResolvedValue(readerStub()),
  findOne: jest.fn().mockResolvedValue(readerStub()),
  getProfile: jest.fn().mockResolvedValue(readerStub()),
  updateProfile: jest.fn().mockResolvedValue(readerStub()._id),
  changePwd: jest.fn().mockResolvedValue(readerStub().username),
  login: jest.fn().mockResolvedValue(accessTokenStub()),
  tokenRefresh: jest.fn().mockReturnValue(accessTokenStub()),
  logout: jest.fn().mockResolvedValue(readerStub()._id),
  addFavourBook: jest.fn().mockResolvedValue(2),
  getFavourBookList: jest.fn().mockResolvedValue(readerStub().favouriteBook),
  delFavourBook: jest.fn().mockResolvedValue(2),
  getReadBooks: jest.fn().mockResolvedValue([bookStub()]),
  getReadHistory: jest.fn().mockResolvedValue(readerStub().readHistory),
});

以下是 TokenService 的手动模拟:

export const TokenService = jest.fn().mockReturnValue({
  createToken: jest.fn().mockResolvedValue(tokenStub()),
  verifyToken: jest.fn().mockResolvedValue(true),
  delToken: jest.fn().mockResolvedValue(tokenStub().readerName),
  resetPwd: jest.fn().mockResolvedValue(tokenStub().readerName),
  verifyEmail: jest.fn().mockResolvedValue(tokenStub().readerName),
});

所有这些模拟文件都位于测试文件文件夹下的模拟文件中,所有这些设置都遵循 Jest 文件。谢谢你的帮助!

标签: mockingnestjsts-jest

解决方案


我刚刚找到了解决方法,使用手动模拟的主要服务,然后直接在测试中添加第二个服务的模拟定义,就在测试功能(第一个描述)之前。然后在测试模块定义中为第二个服务定义模拟(第一个服务只使用提供的原始名称),然后两个模拟都可以正常工作。我认为 Nest 在模拟折叠中手动使用 2 个服务模拟可能有一些限制。


推荐阅读