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

使用MikroORM的NestJS服务单元测试依赖注入失败问题排查

解决Nest+MikroORM单元测试中EntityRepository依赖注入失败问题

问题场景

我有一个基于MikroORM与MySQL正常协作的TestService,编写单元测试时,仅执行服务实例化的基础测试就报错。测试文件内已定义TestEntity、模拟Repository并配置测试模块,但运行时Nest提示无法解析TestService的EntityRepository依赖。

测试代码

import { Test, TestingModule } from '@nestjs/testing';
import { Entity, EntityRepository, Property, Unique } from '@mikro-orm/core';
import { getRepositoryToken } from '@mikro-orm/nestjs';
import { TestService } from './mikro-orm.service';

@Entity()
export class TestEntity {
    @Property() @Unique() public Code: number;
    @Property({ length: 20 }) @Unique() public Description: string;

    constructor(Code: number, Description: string) {
        this.Code = Code;
        this.Description = Description;
    }
}

describe('TestService', () => {
    let service: TestService<TestEntity>;
    let serviceRepository: EntityRepository<TestEntity>;

    const REPOSITORY_TOKEN = getRepositoryToken(TestEntity);
    beforeEach(async () => {
        const mockDataRepository = {
            provide: REPOSITORY_TOKEN,
            useValue: {
                findAll: jest.fn(),
                findOne: jest.fn(),
            },
        };

        const module: TestingModule = await Test.createTestingModule({
            providers: [TestService, mockDataRepository],
        }).compile();

        service = module.get<TestService<TestEntity>>(TestService);
        serviceRepository = module.get<EntityRepository<TestEntity>>(REPOSITORY_TOKEN);
    });

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

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

服务构造函数

constructor(private readonly DataEntity: EntityRepository<T_Entity>) {}

报错信息

TestService › should be defined

    Nest can't resolve dependencies of the TestService (?). Please make sure that the argument EntityRepository at index [0] is available in the RootTestModule context.

    Potential solutions:
    - If EntityRepository is a provider, is it part of the current RootTestModule?
    - If EntityRepository is exported from a separate @Module, is that module imported within RootTestModule?
      @Module({
        imports: [ /* the Module containing EntityRepository */ ]
      })

      at TestingInjector.lookupComponentInParentModules (../../node_modules/@nestjs/core/injector/injector.js:231:19)
      at TestingInjector.resolveComponentInstance (../../node_modules/@nestjs/core/injector/injector.js:184:33)
      at TestingInjector.resolveComponentInstance (../../node_modules/@nestjs/testing/testing-injector.js:16:45)
      at resolveParam (../../node_modules/@nestjs/core/injector/injector.js:106:38)
          at async Promise.all (index 0)
      at TestingInjector.resolveConstructorParams (../../node_modules/@nestjs/core/injector/injector.js:121:27)
      at TestingInjector.loadInstance (../../node_modules/@nestjs/core/injector/injector.js:52:9)
      at TestingInjector.loadProvider (../../node_modules/@nestjs/core/injector/injector.js:74:9)
          at async Promise.all (index 3)
      at TestingInstanceLoader.createInstancesOfProviders (../../node_modules/@nestjs/core/injector/instance-loader.js:44:9)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total

解决方案

核心问题是泛型类型擦除导致依赖注入令牌不匹配:Nest无法通过泛型EntityRepository<T_Entity>找到对应的实体Repository令牌,必须明确关联实体专属的注入令牌。

方案一:手动实例化服务(最简单直接)

跳过Nest的DI系统,直接手动创建服务实例并传入模拟的Repository:

describe('TestService', () => {
    let service: TestService<TestEntity>;
    let mockRepository: Partial<EntityRepository<TestEntity>>;

    beforeEach(() => {
        // 创建模拟Repository
        mockRepository = {
            findAll: jest.fn(),
            findOne: jest.fn(),
        };
        // 手动实例化服务
        service = new TestService(mockRepository as EntityRepository<TestEntity>);
    });

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

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

方案二:修正测试模块的DI配置

如果要保留Nest测试模块的用法,需要通过useFactory明确关联依赖令牌:

beforeEach(async () => {
    const mockDataRepository = {
        provide: getRepositoryToken(TestEntity),
        useValue: {
            findAll: jest.fn(),
            findOne: jest.fn(),
        },
    };

    const module: TestingModule = await Test.createTestingModule({
        providers: [
            {
                provide: TestService,
                // 通过工厂函数手动关联依赖
                useFactory: (repo) => new TestService<TestEntity>(repo),
                inject: [getRepositoryToken(TestEntity)],
            },
            mockDataRepository,
        ],
    }).compile();

    service = module.get<TestService<TestEntity>>(TestService);
    serviceRepository = module.get<EntityRepository<TestEntity>>(getRepositoryToken(TestEntity));
});

方案三:完善服务的依赖注入标记

在TestService的构造函数中添加@InjectRepository装饰器,明确指定实体类型,让Nest能正确识别注入令牌:

// 修改TestService的构造函数
import { InjectRepository } from '@mikro-orm/nestjs';
import { EntityRepository } from '@mikro-orm/core';

export class TestService<T_Entity> {
    constructor(
        @InjectRepository(T_Entity)
        private readonly DataEntity: EntityRepository<T_Entity>
    ) {}
}

注:如果TestService是针对特定实体的服务,直接将T_Entity替换为具体的实体类(如TestEntity)即可。

核心原因

TypeScript的泛型类型在编译后会被擦除,Nest的DI系统无法通过泛型EntityRepository<T_Entity>匹配到对应的实体Repository令牌。必须通过getRepositoryToken(EntityClass)获取实体专属的令牌,或手动关联依赖关系。

内容的提问来源于stack exchange,提问作者Steven Scott

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 15:15:44