首页 > 解决方案 > Nestjs / Typeorm 在每次测试后使用事务回滚数据库状态

问题描述

我正在尝试使用带有事务的 Nestjs/Typeorm 在每次 e2e 测试之前/之后启动和回滚数据库状态。

我在下面包含了一个代码片段尝试。我正在尝试覆盖 EntityManager 提供程序,以便使用 QueryRunner 实例对其进行初始化,以便我可以在每次测试之前/之后启动和回滚事务。但是,我似乎无法让存储库(请参阅下面代码片段中的 beforeEach 方法中的注释)来使用我重写的 EntityManager 实例,以启用成功的事务使用.....我认为这就是为什么事务在每个之后都没有回滚测试完成了??

  let app: INestApplication;
  let testModule: TestingModule;

  afterEach(async () => {
    const em: EntityManager = testModule.get(getEntityManagerToken('default'));
    await em.queryRunner.rollbackTransaction();
  });

  beforeEach(async () => {
    const con: Connection = testModule.get(Connection);
    const em: EntityManager = testModule.get(getEntityManagerToken('default'));
    const repo: CourseRepository = testModule.get(CourseRepository);
    const result: boolean = repo.isEntityManagerMine(em); // false => the repo is not using the default entity manager
    const conResult: boolean = repo.isConnectionMine(em.connection); // true => the repo is using the same connection
    await em.queryRunner.startTransaction();
  });

  afterAll(async() => {
    await app.close();
    await testModule.close();
  });

  beforeAll(async () => {
    testModule = await Test.createTestingModule({
      imports: [AppModule],})
    .overrideProvider(getEntityManagerToken('default'))
    .useFactory({
      factory: (connection: Connection): EntityManager => {
        const queryRunner: QueryRunner = connection.createQueryRunner('master');
        const entityManager: EntityManager = connection.createEntityManager(queryRunner);
        return entityManager;
      },
      inject:[getConnectionToken('default')],
    })
    .compile();

    app = testModule.createNestApplication();
    await app.init();
  });

 // tests using request from supertest library

标签: nestjstypeform

解决方案


我遇到了类似的问题:我正在使用Nestjs + TypeORM + Jest设置。我正在使用DataMapper 模式

我想,当我们编写集成测试时,我们实际上是在数据库中插入记录。我也不想使用新的数据库,我必须在其中创建模式并为所有数据播种 - 当我的项目变得更大时,这可能会导致时间增加。使用单独的数据库进行测试的另一个威胁是,确保应用更改的顺序。一个错误的步骤可能会占用我修复种子数据的无数小时。

在运行集成测试时在 DB 中插入数据的问题是 - 对于由 repository.insert() 或 repository.save() 完成的每个插入 - typeorm 创建一个新事务并提交它。如果我[在 beforeAll() 中启动一个 txn - 运行测试 - 在 afterAll() 中回滚 txn ] ,这会产生一个问题,因为已经在存储库级别完成了提交。这使得上述流程毫无用处。

以下是我遵循的解决方案。

  • 使用与开发环境相同的数据库进行集成测试
  • 编写集成测试
  • 在 afterAll() 块中编写删除语句

以下是代码块:

afterAll(async () => {
await queryRunner.startTransaction();
await queryRunner.query(`delete from \"Accounts\" 
    where \"walletWalletId\" in 
        (select \"wallet_id\" from \"Wallet\" 
            where \"userUuid\" = \'`+VALID_UUID+'\')');

await queryRunner.query(`delete from \"Wallet\"
    where \"userUuid\" = \'`+ VALID_UUID+'\'');

await queryRunner.query(`delete from \"Users\" 
    where \"uuid\" = \'`+VALID_UUID+'\'');
await queryRunner.commitTransaction();
});

推荐阅读