pg_duckdb扩展测试框架:pytest与PostgreSQL集成实践

pg_duckdb扩展测试框架:pytest与PostgreSQL集成实践

【免费下载链接】pg_duckdb DuckDB-powered Postgres for high performance apps & analytics. 【免费下载链接】pg_duckdb 项目地址: https://gitcode.com/GitHub_Trending/pg/pg_duckdb

测试框架架构概览

pg_duckdb项目采用pytest作为核心测试框架,通过会话级 fixtures 实现PostgreSQL数据库的生命周期管理。测试框架主要包含两大模块:

  • 环境管理模块:自动创建隔离的测试数据库环境,确保测试用例之间无状态干扰
  • 数据库交互模块:封装PostgreSQL连接与DuckDB查询接口,提供统一的测试操作层

核心实现文件包括:

环境初始化流程

测试框架通过pytest的fixture机制实现环境自动化准备,关键流程如下:

mermaid

关键代码实现(来自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()

测试隔离机制

框架采用三层隔离策略确保测试独立性:

  1. 会话级隔离:所有测试共享一个PostgreSQL实例(通过shared_pg fixture实现)
  2. 测试级隔离:每个测试用例使用独立schema,测试后自动清理
  3. 数据级隔离:通过事务回滚和连接重置确保数据互不干扰

清理机制实现(来自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

性能优化策略

测试框架采用多种优化手段提升执行效率:

  1. 连接池复用:会话级数据库连接复用,减少初始化开销
  2. 异步测试:支持异步查询执行,提升I/O密集型测试效率
  3. 日志级别控制:通过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.pyDuckDB扩展加载与使用
事务测试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的深度集成,实现了自动化、可扩展的测试体系。核心优势包括:

  1. 环境自动化:从数据库初始化到测试清理全程自动化
  2. 接口统一化:提供一致的SQL执行接口,屏蔽PostgreSQL与DuckDB差异
  3. 测试隔离化:多层次隔离机制确保测试用例独立可靠

后续扩展方向:

  • 增加分布式测试支持
  • 集成性能基准测试
  • 实现测试结果可视化 dashboard

官方测试文档:test/regression/

【免费下载链接】pg_duckdb DuckDB-powered Postgres for high performance apps & analytics. 【免费下载链接】pg_duckdb 项目地址: https://gitcode.com/GitHub_Trending/pg/pg_duckdb

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值