使用Jest测试NestJS应用时遭遇循环依赖问题求助
NestJS Jest单元测试循环依赖问题解决
问题场景
基于Mongoose的NestJS应用运行阶段无异常,但使用Jest编写单元测试时触发循环依赖错误。注释掉测试模块中providers: [PrivateClientService]后测试可正常通过。
测试代码
// client.controller.spec.ts import { Test } from '@nestjs/testing' import { PrivateClientService } from '../client.service' import { responseMock } from '@test/mocks/response.mock' jest.mock('../client.service') describe('PrivateClientController', () => { let privateClientService: PrivateClientService beforeEach(async () => { console.log(responseMock) // 别名导入正常工作 const moduleRef = await Test.createTestingModule({ imports: [], // controllers: [], providers: [PrivateClientService], }).compile() jest.clearAllMocks() }) describe('createClient', () => { it('should passed', () => { expect(true).toBe(true) }) }) })
服务代码
// client.service.ts import { Injectable, NotFoundException } from '@nestjs/common' import { isValidObjectId } from 'mongoose' import { InvalidObjectIdException } from '@framework/exceptions/InvalidObjectId.exception' import { Client } from '../schemas/client.schema' import { ClientRepository } from '../client.repository' @Injectable() export class PrivateClientService { constructor(private readonly clientRepository: ClientRepository) {} async createClient(client: Client): Promise<Client> { const newClient = await this.clientRepository.create(client) return newClient } async updateClient(id: string, client: Client): Promise<Client> { if (!isValidObjectId(id)) throw new InvalidObjectIdException() const updatedClient = await this.clientRepository.findByIdAndUpdate(id, client) if (!updatedClient) { throw new NotFoundException() } return updatedClient } async deleteClient(id: string): Promise<Client> { if (!isValidObjectId(id)) throw new InvalidObjectIdException() const client = await this.clientRepository.findByIdAndDelete(id) if (!client) { throw new NotFoundException() } return client } }
原因分析
测试中使用jest.mock('../client.service')自动生成了PrivateClientService的mock类,但同时在TestingModule的providers中注册了真实的PrivateClientService类。而PrivateClientService依赖ClientRepository,测试模块未提供该依赖的mock实现,导致Nest的DI容器无法正确解析依赖链,最终触发类似循环依赖的错误提示(实际是依赖缺失导致的解析失败)。
解决方案
方案一:为ClientRepository提供Mock实现
在测试模块中手动添加ClientRepository的mock,让DI容器能正常创建PrivateClientService实例:
beforeEach(async () => { const moduleRef = await Test.createTestingModule({ providers: [ PrivateClientService, // 注入ClientRepository的mock对象 { provide: ClientRepository, useValue: { create: jest.fn().mockResolvedValue({}), findByIdAndUpdate: jest.fn().mockResolvedValue({}), findByIdAndDelete: jest.fn().mockResolvedValue({}) } } ], }).compile() privateClientService = moduleRef.get(PrivateClientService) jest.clearAllMocks() })
方案二:直接使用Jest生成的Mock服务
既然已经通过jest.mock生成了mock类,可直接使用该mock,同时补充依赖的mock:
beforeEach(async () => { const moduleRef = await Test.createTestingModule({ providers: [ PrivateClientService, { provide: ClientRepository, useValue: jest.fn() } ], }).compile() privateClientService = moduleRef.get(PrivateClientService) jest.clearAllMocks() })
核心要点:测试时必须为服务的所有依赖提供mock实现,否则Nest无法完成依赖注入,进而抛出错误。
内容的提问来源于stack exchange,提问作者Raphael Rlt
相关产品推荐
相关产品推荐

