⚠️ Alpha内测版本警告:此为早期内部构建版本,尚不完整且可能存在错误,欢迎大家提Issue反馈问题或建议
Skip to content

9.2.3 测试前初始化数据库——数据库迁移:测试数据库的初始化

测试数据库的表结构必须与开发/生产保持一致,迁移是保证这一点的关键。

测试数据库初始化流程

使用 Prisma 管理测试数据库迁移

方法一:migrate deploy(推荐用于 CI)

bash
# 部署已有的迁移到测试数据库
dotenv -e .env.test -- npx prisma migrate deploy
json
// package.json
{
  "scripts": {
    "test:setup": "dotenv -e .env.test -- prisma migrate deploy",
    "test": "npm run test:setup && dotenv -e .env.test -- jest",
    "test:ci": "npm run test:setup && dotenv -e .env.test -- jest --ci"
  }
}

方法二:migrate reset(开发时使用)

bash
# 重置数据库并重新运行所有迁移
dotenv -e .env.test -- npx prisma migrate reset --force
json
// package.json
{
  "scripts": {
    "test:reset": "dotenv -e .env.test -- prisma migrate reset --force",
    "test:fresh": "npm run test:reset && dotenv -e .env.test -- jest"
  }
}

方法三:db push(快速原型)

bash
# 直接推送 schema 变更(不生成迁移文件)
dotenv -e .env.test -- npx prisma db push

自动化测试数据库初始化

typescript
// test/setup-db.ts
import { execSync } from 'child_process';
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

export async function setupTestDatabase() {
  console.log('🔧 Setting up test database...');
  
  try {
    // 运行迁移
    execSync('npx prisma migrate deploy', {
      env: { ...process.env, DATABASE_URL: process.env.DATABASE_URL },
      stdio: 'inherit',
    });
    
    // 验证连接
    await prisma.$connect();
    console.log('✅ Test database ready');
  } catch (error) {
    console.error('❌ Failed to setup test database:', error);
    throw error;
  }
}

export async function teardownTestDatabase() {
  await prisma.$disconnect();
}
typescript
// jest.setup.ts
import { setupTestDatabase, teardownTestDatabase } from './test/setup-db';

beforeAll(async () => {
  await setupTestDatabase();
});

afterAll(async () => {
  await teardownTestDatabase();
});

Jest 全局配置

typescript
// jest.config.ts
import type { Config } from 'jest';

const config: Config = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
  globalSetup: '<rootDir>/test/global-setup.ts',
  globalTeardown: '<rootDir>/test/global-teardown.ts',
  testTimeout: 30000, // 迁移可能需要较长时间
};

export default config;
typescript
// test/global-setup.ts
import { execSync } from 'child_process';

export default async function globalSetup() {
  console.log('\n🚀 Global test setup...');
  
  // 确保测试数据库结构是最新的
  execSync('dotenv -e .env.test -- npx prisma migrate deploy', {
    stdio: 'inherit',
  });
  
  // 生成 Prisma Client
  execSync('npx prisma generate', { stdio: 'inherit' });
}
typescript
// test/global-teardown.ts
export default async function globalTeardown() {
  console.log('\n🧹 Global test teardown...');
  // 可选:清理测试数据库
}

处理迁移冲突

场景:本地迁移与远程不一致

bash
# 查看迁移状态
dotenv -e .env.test -- npx prisma migrate status

# 如果有问题,重置测试数据库
dotenv -e .env.test -- npx prisma migrate reset --force

场景:CI 中迁移失败

yaml
# .github/workflows/test.yml
jobs:
  test:
    steps:
      - name: Setup Database
        run: |
          # 等待数据库就绪
          sleep 5
          # 运行迁移
          npx prisma migrate deploy
        env:
          DATABASE_URL: ${{ env.DATABASE_URL }}

使用 Docker 实现一次性数据库

typescript
// test/docker-db.ts
import { execSync } from 'child_process';
import { v4 as uuid } from 'uuid';

export function createTestDatabase() {
  const dbName = `test_${uuid().replace(/-/g, '_')}`;
  
  execSync(`docker run -d --name ${dbName} \
    -e POSTGRES_DB=${dbName} \
    -e POSTGRES_USER=test \
    -e POSTGRES_PASSWORD=test \
    -p 0:5432 \
    postgres:15-alpine`);
  
  // 获取映射的端口
  const port = execSync(`docker port ${dbName} 5432`).toString().split(':')[1].trim();
  
  return {
    url: `postgresql://test:test@localhost:${port}/${dbName}`,
    cleanup: () => execSync(`docker rm -f ${dbName}`),
  };
}

迁移策略对比

策略适用场景优点缺点
migrate deployCI/CD快速、可靠需要已有迁移
migrate reset开发测试完全重置较慢
db push快速原型最快可能丢失数据
Docker 一次性并行测试完全隔离启动较慢

常见问题

问题原因解决方案
迁移超时数据库连接慢增加超时时间
表不存在迁移未运行检查 migrate deploy
类型不匹配Client 未更新运行 prisma generate
并行冲突共享数据库使用事务或 Docker

本节小结

测试数据库迁移的核心目标是确保测试环境的表结构与生产一致。推荐在 CI 中使用 migrate deploy,在本地开发时使用 migrate reset。通过 Jest 的全局配置,可以在测试运行前自动完成迁移,让测试专注于业务逻辑验证。