integration-test-db.ts 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. import { DataSource } from 'typeorm';
  2. import { vi, beforeEach, afterEach, afterAll } from 'vitest';
  3. /**
  4. * 集成测试数据库工具类 - 使用真实PostgreSQL数据库
  5. */
  6. export class IntegrationTestDatabase {
  7. private static dataSource: DataSource | null = null;
  8. /**
  9. * 初始化集成测试数据库
  10. */
  11. static async initialize(): Promise<DataSource> {
  12. if (this.dataSource?.isInitialized) {
  13. return this.dataSource;
  14. }
  15. // 使用环境变量中的测试数据库配置
  16. const databaseUrl = process.env.TEST_DATABASE_URL ||
  17. process.env.DATABASE_URL?.replace('d8dai', 'test_d8dai') ||
  18. 'postgresql://postgres:test_password@localhost:5432/test_d8dai';
  19. this.dataSource = new DataSource({
  20. type: 'postgres',
  21. url: databaseUrl,
  22. synchronize: true,
  23. dropSchema: true, // 每次测试都重新创建schema
  24. logging: false,
  25. entities: [
  26. // 导入实际实体
  27. (await import('../modules/users/user.entity')).UserEntity,
  28. (await import('../modules/users/role.entity')).Role
  29. ]
  30. });
  31. await this.dataSource.initialize();
  32. return this.dataSource;
  33. }
  34. /**
  35. * 清理集成测试数据库
  36. */
  37. static async cleanup(): Promise<void> {
  38. if (this.dataSource?.isInitialized) {
  39. await this.dataSource.destroy();
  40. this.dataSource = null;
  41. }
  42. }
  43. /**
  44. * 获取当前数据源
  45. */
  46. static getDataSource(): DataSource | null {
  47. return this.dataSource;
  48. }
  49. /**
  50. * 清空所有表数据
  51. */
  52. static async clearAllData(): Promise<void> {
  53. if (!this.dataSource?.isInitialized) {
  54. return;
  55. }
  56. const queryRunner = this.dataSource.createQueryRunner();
  57. await queryRunner.connect();
  58. try {
  59. // 获取所有实体
  60. const entities = this.dataSource.entityMetadatas;
  61. // 按依赖关系排序(先删除子表,再删除父表)
  62. const sortedEntities = entities.sort((a, b) => {
  63. if (a.foreignKeys.some(fk => fk.referencedEntityMetadata.name === b.name)) {
  64. return 1; // a 依赖于 b,a 应该排在后面
  65. }
  66. if (b.foreignKeys.some(fk => fk.referencedEntityMetadata.name === a.name)) {
  67. return -1; // b 依赖于 a,a 应该排在前面
  68. }
  69. return 0;
  70. });
  71. // 清空所有表数据
  72. for (const entity of sortedEntities) {
  73. const repository = this.dataSource.getRepository(entity.name);
  74. await repository.clear();
  75. }
  76. } finally {
  77. await queryRunner.release();
  78. }
  79. }
  80. }
  81. /**
  82. * 集成测试数据库生命周期钩子
  83. */
  84. export function setupIntegrationDatabaseHooks() {
  85. beforeEach(async () => {
  86. await IntegrationTestDatabase.initialize();
  87. });
  88. afterEach(async () => {
  89. await IntegrationTestDatabase.clearAllData();
  90. });
  91. afterAll(async () => {
  92. await IntegrationTestDatabase.cleanup();
  93. });
  94. }