You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 06:33:19