使用 NestJS 和 TypeORM 进行事务

问题描述 投票:0回答:1

我想编写这样一个单元测试文件,每次运行它时,我都会运行整个应用程序的一个实例。这部分确保了这一点:

module = await Test.createTestingModule({
  imports: [AppModule],
}).compile();

然后我想在每次单元测试后清理数据库。 ChatGPT 让我得出的结论是我应该使用交易。它建议我应该使用:

beforeEach(async () => {
  await dataSource.query('BEGIN');
});

afterEach(async () => {
  await dataSource.query('ROLLBACK');
});

但它不想为我工作。

然后跟聊了一番之后,我得出的结论是我应该使用

queryRunner.startTransaction()
queryRunner.rollbackTransaction()
。但它仍然不想为我工作。

请帮我修复以下代码。

import { Test, TestingModule } from '@nestjs/testing';
import { UsersService } from './users.service';
import { AppModule } from '../../app.module';
import { DataSource, QueryRunner } from 'typeorm';
import { DATA_SOURCE } from '../database/database.providers';
import { runSeeders } from 'typeorm-extension';
import { ConfigService } from '@nestjs/config';

describe('UsersService', () => {
  let service: UsersService;
  let module: TestingModule;
  let dataSource: DataSource;
  let queryRunner: QueryRunner;
  let config: ConfigService;
  let createQueryRunner;
  let release;

  beforeAll(async () => {
    module = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();

    config = module.get<ConfigService>(ConfigService);
    dataSource = module.get<DataSource>(DATA_SOURCE);

    if (config.get<string>('NODE_ENV') === 'testing') {
      console.info('Running seeders for testing environment');
      await runSeeders(dataSource);
    }

    service = module.get<UsersService>(UsersService);
  });

  beforeEach(async () => {
    queryRunner = dataSource.createQueryRunner();
    await queryRunner.startTransaction();
  });

  afterEach(async () => {
    await queryRunner.rollbackTransaction();

    await queryRunner.release();
  });

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

  it('should be defined', async () => {
    await service.create({ firstName: 'FN', lastName: 'LN', email: '[email protected]' });
    await service.create({ firstName: 'FN2', lastName: 'LN2', email: '[email protected]' });

    expect(service).toBeDefined();
  });

  it('should return a user', async () => {
    const user = await service.findOneByEmail('[email protected]');
    expect(user).toBeDefined();
  });
});
typescript unit-testing nestjs nestjs-typeorm
1个回答
0
投票

通过一些尝试和错误,我找到了这个解决方案。我使用

<<==
注释来突出显示添加到上一个示例中的行。

import { Test, TestingModule } from '@nestjs/testing';
import { UsersService } from './users.service';
import { AppModule } from '../../app.module';
import { DataSource, QueryRunner } from 'typeorm';
import { DATA_SOURCE } from '../database/database.providers';
import { runSeeders } from 'typeorm-extension';
import { ConfigService } from '@nestjs/config';

describe('UsersService', () => {
  let service: UsersService;
  let module: TestingModule;
  let dataSource: DataSource;
  let queryRunner: QueryRunner;
  let config: ConfigService;
  let createQueryRunner;
  let release;

  beforeAll(async () => {
    module = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();

    config = module.get<ConfigService>(ConfigService);
    dataSource = module.get<DataSource>(DATA_SOURCE);

    if (config.get<string>('NODE_ENV') === 'testing') {
      console.info('Running seeders for testing environment');
      await runSeeders(dataSource);
    }

    service = module.get<UsersService>(UsersService);
  });

  beforeEach(async () => {
    queryRunner = dataSource.createQueryRunner();
    await queryRunner.startTransaction();

    createQueryRunner = dataSource.createQueryRunner; // <<==
    release = queryRunner.release;                    // <<==

    dataSource.createQueryRunner = () => queryRunner; // <<==
    queryRunner.release = () => Promise.resolve();    // <<==
  });

  afterEach(async () => {
    await queryRunner.rollbackTransaction();

    dataSource.createQueryRunner = createQueryRunner; // <<==
    queryRunner.release = release;                    // <<==

    await queryRunner.release();
  });

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

  it('should be defined', async () => {
    await service.create({ firstName: 'FN', lastName: 'LN', email: '[email protected]' });
    await service.create({ firstName: 'FN2', lastName: 'LN2', email: '[email protected]' });

    expect(service).toBeDefined();
  });

  it('should return a user', async () => {
    const user = await service.findOneByEmail('[email protected]');
    expect(user).toBeDefined();
  });
});

说明:

我想几乎每次对数据库进行查询时,我们都会使用

dataSource.createQueryRunner().query(<SOME SQL QUERY>)
,它会创建一个新的 queryRunner。但是为了让事务在我们的测试文件中为我们工作,我们必须在每次进行查询时使用相同的
queryRunner
。上面显示了我如何弄清楚如何强制执行此行为。如果有人有更好的解决方案,欢迎分享。我希望 TypeORM 中的这个问题能够尽快得到解决,或者会引入一些更好的解决方法。

© www.soinside.com 2019 - 2024. All rights reserved.