pg_duckdb扩展测试框架:pytest与PostgreSQL集成实践
测试框架架构概览
pg_duckdb项目采用pytest作为核心测试框架,通过会话级 fixtures 实现PostgreSQL数据库的生命周期管理。测试框架主要包含两大模块:
- 环境管理模块:自动创建隔离的测试数据库环境,确保测试用例之间无状态干扰
- 数据库交互模块:封装PostgreSQL连接与DuckDB查询接口,提供统一的测试操作层
核心实现文件包括:
- 测试配置:test/pycheck/conftest.py
- 工具函数:test/pycheck/utils.py
- 测试用例:test/pycheck/目录下的各类功能测试
环境初始化流程
测试框架通过pytest的fixture机制实现环境自动化准备,关键流程如下:
关键代码实现(来自test/pycheck/conftest.py):
@pytest.fixture(scope="session")
def shared_pg(tmp_path_factory):
"""Starts a new Postgres db that is shared for tests in this process"""
pg = Postgres(tmp_path_factory.getbasetemp() / "pgdata")
pg.initdb()
pg.start()
pg.sql("CREATE ROLE duckdb_group")
yield pg
pg.cleanup()
测试隔离机制
框架采用三层隔离策略确保测试独立性:
- 会话级隔离:所有测试共享一个PostgreSQL实例(通过
shared_pgfixture实现) - 测试级隔离:每个测试用例使用独立schema,测试后自动清理
- 数据级隔离:通过事务回滚和连接重置确保数据互不干扰
清理机制实现(来自test/pycheck/conftest.py):
@pytest.fixture
def pg(initialized_shared_pg, default_db_name):
shared_pg.reset() # 重置数据库状态
shared_pg.create_schema(default_db_name) # 创建测试专用schema
try:
yield shared_pg
finally:
shared_pg.cleanup_test_leftovers() # 清理测试残留数据
数据库交互接口
框架封装了两类核心交互接口:
1. PostgreSQL操作接口
通过Postgres类封装数据库管理功能,包括:
- 连接管理:自动处理端口分配与连接参数
- SQL执行:支持同步/异步查询执行
- 环境配置:自动设置pg_duckdb相关GUC参数
关键方法示例:
# 创建数据库
pg.createdb("test_db")
# 执行SQL查询
result = pg.sql("SELECT * FROM duckdb.query('SELECT 42')")
# 异步查询
async_result = await pg.asql("SELECT current_database()")
2. DuckDB集成接口
通过dsql方法实现DuckDB查询直接执行:
# 在PostgreSQL中执行DuckDB查询
result = pg.dsql("SELECT count(*) FROM 'test/data/iris.csv'")
测试用例编写规范
基础测试模板
def test_basic_query(pg):
# 准备测试数据
pg.sql("CREATE TABLE test_data (id INT, value TEXT)")
pg.sql("INSERT INTO test_data VALUES (1, 'pg_duckdb')")
# 执行DuckDB查询
result = pg.dsql("SELECT value FROM test_data WHERE id = 1")
# 验证结果
assert result == "pg_duckdb"
参数化测试示例
@pytest.mark.parametrize("input,expected", [
("'123'", 123),
("'45.6'", 45.6),
("'true'", True)
])
def test_type_conversion(pg, input, expected):
result = pg.dsql(f"SELECT CAST({input} AS ANY TYPE)")
assert result == expected
高级测试场景
1. 并发测试
框架支持多数据库实例并发测试:
@pytest.fixture
def pg_two_dbs(shared_pg):
for dbname in ["test_db_1", "test_db_2"]:
shared_pg.createdb(dbname)
init_pg(shared_pg, dbname=dbname)
yield shared_pg.cur(dbname="test_db_1"), shared_pg.cur(dbname="test_db_2")
2. 事务一致性测试
通过事务控制验证数据一致性:
def test_transaction_rollback(pg):
with pg.transaction() as cur:
cur.sql("INSERT INTO test_table VALUES (1)")
# 事务内查询可见
assert cur.sql("SELECT count(*) FROM test_table") == 1
# 回滚事务
cur.connection.rollback()
# 回滚后数据不可见
assert pg.sql("SELECT count(*) FROM test_table") == 0
3. MotherDuck集成测试
框架支持MotherDuck云服务集成测试:
@pytest.fixture
def md_cur(pg, default_db_name, ddb, md_test_user):
pg.sql(f"CALL duckdb.enable_motherduck('{md_test_user['token']}')")
with pg.cur() as cur:
cur.wait_until_schema_exists(f"ddb${default_db_name}")
yield cur
性能优化策略
测试框架采用多种优化手段提升执行效率:
- 连接池复用:会话级数据库连接复用,减少初始化开销
- 异步测试:支持异步查询执行,提升I/O密集型测试效率
- 日志级别控制:通过
silent_logs上下文管理器减少日志输出
@contextmanager
def silent_logs(self):
"""Set the log level to FATAL to reduce output noise"""
self.sql("SET log_min_messages TO FATAL")
try:
yield
finally:
self.sql("RESET log_min_messages")
测试覆盖率
框架覆盖的主要测试类型:
| 测试类别 | 示例文件 | 主要测试内容 |
|---|---|---|
| 基础功能 | basic.sql | 数据类型转换、基本查询 |
| 扩展功能 | extension_test.py | DuckDB扩展加载与使用 |
| 事务测试 | transactions.sql | 事务隔离级别验证 |
| 并发控制 | concurrency.sql | 多连接并发操作 |
| 权限测试 | non_superuser_test.py | 非超级用户权限控制 |
常见问题排查
1. 端口冲突问题
框架通过PortLock类自动分配端口,解决多实例冲突:
class PortLock:
def __init__(self):
global next_port
while True:
next_port += 1
# 检测端口可用性
with closing(socket.socket()) as s:
try:
s.bind(("127.0.0.1", next_port))
self.port = next_port
break
except Exception:
continue
2. 测试残留数据
通过cleanup_test_leftovers方法确保资源释放:
def cleanup_test_leftovers(self):
self.cleanup_subscriptions()
self.cleanup_publications()
self.cleanup_replication_slots()
self.cleanup_servers()
self.cleanup_schemas()
self.cleanup_users()
3. 性能测试报告
框架集成TPCH性能测试套件,可生成对比图表:
总结与扩展
pg_duckdb测试框架通过pytest与PostgreSQL的深度集成,实现了自动化、可扩展的测试体系。核心优势包括:
- 环境自动化:从数据库初始化到测试清理全程自动化
- 接口统一化:提供一致的SQL执行接口,屏蔽PostgreSQL与DuckDB差异
- 测试隔离化:多层次隔离机制确保测试用例独立可靠
后续扩展方向:
- 增加分布式测试支持
- 集成性能基准测试
- 实现测试结果可视化 dashboard
官方测试文档:test/regression/
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



