Rust PostgreSQL扩展开发框架pgrx-tests的使用,pgrx-tests助力高效PostgreSQL插件测试与验证
Rust PostgreSQL扩展开发框架pgrx-tests的使用,pgrx-tests助力高效PostgreSQL插件测试与验证
pgrx-tests是用于pgrx的测试框架,建议作为[dev-dependencies]
与pgrx一起使用。
安装
全局安装二进制工具
cargo install pgrx-tests
运行上述命令将全局安装pgrx_embed_pgrx-tests
二进制工具。
作为库安装
在项目目录中运行以下Cargo命令:
cargo add pgrx-tests
或者在Cargo.toml中添加以下行:
pgrx-tests = "0.16.0"
完整示例demo
下面是一个使用pgrx-tests进行PostgreSQL扩展测试的完整示例:
// 在Cargo.toml中添加依赖
// [dev-dependencies]
// pgrx-tests = "0.16.0"
use pgrx::prelude::*;
use pgrx_tests::testing::*;
// 定义要测试的PostgreSQL扩展函数
#[pg_extern]
fn add_one(i: i32) -> i32 {
i + 1
}
// 定义测试模块
#[cfg(test)]
mod tests {
use super::*;
use pgrx_tests::pg_test;
// 定义测试函数
#[pg_test]
fn test_add_one() {
// 测试add_one函数
let result = Spi::get_one::<i32>("SELECT add_one(1);");
assert_eq!(result, Ok(Some(2)));
}
// 另一个测试示例
#[pg_test]
fn test_add_one_with_negative() {
let result = Spi::get_one::<i32>("SELECT add_one(-5);");
assert_eq!(result, Ok(Some(-4)));
}
}
测试执行
要运行这些测试,可以使用以下命令:
cargo pgrx test
完整示例代码
基于上述示例,这里提供一个更完整的PostgreSQL扩展测试示例:
// 在Cargo.toml中添加依赖
// [dev-dependencies]
// pgrx-tests = "0.16.0"
use pgrx::prelude::*;
use pgrx_tests::testing::*;
// 定义一个简单的数学函数库扩展
// 加法函数
#[pg_extern]
fn add(a: i32, b: i32) -> i32 {
a + b
}
// 减法函数
#[pg_extern]
fn subtract(a: i32, b: i32) -> i32 {
a - b
}
// 阶乘函数
#[pg_extern]
fn factorial(n: i32) -> i64 {
if n <= 1 {
1
} else {
(1..=n as i64).product()
}
}
// 测试模块
#[cfg(test)]
mod tests {
use super::*;
use pgrx_tests::pg_test;
// 测试加法函数
#[pg_test]
fn test_add() {
let result = Spi::get_one::<i32>("SELECT add(10, 20);");
assert_eq!(result, Ok(Some(30)));
}
// 测试减法函数
#[pg_test]
fn test_subtract() {
let result = Spi::get_one::<i32>("SELECT subtract(50, 20);");
assert_eq!(result, Ok(Some(30)));
}
// 测试阶乘函数
#[pg_test]
fn test_factorial() {
let result = Spi::get_one::<i64>("SELECT factorial(5);");
assert_eq!(result, Ok(Some(120)));
}
// 测试边界条件
#[pg_test]
fn test_factorial_boundary() {
let result = Spi::get_one::<i64>("SELECT factorial(0);");
assert_eq!(result, Ok(Some(1)));
}
// 测试多个函数的组合使用
#[pg_test]
fn test_combined_operations() {
let result = Spi::get_one::<i32>(
"SELECT add(subtract(100, 50), subtract(50, 10));"
);
assert_eq!(result, Ok(Some(90)));
}
}
1 回复
Rust PostgreSQL扩展开发框架pgrx-tests的使用指南
概述
pgrx-tests是pgrx框架的一部分,专门用于简化PostgreSQL扩展的测试流程。它为Rust开发者提供了一个高效的方式来编写和运行PostgreSQL扩展的单元测试和集成测试。
主要特性
- 简化PostgreSQL扩展测试设置
- 自动管理测试数据库生命周期
- 支持并行测试执行
- 提供方便的断言宏
- 与标准Rust测试工具集成
安装与设置
首先确保已安装pgrx工具链:
cargo install --locked cargo-pgrx
cargo pgrx init
然后在你的pgrx项目中添加依赖:
[dependencies]
pgrx = "0.9"
基本使用方法
1. 创建测试模块
在你的扩展项目中创建一个测试模块:
#[cfg(test)]
mod tests {
use pgrx::prelude::*;
use pgrx_tests::pg_test;
#[pg_test]
fn test_my_extension_function() {
// 测试代码
}
}
2. 编写测试用例
#[pg_test]
fn test_add_numbers() {
Spi::connect(|client| {
let result = client.select("SELECT my_add_function(1, 2);", None, None)
.first()
.get_one::<i32>();
assert_eq!(result, Ok(3));
});
}
3. 运行测试
使用cargo pgrx运行测试:
cargo pgrx test
高级功能
1. 测试初始化
#[pg_test(initialization = "init_test_data")]
fn test_with_data() {
// 测试代码
}
fn init_test_data() {
Spi::connect(|client| {
client.update("INSERT INTO test_table VALUES (1, 'test');", None, None);
});
}
2. 并行测试
#[pg_test(parallel)]
fn test_parallel_1() {
// 测试代码
}
#[pg_test(parallel)]
fn test_parallel_2() {
// 测试代码
}
3. 事务处理
#[pg_test(transaction)]
fn test_in_transaction() {
// 测试代码将在事务中运行
}
实际示例
以下是一个完整的测试示例,测试一个自定义聚合函数:
#[pg_test]
fn test_custom_aggregate() {
Spi::connect(|client| {
// 创建测试表
client.update("CREATE TABLE test_agg (value integer);", None, None);
// 插入测试数据
for i in 1..=5 {
client.update(&format!("INSERT INTO test_agg VALUES ({});", i), None, None);
}
// 测试自定义聚合
let result = client.select("SELECT my_custom_agg(value) FROM test_agg;", None, None)
.first()
.get_one::<i32>();
assert_eq(result, Ok(15)); // 假设我们的聚合函数是求和
// 清理
client.update("DROP TABLE test_agg;", None, None);
});
}
完整示例demo
下面是一个完整的pgrx扩展测试示例,包含多个测试场景:
// src/lib.rs
use pgrx::prelude::*;
#[pg_extern]
fn add_numbers(a: i32, b: i32) -> i32 {
a + b
}
#[pg_extern]
fn string_length(s: &str) -> i32 {
s.len() as i32
}
#[cfg(test)]
mod tests {
use super::*;
use pgrx::prelude::*;
use pgrx_tests::pg_test;
// 测试初始化函数
fn setup_test_table() {
Spi::connect(|client| {
client.update("CREATE TABLE test_data (id serial, name text);", None, None);
client.update("INSERT INTO test_data (name) VALUES ('test1'), ('test2');", None, None);
});
}
// 基本功能测试
#[pg_test]
fn test_add_numbers() {
Spi::connect(|client| {
let result = client.select("SELECT add_numbers(1, 2);", None, None)
.first()
.get_one::<i32>();
assert_eq!(result, Ok(3));
});
}
// 字符串函数测试
#[pg_test]
fn test_string_length() {
Spi::connect(|client| {
let result = client.select("SELECT string_length('hello');", None, None)
.first()
.get_one::<i32>();
assert_eq!(result, Ok(5));
});
}
// 带初始化的测试
#[pg_test(initialization = "setup_test_table")]
fn test_table_operations() {
Spi::connect(|client| {
// 验证表创建和数据插入
let count = client.select("SELECT COUNT(*) FROM test_data;", None, None)
.first()
.get_one::<i64>();
assert_eq!(count, Ok(2));
// 测试数据内容
let name = client.select("SELECT name FROM test_data WHERE id = 1;", None, None)
.first()
.get_one::<String>();
assert_eq!(name, Ok("test1".to_string()));
});
}
// 并行测试
#[pg_test(parallel)]
fn test_parallel_1() {
Spi::connect(|client| {
let result = client.select("SELECT add_numbers(10, 20);", None, None)
.first()
.get_one::<i32>();
assert_eq!(result, Ok(30));
});
}
#[pg_test(parallel)]
fn test_parallel_2() {
Spi::connect(|client| {
let result = client.select("SELECT string_length('parallel');", None, None)
.first()
.get_one::<i32>();
assert_eq!(result, Ok(8));
});
}
// 事务测试
#[pg_test(transaction)]
fn test_in_transaction() {
Spi::connect(|client| {
// 这个操作会在事务中执行,测试完成后自动回滚
client.update("INSERT INTO test_data (name) VALUES ('temp');", None, None);
let count = client.select("SELECT COUNT(*) FROM test_data;", None, None)
.first()
.get_one::<i64>();
assert_eq!(count, Ok(3));
});
}
}
最佳实践
- 隔离测试:每个测试应该独立运行,不依赖其他测试的状态
- 清理资源:测试后清理创建的表或其他对象
- 使用事务:对于可能失败的测试,使用事务避免污染数据库状态
- 组合测试:将相关测试组织在一起,使用模块化结构
- 性能考虑:对于耗时测试,标记为
#[ignore]
并在需要时单独运行
调试技巧
如果测试失败,可以:
- 使用
cargo pgrx test -- --nocapture
查看完整输出 - 检查PostgreSQL日志获取更多信息
- 使用
#[pg_test(verbose)]
获取更详细的执行信息
pgrx-tests框架通过简化PostgreSQL扩展的测试流程,显著提高了开发效率和代码质量,是开发高质量PostgreSQL扩展的必备工具。