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

Nest.js测试无法解析ReportingService依赖:Sequelize不可用

Nest.js测试依赖解析错误解决方案

问题根源

  1. 缺少Sequelize依赖提供者:ReportingService构造函数中直接注入了Sequelize实例,但测试模块未提供该依赖的模拟实现,导致Nest无法解析依赖。
  2. 类属性初始化时机错误:materialIdAttributes和materialIdOrder作为类级属性,会在构造函数执行前初始化,此时this.sequelize还未被注入,会直接抛出undefined错误,即便解决依赖注入也无法正常运行。

解决方案步骤

1. 为测试模块添加Sequelize模拟提供者

在reporting.service.spec.ts的测试模块中,补充Sequelize的模拟实现,确保Nest能解析该依赖:

import { getModelToken } from '@nestjs/sequelize';
import { Test } from '@nestjs/testing';
import { Sequelize } from 'sequelize-typescript';
import { MasterML } from '../../../src/simply/reporting/reporting.model';
import { ReportingService } from '../../../src/simply/reporting/reporting.service';

const testMaterialIds: string[] = [
  'MTRL-1',
  'MTRL-2',
  'MTRL-3',
];

// 模拟Sequelize核心方法
const mockSequelize = {
  fn: jest.fn((fnName, col) => `${fnName}(${col}`),
  literal: jest.fn((str) => str),
  col: jest.fn((colName) => colName),
};

describe('ReportingService', () => {
  let service: ReportingService;
  let masterMlModel: typeof MasterML;

  beforeEach(async () => {
    const module = await Test.createTestingModule({
      providers: [
        ReportingService,
        {
          provide: getModelToken(MasterML),
          useValue: {
            // 修正模拟返回值,匹配服务中map操作的结构
            findAll: jest.fn(() => testMaterialIds.map(id => ({ materialId: id }))),
          },
        },
        // 添加Sequelize模拟提供者
        {
          provide: Sequelize,
          useValue: mockSequelize,
        },
      ],
    }).compile();
    service = module.get(ReportingService);
    masterMlModel = module.get<typeof MasterML>(getModelToken(MasterML));
  });

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

  it('getMaterialIds - should return expected material IDs', async () => {
    const result = await service.getMaterialIds('PLNT1');
    expect(result).toEqual(testMaterialIds);
  });

  it('should call findAll with correct parameters', async () => {
    await service.getMaterialIds('PLNT1');
    expect(masterMlModel.findAll).toHaveBeenCalledWith({
      attributes: expect.any(Array),
      where: { plantId: 'PLNT1' },
      order: expect.any(Array),
    });
  });
});

2. 修复服务中类属性的初始化时机

将materialIdAttributes和materialIdOrder从类级属性改为构造函数内初始化,确保this.sequelize已注入后再创建配置:

import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/sequelize';
import { Sequelize } from 'sequelize-typescript';
import { MasterML } from './reporting.model';

@Injectable()
export class ReportingService {
  materialIdAttributes: any[];
  materialIdOrder: any[];

  constructor(
    public sequelize: Sequelize,
    @InjectModel(MasterML) private readonly masterMl: typeof MasterML,
  ) {
    // 构造函数内初始化属性,此时this.sequelize已可用
    this.materialIdAttributes = [
      [
        this.sequelize.fn('DISTINCT', this.sequelize.col('MATERIAL_ID')),
        'materialId',
      ],
    ];

    this.materialIdOrder = [[this.sequelize.literal('materialId ASC')]];
  }

  async getMaterialIds(
    plantId: string,
  ): Promise<string[] | []> {
    return this.masterMl.findAll({
      attributes: this.materialIdAttributes,
      where: { plantId },
      order: this.materialIdOrder,
    }).then((rows) => rows.map((row) => row.materialId));
  }
}

额外说明

  • 原测试中findAll的模拟返回值不符合服务逻辑,改为返回包含materialId属性的对象数组,确保map操作能正确提取ID。
  • 模拟Sequelize的fn、literal、col方法,保证服务中的查询配置能正常生成。

内容的提问来源于stack exchange,提问作者Praneeth Karnena

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 10:44:55