WSL环境下Alembic与Pytest连接本地PostgreSQL认证失败
解决pytest+Alembic连接PostgreSQL密码认证失败问题
问题现象
在WSL环境下使用pytest结合Alembic连接Docker部署的PostgreSQL时,出现以下密码认证失败错误,即使相同密码可通过pgAdmin正常连接:
sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) connection to server at "localhost" (127.0.0.1), port 5432 failed: FATAL: password authentication failed for user "testuser"
环境配置信息
Docker部署PostgreSQL命令
docker run -d --rm --name postgres-container -e POSTGRES_USER=testuser -e POSTGRES_PASSWORD=examplepass -p 5432:5432 postgres:latest
pytest.ini配置
[pytest] verbosity_assertions = 1 env = DB_PASS=examplepass DB_USER=testuser DB_HOST=localhost DB_NAME=testdb DB_PORT=5432
conftest.py初始化代码
@pytest.fixture(scope='module') def connection_string(): return f'postgresql://{os.getenv("DB_USER")}:{os.getenv("DB_PASS")}@{os.getenv("DB_HOST")}/{os.getenv("DB_NAME")}' @pytest.fixture(scope='module') def engine(connection_string): logging.info(connection_string) engine = create_engine(connection_string) logging.info(engine.url) return engine @pytest.fixture(scope='module') def tables(engine): alembic_cfg = AlembicConfig("alembic.ini") alembic_cfg.set_main_option('sqlalchemy.url', str(engine.url)) command.upgrade(alembic_cfg, "head") yield command.downgrade(alembic_cfg, "base") @pytest.fixture(scope='module') def session(engine, tables, context): """Returns an sqlalchemy session, and after the test tears down everything properly.""" connection = engine.connect() Session = sessionmaker(bind=connection) session = Session() # inserts example tables insert_into_tables(session, context) yield session
test_file.py测试代码
sys.path.append(".") from sqlalchemy import text def test_db_setup(session): # Try to execute a simple query to check if a table exists result_table_exists = session.execute(text("SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_name = 'task')"))
日志输出(确认连接URL正确)
INFO root:conftest.py:47 postgresql://testuser:examplepass@localhost/testdb INFO root:conftest.py:49 postgresql://testuser:***@localhost/testdb
排查与解决方案
1. 解决WSL与Docker的网络映射问题
WSL2的localhost默认不与Windows主机的localhost直接映射,如果你的Docker是在Windows上运行的,WSL内部访问localhost无法连接到Windows上的Docker容器:
- 方案1:改用Windows主机IP访问:在WSL终端执行
cat /etc/resolv.conf,找到nameserver后的IP(通常是192.168.x.x),修改pytest.ini中的DB_HOST为该IP。 - 方案2:开启Docker的WSL集成:打开Docker Desktop设置 → Resources → WSL Integration,勾选你使用的WSL发行版,重启Docker后即可用
localhost访问。 - 方案3:在WSL内部启动Docker容器:直接在WSL终端执行Docker启动命令,此时
localhost可正常指向WSL内部的容器。
2. 确认目标数据库存在
Docker启动Postgres时,默认会创建一个与POSTGRES_USER同名的数据库(即testuser),但你的配置中DB_NAME设为testdb,该数据库默认不存在:
- 方案1:修改pytest.ini中的
DB_NAME为testuser,使用默认创建的数据库。 - 方案2:启动Docker容器时添加
-e POSTGRES_DB=testdb参数,让容器自动创建testdb数据库:docker run -d --rm --name postgres-container -e POSTGRES_USER=testuser -e POSTGRES_PASSWORD=examplepass -e POSTGRES_DB=testdb -p 5432:5432 postgres:latest
3. 手动验证连接可用性
在WSL终端用psql手动测试连接,排除代码层面问题:
# 替换<HOST>为实际IP或localhost psql -h <HOST> -U testuser -d testdb
输入密码examplepass,如果能成功连接,说明数据库和网络没问题,需检查代码中是否有其他隐藏问题;如果连接失败,说明网络或数据库配置存在问题。
4. 优化session fixture的资源清理(可选)
虽然不影响认证,但为避免资源泄漏,建议在session fixture的yield后添加清理逻辑:
@pytest.fixture(scope='module') def session(engine, tables, context): """Returns an sqlalchemy session, and after the test tears down everything properly.""" connection = engine.connect() Session = sessionmaker(bind=connection) session = Session() # inserts example tables insert_into_tables(session, context) yield session # 添加清理逻辑 session.rollback() session.close() connection.close()
内容的提问来源于stack exchange,提问作者Zu Jiry
相关产品推荐
相关产品推荐

