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

在Next.js中用Tsyringe+Playwright实现DI:解决未注册依赖错误

解决Next.js + tsyringe 测试环境DI注入失败问题

核心问题定位

测试时抛出Error: Attempted to resolve unregistered dependency token: "IUser",本质是Playwright测试环境中,tsyringe容器未注册IUser对应的Mock实现,或者生产环境的注册逻辑在测试时没有被正确覆盖。

具体解决方案

1. 拆分DI注册逻辑,区分生产/测试环境

把容器注册代码拆成独立文件,避免硬编码实现类,方便测试时替换:

  • 创建di-registry.ts(生产环境注册):
import { container } from 'tsyringe';
import { IUser } from './interfaces';
import { User } from './User';

export const registerProductionDependencies = () => {
  container.register<IUser>('IUser', { useClass: User });
};
  • 创建di-registry.mock.ts(测试环境注册):
import { container } from 'tsyringe';
import { IUser } from './interfaces';
import { UserMock } from './UserMock';

export const registerTestDependencies = () => {
  container.clearInstances(); // 清空生产环境的实例残留
  container.register<IUser>('IUser', { useClass: UserMock });
};

2. 修改instrumentation.ts,根据环境加载注册逻辑

Next.js的instrumentation.ts会在应用启动时执行,这里要判断环境:

import { registerProductionDependencies } from './di-registry';

export async function register() {
  if (process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'development') {
    registerProductionDependencies();
  }
}

3. 在Playwright测试中手动注册Mock依赖

测试用例执行前,需要先调用测试环境的注册函数,确保容器里有Mock实现:

import { test, expect } from '@playwright/test';
import { registerTestDependencies } from '../src/di-registry.mock';

test.beforeAll(() => {
  // 测试启动前注册Mock依赖
  registerTestDependencies();
});

test('测试DI注入Mock类', async ({ page }) => {
  await page.goto('/di');
  // 断言页面上显示Mock类的内容,比如UserMock返回的固定值
  await expect(page.getByText('Mock User Data')).toBeVisible();
});

4. 确保页面组件正确获取依赖

页面di.tsx中要通过tsyringe的resolve方法获取实例,注意不要提前初始化:

import { container } from 'tsyringe';
import { IUser } from './interfaces';

export default function DIPage() {
  const user = container.resolve<IUser>('IUser');
  return <div>{user.getData()}</div>;
}

备选方案:改用@nestjs/core的DI(如果tsyringe适配困难)

如果tsyringe在Next.js测试环境的适配问题多,可以用NestJS的DI容器,步骤更清晰:

  1. 安装依赖:npm install @nestjs/core @nestjs/common
  2. 创建生产模块:
import { Module } from '@nestjs/common';
import { IUser } from './interfaces';
import { User } from './User';

@Module({
  providers: [{ provide: 'IUser', useClass: User }],
  exports: ['IUser'],
})
export class AppModule {}
  1. 测试时替换提供者:
import { Test } from '@nestjs/testing';
import { AppModule } from './app.module';
import { UserMock } from './UserMock';

test.beforeAll(async () => {
  const moduleRef = await Test.createTestingModule({
    imports: [AppModule],
  })
    .overrideProvider('IUser')
    .useClass(UserMock)
    .compile();
  
  // 可将模块实例全局挂载,或在页面组件中通过moduleRef.get('IUser')获取实例
});

关键注意事项

  • 测试时一定要清空容器实例,避免生产环境的实例残留
  • 确保process.env.NODE_ENV在测试时被正确设置为test
  • Next.js App Router中,instrumentation.ts仅在服务端执行,客户端组件的DI需要通过getServerSideProps或服务端组件传递实例给客户端

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 17:33:18