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

无需Mock:NestJS如何切换MySQL/SQLite测试Controller与Service

解决Prisma在测试环境切换为SQLite的方案

核心问题根源

你碰到的问题本质是:Prisma Client是根据schema.prisma里配置的provider生成的,仅在代码里修改数据源URL不会替换底层依赖的数据库驱动,所以就算指定了SQLite文件路径,程序还是会沿用MySQL的连接逻辑。

可行解决方案

1. 环境变量动态切换schema配置(最简便)

不需要额外编写测试专用PrismaService,通过环境变量让schema自动适配不同环境:

  • 修改schema.prisma,用环境变量定义provider和URL:
datasource db {
  provider = env("DATABASE_PROVIDER")
  url      = env("DATABASE_URL")
}
  • 根目录创建多环境配置文件:
    • .env(开发/生产):
      DATABASE_PROVIDER=mysql
      DATABASE_URL="mysql://user:password@localhost:3306/db_name"
      
    • .env.test(测试):
      DATABASE_PROVIDER=sqlite
      DATABASE_URL="file:./test.db"
      
  • 简化基础PrismaService,让它自动读取环境变量:
@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
  constructor() {
    super(); // Prisma会自动读取对应环境的.env配置
  }

  async onModuleInit() {
    await this.$connect();
  }
}
  • 配置测试框架加载测试环境变量(以Jest为例),修改jest.config.js:
module.exports = {
  // 其他配置...
  setupFiles: ['dotenv/config'],
  globals: {
    'dotenv/config': { path: '.env.test' }
  }
};

2. 为测试环境单独生成Prisma Client

如果不想动态修改主schema,可以为测试单独维护一套配置:

  • 复制schema.prisma为schema.test.prisma,修改数据源为SQLite:
datasource db {
  provider = "sqlite"
  url      = "file:./test.db"
}
  • 在package.json添加测试Client生成脚本:
{
  "scripts": {
    "prisma:generate:test": "prisma generate --schema=./prisma/schema.test.prisma"
  }
}
  • 测试前执行npm run prisma:generate:test生成适配SQLite的Client,再编写测试用PrismaService:
import { PrismaClient as PrismaTestClient } from '../prisma/generated/test/client';

@Injectable()
export class PrismaServiceTest extends PrismaTestClient implements OnModuleInit {
  constructor() {
    super();
  }

  async onModuleInit() {
    await this.$connect();
  }
}

3. 修正测试代码的模块替换逻辑

不管用哪种方案,测试里的依赖替换要确保正确:

describe('UserController', () => {
  let service: UserService;
  let controller: UserController;
  let prisma: PrismaServiceTest;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      imports: [GlobalModule],
      controllers: [UserController],
      providers: [UserService], // 移除PrismaService避免冲突
    })
      .overrideProvider(PrismaService)
      .useClass(PrismaServiceTest) // 用useClass让Nest自动处理注入
      .compile();

    service = module.get<UserService>(UserService);
    controller = module.get<UserController>(UserController);
    prisma = module.get<PrismaServiceTest>(PrismaService); // 按原服务token获取实例
  });

  it('signup user', async () => {
    const user = await controller.createUser(signupUser);
    expect(user.email).toEqual(signupUser.email);
  });
});

关于Mock的补充

完全认同你说的无意义Mock问题——如果所有数据库操作都Mock,测试的只是代码调用逻辑,而非真实的数据交互流程。用SQLite做测试数据库能覆盖数据校验、关联查询、事务逻辑等真实场景,这才是有价值的集成测试。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 01:15:20