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"

主要功能

  1. 验证Result是否为Ok
  2. 提取Ok值进行进一步断言
  3. 链式调用支持

基本使用方法

简单断言

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风险。

注意事项

  1. 仅推荐在测试代码中使用
  2. 测试失败时会打印详细的错误信息
  3. 支持所有实现了Debug trait的Result类型

这个库特别适合需要频繁测试返回Result类型的函数的场景,能显著提高测试代码的可读性和编写效率。

回到顶部