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

非NestJS项目中Jest Mock TypeORM DataSource单元测试问题

解决TypeORM非NestJS项目中Mock DataSource事务单元测试问题

你遇到的核心问题是jest.mock的使用时机和目标错误,导致实际的DataSource实例被导入并尝试连接数据库,从而抛出Driver not Connected错误。下面是具体的修复方案:

问题根源

  1. jest.mock会被提升到模块代码的最顶部执行,你在beforeEach里调用的mock不会覆盖之前已经导入的datasource实例。
  2. 业务代码导入的是datasource.ts中已经实例化好的datasource对象,而非TypeORM的DataSource类,所以mocktypeorm模块的DataSource构造函数完全无效。

修复步骤

1. 调整Mock的位置与目标

直接在测试文件顶部mock你的自定义datasource模块,确保业务代码导入的是mock后的实例,而非真实数据库连接。

2. 确保Mock的异步方法返回Promise

事务相关的方法(startTransaction、rollbackTransaction等)都是异步操作,需要让它们返回resolved的Promise,避免测试中出现未处理的rejection。

3. 获取Mock实例用于验证

在测试中获取mock后的datasource实例,方便后续验证方法调用情况。

修改后的完整代码

mock.datasource.ts(优化异步方法)

import { DataSource } from 'typeorm';

export const dataSourceMockFactory: () => MockType<DataSource> = jest.fn(() => ({
  createQueryRunner: jest.fn().mockReturnValue({
    startTransaction: jest.fn().mockResolvedValue(undefined), // 明确返回resolved Promise
    rollbackTransaction: jest.fn().mockResolvedValue(undefined),
    release: jest.fn().mockResolvedValue(undefined),
    manager: {
      getRepository: jest.fn().mockReturnValue({
        create: jest.fn(),
        findOne: jest.fn().mockResolvedValue(getMyDummyObject()), // 异步方法返回Promise
      }),
      save: jest.fn().mockResolvedValue(undefined),
    },
  }),
}));

export type MockType<T> = {
  [P in keyof T]?: jest.Mock;
};

dummy.unit.test.ts(核心修改)

import { dummyService } from './dummy.service';
import { datasource } from './../../db/datasource';
import { dataSourceMockFactory } from './mock.datasource';

// 关键:把jest.mock放到模块顶部,mock自定义的datasource模块
jest.mock('./../../db/datasource', () => ({
  datasource: dataSourceMockFactory(),
}));

describe('dummy service test', () => {
  // 类型断言为Mocked,方便调用mock方法
  const mockDatasource = datasource as jest.Mocked<typeof datasource>;

  afterEach(() => {
    jest.clearAllMocks();
  });

  it('should execute transaction without error', async () => {
    await expect(dummyService()).resolves.not.toThrow();

    // 验证queryRunner相关方法的调用情况
    expect(mockDatasource.createQueryRunner).toHaveBeenCalled();
    const queryRunner = mockDatasource.createQueryRunner.mock.results[0].value;
    expect(queryRunner.startTransaction).toHaveBeenCalled();
    expect(queryRunner.release).toHaveBeenCalled();
  });

  it('should rollback transaction on error', async () => {
    // 模拟findOne抛出错误
    const queryRunner = mockDatasource.createQueryRunner.mock.results[0].value;
    queryRunner.manager.getRepository().findOne.mockRejectedValue(new Error('DB Error'));

    await expect(dummyService()).resolves.not.toThrow();

    // 验证回滚方法被调用
    expect(queryRunner.rollbackTransaction).toHaveBeenCalled();
    expect(queryRunner.release).toHaveBeenCalled();
  });
});

额外注意事项

  • 业务代码中的dummyService如果硬编码了someId,建议改成参数传入,方便测试时控制输入。
  • 确保getMyDummyObject()返回的数据结构与MyObject实体一致,避免类型或结构不匹配的问题。
  • 若需验证数据库操作的参数(比如findOne的查询条件),可以通过mock.calls获取调用参数进行断言。

内容的提问来源于stack exchange,提问作者Kit A.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 20:01:21