GitHub Actions CI/CD中FastAPI应用测试阶段数据库连接错误
FastAPI GitHub Actions 测试阶段数据库连接错误修复方案
问题分析
从错误日志和Workflow配置来看,核心问题有两点:
- GitHub Actions中启动的Postgres容器仅初始化了
DATABASE_NAME数据库,但测试代码尝试连接的是DATABASE_NAME_TEST,导致目标库不存在。 - 测试环境的
DATABASE_HOSTNAME可能配置为远程生产数据库地址,而非本地启动的Postgres服务地址。
具体修复步骤
1. 调整Postgres服务配置,创建测试数据库
修改Workflow中services.postgres的配置,确保容器启动时自动创建测试数据库:
services: postgres: image: postgres env: POSTGRES_PASSWORD: ${{secrets.DATABASE_PASSWORD}} POSTGRES_USER: ${{secrets.DATABASE_USERNAME}} # 匹配你的数据库用户名,避免默认postgres POSTGRES_DB: ${{secrets.DATABASE_NAME}} # 初始化主库 ports: - 5432:5432 options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 # 挂载初始化脚本,自动创建测试库 volumes: - ./init-test-db.sh:/docker-entrypoint-initdb.d/init-test-db.sh
在项目根目录创建init-test-db.sh脚本(执行chmod +x init-test-db.sh赋予权限):
#!/bin/bash set -e # 使用环境变量创建测试数据库 psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL CREATE DATABASE ${{secrets.DATABASE_NAME_TEST}}; EOSQL
2. 修正测试环境的数据库主机地址
测试时需连接GitHub Actions本地的Postgres容器,而非远程数据库,因此在Workflow的env部分覆盖DATABASE_HOSTNAME:
env: DATABASE_HOSTNAME: localhost # 或直接用服务名"postgres" DATABASE_PORT: ${{secrets.DATABASE_PORT}} DATABASE_PASSWORD: ${{secrets.DATABASE_PASSWORD}} DATABASE_NAME: ${{secrets.DATABASE_NAME}} DATABASE_NAME_TEST: ${{secrets.DATABASE_NAME_TEST}} DATABASE_USERNAME: ${{secrets.DATABASE_USERNAME}} SECRET_KEY: ${{secrets.SECRET_KEY}} ALGORITHM: ${{secrets.ALGORITHM}} ACCESS_TOKEN_EXPIRE_MINUTES: ${{secrets.ACCESS_TOKEN_EXPIRE_MINUTES}}
3. 可选:无需脚本,直接在测试前创建数据库
如果不想使用初始化脚本,可在pytest步骤前添加手动创建测试库的命令:
- name: Create test database run: | PGPASSWORD=${{secrets.DATABASE_PASSWORD}} createdb -h localhost -U ${{secrets.DATABASE_USERNAME}} ${{secrets.DATABASE_NAME_TEST}} - name: test with pytest run: | pip install pytest pip install httpx pytest
4. 验证测试代码的数据库配置
确保测试代码正确读取DATABASE_NAME_TEST环境变量,示例配置:
import os from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker # 测试环境使用测试数据库 SQLALCHEMY_DATABASE_URL = ( f"postgresql://{os.getenv('DATABASE_USERNAME')}:" f"{os.getenv('DATABASE_PASSWORD')}@" f"{os.getenv('DATABASE_HOSTNAME')}:" f"{os.getenv('DATABASE_PORT')}/" f"{os.getenv('DATABASE_NAME_TEST')}" ) engine = create_engine(SQLALCHEMY_DATABASE_URL) TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
内容的提问来源于stack exchange,提问作者Faiz Olam
相关产品推荐
相关产品推荐

