我有与 postgres 数据库对话的 sqlalchemy 应用程序。我想使用测试容器进行一些“集成测试”并尝试各种场景。
只是为了让事情变得简单,假设在我的应用程序中我只期望一个表
users
至少包含
admin
行。
我希望这在所有 测试中可用。这就像我的数据库状态的“基线”。 然后我想做多个测试,例如检查我是否可以登录到应用程序,无论是管理员还是普通用户
我想创建不同的“场景” - 每个测试可能有一个,数据库上有不同的数据。
例如,我想做 3 个测试
,其中只有
-
行
admin
,其中有 2 行:| ||和 -
其中有 4 行:
admin
、user_foo
-
、
admin
、user_x
对于每个测试,我想要/需要编写 3 个不同的装置。我可以使用“原始sql”或sqlalchemy本身,现在并不重要。user_y
但是在运行测试之后(它本身也可能改变数据库的内容)我需要“回滚”到原始的“基线”状态。user_z
但是我不能只是运行
,因为所有更改实际上都已提交。
如何确保数据库在每次测试之前处于“基线”状态(+适当的固定装置)?|| |我发现的唯一解决方案是
ROLLBACK
在每次测试之前删除数据库并从头开始重建
手动编写适当的sql来恢复数据库状态
忽略该问题并希望它有效...| ||第一个运行缓慢,第二个难以维护,第三个......不是解决方案。
- 理想情况下,我希望有一种方法告诉 pg “标记”数据库的状态并恢复我运行测试后。 是否可以?
- manually write the appropriate sql to restore the db status
- ignore the issue and hope it works...
The first one is slow to run, the second is unmantainable and the third... is not a solution.
Ideally I would like to have a way to tell pg to "tag" the status of the db and restore it after I've run the test. Is it possible?
可以使用测试函数作为 pytest fixture 的一部分来实现此目的。 此方法依赖于事务在测试完成后回滚这一事实,从而有效地撤消了对数据库所做的任何更改。 下面是操作方法:
import pytest
from sqlalchemy import create_engine, text
from sqlalchemy.orm import sessionmaker
# 配置测试数据库连接
DATABASE_URL = "postgresql://user:password@host:port/database"
@pytest.fixture(scope="session")
def engine():
"""创建一个 SQLAlchemy 引擎。"""
engine = create_engine(DATABASE_URL)
yield engine
engine.dispose()
@pytest.fixture(scope="session")
def session_factory(engine):
"""创建一个 SQLAlchemy 会话工厂。"""
return sessionmaker(autocommit=False, autoflush=False, bind=engine)
@pytest.fixture(scope="function")
def session(session_factory):
"""为每个测试函数创建一个 SQLAlchemy 会话,并在完成后回滚事务。"""
session = session_factory()
yield session
session.rollback()
session.close()
@pytest.fixture(scope="function")
def baseline_data(session):
"""将数据库填充到其基线状态。"""
session.execute(text("INSERT INTO users (username) VALUES ('admin')"))
session.commit()
# 测试示例
def test_admin_login(session, baseline_data): # 注意 baseline_data 依赖项
"""测试管理员登录。"""
# 执行登录操作并进行断言...
def test_user_creation(session, baseline_data):
"""测试用户创建。"""
# 执行用户创建操作并进行断言...
# 对数据库所做的更改将在测试后回滚
说明:
-
Fixtures: pytest fixtures (
@pytest.fixture
) 用于设置测试环境。 它们有助于避免代码重复,并提供了一种在测试中共享资源的干净方法。 -
数据库连接:
engine
fixture 建立与 PostgreSQL 数据库的连接。session_factory
fixture 创建一个可以生成数据库会话的工厂。 -
会话管理:
session
fixture 对于每个测试函数都至关重要。 它创建了一个新的数据库会话,并且至关重要的是, 在测试完成后回滚 事务。 此回滚可确保每个测试都从一个干净的状态开始,因为在测试期间所做的任何更改都会被撤消。 -
基线数据:
baseline_data
fixture 负责将数据库设置为其基线状态。 在这种情况下,它会插入一个admin
用户。 通过将其作为依赖项包含在测试函数中,可以在每次测试之前应用此基线状态。 -
测试函数:
-
test_admin_login
和test_user_creation
是测试函数示例。 -
它们都依赖于
session
和baseline_data
fixtures。 这种依赖关系确保:- 每个测试都获得一个新的数据库会话。
- 基线数据在每个测试之前都已加载。
- 在这些测试函数中所做的任何数据库更改都将在测试完成后安全地回滚。
如何运行测试:
使用 pytest 运行的测试,它将自动处理 fixtures 的设置和拆除:
pytest
通过此设置,不必在每次测试后手动清理数据库。 回滚机制可确保测试彼此隔离,并且始终从一致的基线状态开始。
标签:python,postgresql,sqlalchemy,pytest From: 78782122