import { DataSource } from 'typeorm'; import { vi, beforeEach, afterEach, afterAll } from 'vitest'; /** * 集成测试数据库工具类 - 使用真实PostgreSQL数据库 */ export class IntegrationTestDatabase { private static dataSource: DataSource | null = null; /** * 初始化集成测试数据库 */ static async initialize(): Promise { if (this.dataSource?.isInitialized) { return this.dataSource; } // 使用环境变量中的测试数据库配置 const databaseUrl = process.env.TEST_DATABASE_URL || process.env.DATABASE_URL?.replace('d8dai', 'test_d8dai') || 'postgresql://postgres:test_password@localhost:5432/test_d8dai'; this.dataSource = new DataSource({ type: 'postgres', url: databaseUrl, synchronize: true, dropSchema: true, // 每次测试都重新创建schema logging: false, entities: [ // 导入实际实体 (await import('../modules/users/user.entity')).UserEntity, (await import('../modules/users/role.entity')).Role ] }); await this.dataSource.initialize(); return this.dataSource; } /** * 清理集成测试数据库 */ static async cleanup(): Promise { if (this.dataSource?.isInitialized) { await this.dataSource.destroy(); this.dataSource = null; } } /** * 获取当前数据源 */ static getDataSource(): DataSource | null { return this.dataSource; } /** * 清空所有表数据 */ static async clearAllData(): Promise { if (!this.dataSource?.isInitialized) { return; } const queryRunner = this.dataSource.createQueryRunner(); await queryRunner.connect(); try { // 获取所有实体 const entities = this.dataSource.entityMetadatas; // 按依赖关系排序(先删除子表,再删除父表) const sortedEntities = entities.sort((a, b) => { if (a.foreignKeys.some(fk => fk.referencedEntityMetadata.name === b.name)) { return 1; // a 依赖于 b,a 应该排在后面 } if (b.foreignKeys.some(fk => fk.referencedEntityMetadata.name === a.name)) { return -1; // b 依赖于 a,a 应该排在前面 } return 0; }); // 清空所有表数据 for (const entity of sortedEntities) { const repository = this.dataSource.getRepository(entity.name); await repository.clear(); } } finally { await queryRunner.release(); } } } /** * 集成测试数据库生命周期钩子 */ export function setupIntegrationDatabaseHooks() { beforeEach(async () => { await IntegrationTestDatabase.initialize(); }); afterEach(async () => { await IntegrationTestDatabase.clearAllData(); }); afterAll(async () => { await IntegrationTestDatabase.cleanup(); }); }