NestJS Jest测试报错:无法解析非类提供者令牌依赖,求解决
NestJS Jest测试报错:POSTGRES_PROVIDERDataSource无法解析
错误信息
Nest can't resolve dependencies of the POSTGRES_PROVIDER_CategoriesRepository (?). Please make sure that the argument POSTGRES_PROVIDERDataSource at index [0] is available in the TypeOrmModule context. Potential solutions: - Is TypeOrmModule a valid NestJS module? - If POSTGRES_PROVIDERDataSource is a provider, is it part of the current TypeOrmModule? - If POSTGRES_PROVIDERDataSource is exported from a separate @Module, is that module imported within TypeOrmModule? @Module({ imports: [ /* the Module containing POSTGRES_PROVIDERDataSource */ ] })
相关代码
测试文件 categories.service.spec.ts
import { Test, TestingModule } from '@nestjs/testing'; import { CategoriesModule } from './categories.module'; describe('CategoriesService', () => { let testModule: TestingModule; beforeEach(async () => { testModule = await Test.createTestingModule({ imports:[CategoriesModule] }).compile(); }); it('should validate the app module', () => { expect(testModule).toBeDefined(); }); });
CategoriesModule 配置
import { Module } from "@nestjs/common"; import { CategoriesService } from "./categories.service"; import { CategoriesRepository } from "./categories.repository"; import { DATABASE_TOKENS, SERVICE_TOKENS } from "../../src/constants"; import { TypeOrmModule } from "@nestjs/typeorm"; import { Categories } from "./models/Categories"; @Module({ imports: [TypeOrmModule.forFeature([Categories], DATABASE_TOKENS.POSTGRES_PROVIDER)], providers: [{ provide: SERVICE_TOKENS.CATEGORIES_SERVICE, useClass: CategoriesService }, { provide: SERVICE_TOKENS.CATEGORIES_REPOSITORY, useClass: CategoriesRepository }, ], exports: [SERVICE_TOKENS.CATEGORIES_SERVICE, SERVICE_TOKENS.CATEGORIES_REPOSITORY] }) export class CategoriesModule { }
AppModule 导入配置
@Module({ imports: [ TypeOrmModule.forRootAsync({ name: DATABASE_TOKENS.POSTGRES_PROVIDER, useClass: TypeOrmConfigServicePostGres, }), CategoriesModule, ], controllers: [AppController], providers: [AppService], })
CategoriesService 实现
import { Injectable, Inject } from "@nestjs/common"; import { Categories } from "./models/Categories"; import { ICategoryService } from "./categories.interface"; import { FetchCategoriesDTO } from "./categories.dto"; import { SERVICE_TOKENS } from "../../src/constants"; import { ICategoryRepository } from "./categories.interface"; @Injectable() export class CategoriesService implements ICategoryService { constructor( @Inject(SERVICE_TOKENS.CATEGORIES_REPOSITORY) private readonly _categoryRepository: ICategoryRepository, ) {} async fetchCategories(dto: FetchCategoriesDTO): Promise<Categories[]> { const { onlyActive } = dto; return this._categoryRepository.fetchCategories(onlyActive); } }
CategoriesRepository 实现
import { Injectable } from "@nestjs/common"; import { ICategoryRepository } from "./categories.interface"; import { InjectRepository } from "@nestjs/typeorm"; import { DATABASE_TOKENS } from "../../src/constants"; import { Categories } from "./models/Categories"; import { Repository } from "typeorm"; @Injectable() export class CategoriesRepository implements ICategoryRepository { constructor( @InjectRepository(Categories, DATABASE_TOKENS.POSTGRES_PROVIDER) private readonly _categories: Repository<Categories>, ) {} async fetchCategories(onlyActive: boolean): Promise<Categories[]> { const queryObject = onlyActive ? { isActive: true } : {}; console.log(queryObject); return this._categories.find({ where: queryObject, }); } }
错误原因
测试模块仅导入了CategoriesModule,但未初始化对应名称的TypeOrm数据源。在生产环境中,AppModule通过TypeOrmModule.forRootAsync配置了名为POSTGRES_PROVIDER的数据源,而测试上下文缺少这一步,导致Nest无法解析CategoriesRepository依赖的POSTGRES_PROVIDERDataSource。
修复方案
方案一:集成测试 - 初始化测试数据源
在测试模块中添加内存数据库的TypeOrm配置,模拟真实数据库环境:
import { Test, TestingModule } from '@nestjs/testing'; import { CategoriesModule } from './categories.module'; import { TypeOrmModule } from '@nestjs/typeorm'; import { DATABASE_TOKENS } from '../../src/constants'; import { Categories } from './models/Categories'; import { SERVICE_TOKENS } from '../../src/constants'; describe('CategoriesService', () => { let testModule: TestingModule; beforeEach(async () => { testModule = await Test.createTestingModule({ imports: [ // 初始化带指定名称的内存数据源 TypeOrmModule.forRoot({ name: DATABASE_TOKENS.POSTGRES_PROVIDER, type: 'sqlite', database: ':memory:', entities: [Categories], synchronize: true, dropSchema: true, }), CategoriesModule, ], }).compile(); }); it('should validate the module', () => { expect(testModule).toBeDefined(); }); it('should fetch categories correctly', async () => { const service = testModule.get(SERVICE_TOKENS.CATEGORIES_SERVICE); const categories = await service.fetchCategories({ onlyActive: false }); expect(categories).toBeInstanceOf(Array); }); });
方案二:单元测试 - Mock仓库依赖
如果不需要测试数据库交互,直接Mock掉ICategoryRepository,专注于Service逻辑:
import { Test, TestingModule } from '@nestjs/testing'; import { CategoriesService } from './categories.service'; import { SERVICE_TOKENS } from '../../src/constants'; import { ICategoryRepository } from './categories.interface'; // Mock仓库的实现逻辑 const mockCategoryRepo: Partial<ICategoryRepository> = { fetchCategories: jest.fn().mockResolvedValue([ { id: 1, name: '测试分类', isActive: true } ]), }; describe('CategoriesService', () => { let service: CategoriesService; beforeEach(async () => { const module = await Test.createTestingModule({ providers: [ CategoriesService, { provide: SERVICE_TOKENS.CATEGORIES_REPOSITORY, useValue: mockCategoryRepo, }, ], }).compile(); service = module.get<CategoriesService>(CategoriesService); }); it('should be defined', () => { expect(service).toBeDefined(); }); it('should call repository to fetch categories', async () => { const result = await service.fetchCategories({ onlyActive: true }); expect(result).toHaveLength(1); expect(mockCategoryRepo.fetchCategories).toHaveBeenCalledWith(true); }); });
内容的提问来源于stack exchange,提问作者chaithu
相关产品推荐
相关产品推荐

