
在 Nest.js 单元测试中,当服务依赖 @InjectModel 注入的 Repository 或其他模块级提供者(如 SequelizeModule.forFeature)时,仅声明 providers 和基础 imports 会导致依赖解析失败;必须显式提供模型令牌或启用真实数据库连接。
在 nest.js 单元测试中,当服务依赖 `@injectmodel` 注入的 repository 或其他模块级提供者(如 `sequelizemodule.forfeature`)时,仅声明 `providers` 和基础 `imports` 会导致依赖解析失败;必须显式提供模型令牌或启用真实数据库连接。
要使 TestingModule 正确解析 WeatherRepo(其构造函数依赖 @InjectModel(Weather)),关键在于:@InjectModel(Weather) 所需的模型令牌必须在测试模块上下文中可用。该令牌由 SequelizeModule.forFeature([Weather]) 提供——它不仅注册了 WeatherRepo,更关键的是向 DI 容器注入了 Model
✅ 正确做法是:在 Test.createTestingModule() 中 显式导入 SequelizeModule.forFeature([Weather]),并确保 Weather 模型已正确定义(含 @Model 装饰器或 Sequelize v6+ 的 Model.init() 配置)。若你希望完全控制行为(如用 jest.spyOn 模拟方法),不推荐使用 overrideProvider 或自动 Mock,而应保留真实 WeatherRepo 实例,并仅对它的依赖(如数据库操作)进行可控拦截。
以下是修正后的 weather.service.spec.ts 示例:
import { Test, TestingModule } from '@nestjs/testing';
import { HttpModule, HttpService } from '@nestjs/axios';
import { SequelizeModule, getModelToken } from '@nestjs/sequelize';
import { WeatherService } from './weather.service';
import { WeatherRepo } from './weather.repo';
import { Weather } from './weather.model'; // 确保模型路径正确
import { ConfigService } from '@nestjs/config';
describe('WeatherService', () => {
let weatherService: WeatherService;
let weatherRepo: WeatherRepo;
let httpService: HttpService;
let moduleRef: TestingModule;
beforeEach(async () => {
// ✅ 关键:导入 forFeature([Weather]),提供 @InjectModel(Weather) 所需的 Model token
moduleRef = await Test.createTestingModule({
imports: [
HttpModule,
SequelizeModule.forRoot({ // 可选:启用内存 SQLite 或测试 DB 连接
dialect: 'sqlite',
storage: ':memory:',
models: [Weather],
synchronize: true,
}),
SequelizeModule.forFeature([Weather]), // ← 必须包含此项!
],
providers: [
WeatherService,
WeatherRepo,
ConfigService,
],
}).compile();
weatherService = moduleRef.get(WeatherService);
weatherRepo = moduleRef.get(WeatherRepo);
httpService = moduleRef.get(HttpService);
});
it('should be defined', async () => {
// ✅ 现在可安全 spyOn WeatherRepo 的方法(如 findOrCreate、update)
jest.spyOn(weatherRepo, 'findOrCreate').mockResolvedValue({ instance: {}, created: false });
jest.spyOn(weatherRepo, 'update').mockResolvedValue(2);
// 模拟 HTTP 请求响应
jest.spyOn(httpService, 'get').mockResolvedValue({
data: { /* mock weather data */ },
});
// 执行被测逻辑
const result = await weatherService.fetchAndPersistWeather('London');
expect(result).toBeDefined();
});
afterEach(async () => {
if (moduleRef) await moduleRef.close();
});
});
⚠️ 注意事项:
- 若不希望连接真实数据库,可搭配 SequelizeMock 或使用 in-memory SQLite(如上例),确保模型同步(synchronize: true)且无迁移冲突;
- ConfigService 需要提供配置对象(可通过 useValue 注入),否则可能引发新错误;
- Weather 模型必须导出为类(非 typeof Weather),且 @InjectModel(Weather) 中的参数类型需与 forFeature 中传入的完全一致(包括 import 路径);
- 不要遗漏 afterEach 中的 moduleRef.close(),避免测试间状态污染。
总结:Nest 测试模块的依赖解析严格遵循模块边界。forFeature([Model]) 是 @InjectModel(Model) 的“供应方”,测试中不可省略——这是解决多层服务(Service → Repo → Model)依赖链的根本方案。










