Rust断言测试库assert_ok的使用,assert_ok提供简洁高效的Result类型断言功能
assert_ok
这个crate包含一个宏assert_ok
,它接受一个表达式,如果表达式评估为Err
,则会panic并显示有用的消息。相反,如果表达式评估为Ok(v)
,则返回值v
。
这在测试中通常很有用。相比于:
let z = foo(arg1, arg2).unwrap();
或者
let z = foo(arg1, arg2).expect("foo failed");
可以使用:
let z = assert_ok!(foo(arg1, arg2));
这样更容易理解,更重要的是在失败的情况下提供了更有用的错误消息。
Tokio中有一个类似的宏,但对于不使用Tokio的库或应用程序来说,为了一个宏而引入它没有意义。
完整示例代码
// 首先需要在Cargo.tml中添加依赖
// assert_ok = "1.0.2"
use assert_ok::assert_ok;
// 定义一个可能返回错误的除法函数
fn divide(a: i32, b: i32) -> Result<i32, String> {
if b == 0 {
Err("Cannot divide by zero".to_string())
} else {
Ok(a / b)
}
}
#[test]
fn test_divide() {
// 成功的情况
let result = assert_ok!(divide(10, 2));
assert_eq!(result, 5);
// 失败的情况 - 会panic并显示错误信息
// let result = assert_ok!(divide(10, 0));
}
fn main() {
// 在非测试代码中使用
match divide(10, 2) {
Ok(result) => println!("Result: {}", result),
Err(e) => println!("Error: {}", e),
}
// 如果确定不会出错,可以这样使用
let result = assert_ok!(divide(10, 2));
println!("Result: {}", result);
}
安装
在项目目录中运行以下Cargo命令:
cargo add assert_ok
或者在Cargo.toml中添加以下行:
assert_ok = "1.0.2"
许可证
Apache-2.0 OR MIT
1 回复
Rust断言测试库assert_ok的使用
assert_ok
是一个简洁高效的Rust测试库,专门用于对Result
类型进行断言测试。它提供了直观的API来验证操作是否成功并检查返回的值。
安装方法
在Cargo.toml中添加依赖:
[dev-dependencies]
assert_ok = "1.0"
主要功能
- 验证
Result
是否为Ok
- 提取
Ok
值进行进一步断言 - 链式调用支持
基本使用方法
简单断言
use assert_ok::assert_ok;
#[test]
fn test_simple_assertion() {
let result: Result<i32, &str> = Ok(42);
assert_ok!(result); // 简单地断言Result是Ok
}
提取值并断言
#[test]
fn test_value_extraction() {
let result: Result<String, &str> = Ok("hello".to_string());
let value = assert_ok!(result); // 提取Ok值
assert_eq!(value, "hello"); // 对提取的值进行断言
}
直接比较返回值
#[test]
fn test_direct_comparison() {
let result: Result<i32, &str> = Ok(42);
assert_ok!(result, 42); // 直接比较Ok值是否等于42
}
使用模式匹配
#[test]
fn test_pattern_matching() {
let result: Result<(i32, i32), &str> = Ok((10, 20));
let (a, b) = assert_ok!(result); // 使用模式匹配解构元组
assert_eq!(a, 10);
assert_eq!(b, 20);
}
链式调用
#[test]
fn test_chaining() {
let result: Result<Vec<i32>, &str> = Ok(vec![1, 2, 3]);
assert_ok!(result) // 提取Ok值
.iter() // 链式调用迭代器方法
.for_each(|x| assert!(x > &0)); // 对每个元素断言
}
高级用法
自定义错误消息
#[test]
fn test_custom_message() {
let result: Result<i32, &str> = Err("something went wrong");
assert_ok!(result, "Expected successful result but got error"); // 自定义错误消息
}
与?
操作符结合
#[test]
fn test_with_try_operator() -> Result<(), &'static str> {
let value = assert_ok!(some_function()?); // 结合?操作符使用
// 使用value进行更多测试
Ok(())
}
完整示例demo
// 首先在Cargo.toml中添加依赖:
// [dev-dependencies]
// assert_ok = "1.0"
use assert_ok::assert_ok;
// 被测函数1 - 返回Result的简单函数
fn divide(a: i32, b: i32) -> Result<i32, &'static str> {
if b == 0 {
Err("division by zero")
} else {
Ok(a / b)
}
}
// 被测函数2 - 返回Result的复杂类型
fn parse_numbers(s: &str) -> Result<Vec<i32>, &'static str> {
s.split(',')
.map(|part| part.trim().parse().map_err(|_| "parse error"))
.collect()
}
#[test]
fn test_divide_success() {
let result = divide(10, 2);
assert_ok!(result, 5); // 直接比较返回值
}
#[test]
fn test_divide_failure() {
let result = divide(10, 0);
assert_ok!(result, "division by zero"); // 测试预期错误
}
#[test]
fn test_parse_numbers() {
let result = parse_numbers("1, 2, 3, 4, 5");
// 提取值并链式调用
assert_ok!(result)
.iter()
.enumerate()
.for_each(|(i, &x)| assert_eq!(x, (i + 1) as i32));
}
#[test]
fn test_pattern_matching_demo() {
fn get_coordinates() -> Result<(f64, f64), &'static str> {
Ok((35.6895, 139.6917))
}
let (lat, lon) = assert_ok!(get_coordinates()); // 模式匹配解构
assert!((lat - 35.6895).abs() < 0.0001);
assert!((lon - 139.6917).abs() < 0.0001);
}
#[test]
fn test_custom_error_message() {
let result: Result<i32, &str> = Err("database connection failed");
assert_ok!(result, "Expected successful database operation");
}
与标准库断言比较
传统方式:
assert!(result.is_ok());
let value = result.unwrap();
使用assert_ok
更简洁安全:
let value = assert_ok!(result);
assert_ok
在测试失败时会提供更清晰的错误信息,并且避免了直接使用unwrap()
可能导致的panic风险。
注意事项
- 仅推荐在测试代码中使用
- 测试失败时会打印详细的错误信息
- 支持所有实现了
Debug
trait的Result
类型
这个库特别适合需要频繁测试返回Result
类型的函数的场景,能显著提高测试代码的可读性和编写效率。