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

NestJS测试报错:Repository未注入,无法读取其属性

NestJS单元测试中ProfilesService的Repository注入失败问题

在对AdsService进行单元测试时,出现报错提示无法读取Repository的属性,报错触发点在ProfilesService的findByProfileId方法调用profileRepository.findOne时,推测是测试环境下Repository未成功注入。

相关业务代码

ads.module.ts

@Module({
  imports: [
    TypeOrmModule.forFeature([Ads]),
    ProfilesModule,
  ],
  providers: [AdsService],
  controllers: [AdsController],
  exports: [AdsService],
})
export class AdsModule {}

profile.module.ts

@Module({
  imports: [
    TypeOrmModule.forFeature([Profiles]),
  ],
  providers: [ProfilesService],
  controllers: [ProfilesController],
  exports: [ProfilesService],
})
export class ProfilesModule {}

ads.service.ts

@Injectable()
export class AdsService {
  constructor(
    @InjectRepository(Ads) private adsRepository: Repository<Ads>,
    private profileService: ProfilesService,
  ) {}

  create = async (createAdsDto: AdsDto) => {
    const profile = await this.profileService.findByProfileId(
      createAdsDto.profileId,
    ); 

    return null;
  }
}

profiles.service.ts

@Injectable()
export class ProfilesService {
  constructor(
    @InjectRepository(Profiles) private profileRepository: Repository<Profiles>
  ) {}

  findByProfileId = async (id: number): Promise<Profiles> => {
    // 以下代码触发报错
    const profile = await this.profileRepository.findOne({
      where: { id },
      relations: { user: true, avatar: true },
    });

    return profile;
  };
}

测试代码

ads.service.spec.ts

describe('AdsService', () => {
  let service: AdsService;
  let adsRepository: Repository<Ads>;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        AdsService,
        { 
          provide: getRepositoryToken(Ads), 
          useValue: {
            // 可根据测试需求添加AdsRepository需mock的方法
          } 
        },
        // 模拟ProfilesService,隔离依赖
        {
          provide: ProfilesService,
          useValue: {
            findByProfileId: jest.fn().mockResolvedValue({
              id: 1,
              user: {},
              avatar: {}
            })
          }
        }
      ],
    }).compile();

    service = module.get(AdsService);
    adsRepository = module.get<Repository<Ads>>(getRepositoryToken(Ads));
  });

  afterAll(() => {
    jest.resetAllMocks();
  });

  describe('Initial variables must be defined', () => {
    test('Ads Service must be defined', () => {
      expect(service).toBeDefined();
    });

    test('Ads Repository must be defined', () => {
      expect(adsRepository).toBeDefined();
    });

    test('can create ads', async () => {
      const ads = await service.create({
        profileId: 1,
        type: 'Oferta',
        category: 'Vivienda',
        location: 'Alicante',
        title: 'Apartment For Rent',
        description: 'This is a sample description',
        extract: 'This is a sample extract short description',
      } as AdsDto);
      expect(ads).toBeNull();
      // 验证ProfilesService的方法调用情况
      const profileService = module.get(ProfilesService);
      expect(profileService.findByProfileId).toHaveBeenCalledWith(1);
    });
  });
});

报错截图

测试结果截图

问题原因及解决方案

问题原因

直接使用useClass: Repository创建Repository实例时,TypeORM的Repository依赖EntityManager等内部资源,测试环境下未初始化这些资源,导致实例内部属性为undefined,调用findOne时触发报错。

解决方案

针对AdsService的单元测试,核心是验证AdsService的逻辑,因此应隔离依赖,直接模拟ProfilesService的方法,而非引入真实的ProfilesService及其依赖的Repository:

  1. 在测试模块的providers中,用useValue模拟ProfilesService,预先定义findByProfileId的返回值;
  2. 无需手动注入ProfilesRepository,因为已mock了ProfilesService的行为;
  3. 若需验证依赖方法的调用情况,可在测试中获取mock的ProfilesService,验证方法调用次数和参数。

如果需要单独测试ProfilesService,才需正确模拟其依赖的Repository,此时可用useValue提供包含mock方法的对象,例如:

{
  provide: getRepositoryToken(Profiles),
  useValue: {
    findOne: jest.fn().mockResolvedValue({ id: 1, user: {}, avatar: {} })
  }
}

内容的提问来源于stack exchange,提问作者Benjoe Carandang

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 10:26:30