Rust断言库assertor的使用:高效测试与验证代码逻辑的必备工具

Rust断言库assertor的使用:高效测试与验证代码逻辑的必备工具

Assertor是一个使测试断言和失败信息更易读的Rust库。它深受Java Truth在API设计和错误信息方面的启发,但这是一个完全独立的项目。

免责声明

这不是Google的官方产品,只是Google拥有的代码。⚠ API尚未完全稳定,可能在1.0版本之前会有变化。

示例

use assertor::*;

#[test]
fn test_it() {
    assert_that!("foobarbaz").contains("bar");
    assert_that!("foobarbaz").ends_with("baz");

    assert_that!(0.5).with_abs_tol(0.2).is_approx_equal_to(0.6);

    assert_that!(vec!["a", "b"]).contains("a");
    assert_that!(vec!["a", "b"]).has_length(2);
    assert_that!("foobarbaz").ends_with("baz");

    assert_that!(0.5).with_abs_tol(0.2).is_approx_equal_to(0.6);

    assert_that!(vec!["a", "b"]).contains("a");
    assert_that!(vec!["a", "b"]).has_length(2);
    assert_that!(vec!["a", "b"]).contains_exactly(vec!["a", "b"]);

    assert_that!(Option::Some("Foo")).has_value("Foo");
}

完整示例demo

// 引入assertor库
use assertor::*;

// 测试字符串操作
#[test]
fn test_string_assertions() {
    // 检查字符串包含
    assert_that!("hello world").contains("world");
    // 检查字符串结尾
    assert_that!("foo bar").ends_with("bar");
}

// 测试数值操作
#[test]
fn test_numeric_assertions() {
    // 近似相等检查
    assert_that!(1.0).with_abs_tol(0.1).is_approx_equal_to(1.05);
}

// 测试集合操作
#[test]
fn test_collection_assertions() {
    let vec = vec![1, 2, 3];
    // 检查集合长度
    assert_that!(vec).has_length(3);
    // 检查集合包含元素
    assert_that!(vec).contains(2);
}

// 测试Option操作
#[test]
fn test_option_assertions() {
    // 检查Some值
    assert_that!(Some("value")).has_value("value");
    // 检查None
    assert_that!(Option::<i32>::None).is_none();
}

// 测试anyhow错误(需要启用anyhow特性)
#[cfg(feature = "anyhow")]
#[test]
fn test_anyhow_assertions() {
    use anyhow::anyhow;
    
    fn failing_function() -> anyhow::Result<()> {
        Err(anyhow!("operation failed"))
    }
    
    assert_that!(failing_function())
        .err()
        .has_message("operation failed");
}

特性想法

  • [ ] 颜色/加粗
  • [ ] 更好的diff: vec
  • [ ] 更好的diff: set
  • [ ] 更好的diff: HashMap

安装

在项目目录中运行以下Cargo命令:

cargo add assertor

或者在Cargo.toml中添加:

assertor = "0.0.4"

要使用anyhow功能,请添加:

assertor = { version = "0.0.4", features = ["anyhow"] }

1 回复

Rust断言库assertor的使用:高效测试与验证代码逻辑的必备工具

assertor是Rust中一个强大的断言库,它提供了丰富的断言方法,可以帮助开发者更高效地编写测试和验证代码逻辑。相比标准库中的assert!宏,assertor提供了更详细的错误信息和更灵活的断言方式。

安装

Cargo.toml中添加依赖:

[dependencies]
assertor = "0.8"

基本使用方法

1. 基本断言

use assertor::*;

#[test]
fn test_basic_assertions() {
    assert_that!(true).is_true();
    assert_that!(false).is_false();
    
    assert_that!(10).is_equal_to(10);
    assert_that!(10).is_not_equal_to(20);
}

2. 数值比较

#[test]
fn test_number_comparisons() {
    let value = 42;
    
    assert_that!(value).is_greater_than(30);
    assert_that!(value).is_greater_than_or_equal_to(42);
    assert_that!(value).is_less_than(50);
    assert_that!(value).is_less_than_or_equal_to(42);
    
    // 范围检查
    assert_that!(value).is_between(40, 45);
}

3. 字符串断言

#[test]
fn test_string_assertions() {
    let message = "Hello, Rust!";
    
    assert_that!(message).is_equal_to("Hello, Rust!");
    assert_极速!");
    assert_that!(message).contains("Rust");
    assert_that!(message).starts_with("Hello");
    assert_that!(message).ends_with("!");
    assert_that!(message).has_length(12);
}

4. 集合断言

#[test]
fn test_collection_assertions() {
    let numbers = vec![1, 2, 3, 4, 5];
    
    assert_that!(numbers).has_length(5);
    assert_that!(numbers).contains(3);
    assert_that!(numbers).does_not_contain(10);
    assert_that!(numbers).contains_all_of(&[2, 4]);
    assert_that!(numbers).contains_exactly(&[1, 2, 3, 4, 5]);
}

5. Option和Result断言

#[test]
fn test_option_result_assertions() {
    let some_value: Option<i32> = Some(42);
    let none_value: Option<i32> = None;
    
    assert_that!(some_value).is_some();
    assert_that!(some_value).is_some_and(|x| *x == 42);
    assert_that!(none_value).is_none();
    
    let ok_result: Result<i32, &str> = Ok(42);
    let err_result: Result<i32, &str> = Err("error");
    
    assert_that!(ok_result).is_ok();
    assert_that!(ok_result).is_ok_and(|x| *x == 42);
    assert_that!(err_result).is_err();
    assert_that!(err_result).is_err_and(|x| *x == "error");
}

6. 浮点数比较(考虑浮点精度)

#[test]
fn test_float_comparisons() {
    let pi = 3.14159265359;
    
    // 默认精度比较
    assert_that!(pi).is_close_to(3.14, 0.01);
    
    // 自定义精度比较
    assert_that!(pi).is_close_to(3.1416, 0.0001);
}

7. 布尔表达式断言

#[test]
fn test_boolean_conditions() {
    let x = 10;
    let y = 20;
    
    assert_that!(x > 5 && y < 30).is_true();
    assert_that!(x == y).is_false();
}

高级功能

1. 自定义错误信息

#[test]
fn test_with_custom_message() {
    let value = 42;
    assert_that!(value)
        .with_message("Value should be between 40 and 50")
        .is_between(40, 50);
}

2. 链式调用

#[test]
fn test_chained_assertions() {
    let name = "Rust";
    
    assert_that!(name)
        .has_length(4)
        .starts_with("R")
        .ends_with("t")
        .contains("us");
}

3. 异步测试支持

#[tokio::test]
async fn test_async_code() {
    let result = some_async_function().await;
    assert_that!(result).is_ok();
}

完整示例代码

下面是一个综合使用assertor的完整测试示例:

use assertor::*;

// 测试模块
#[cfg(test)]
mod tests {
    use super::*;
    
    // 测试基本断言
    #[test]
    fn test_integrated_assertions() {
        // 测试数值
        let age = 25;
        assert_that!(age)
            .is_greater_than(18)
            .is_less_than(60)
            .is_equal_to(25);
            
        // 测试字符串
        let username = "rustacean";
        assert_that!(username)
            .has_length(9)
            .starts_with("rust")
            .contains("ace")
            .is_equal_to("rustacean");
            
        // 测试集合
        let languages = vec!["Rust", "Go", "Python"];
        assert_that!(languages)
            .has_length(3)
            .contains("Rust")
            .does_not_contain("Java")
            .contains_all_of(&["Go", "Python"]);
            
        // 测试Option
        let some_value: Option<&str> = Some("hello");
        assert_that!(some_value)
            .is_some()
            .is_some_and(|x| *x == "hello");
            
        // 测试Result
        let result: Result<i32, &str> = Ok(100);
        assert_that!(result)
            .is_ok()
            .is_ok_and(|x| *x == 100);
    }
    
    // 测试自定义错误信息
    #[test]
    fn test_custom_error_message() {
        let score = 85;
        assert_that!(score)
            .with_message("Score should be between 80 and 90")
            .is_between(80, 90);
    }
    
    // 异步测试示例
    #[tokio::test]
    async fn test_async_operation() {
        async fn fetch_data() -> Result<String, &'static str> {
            Ok("data".to_string())
        }
        
        let result = fetch_data().await;
        assert_that!(result)
            .is_ok()
            .is_ok_and(|x| *x == "data");
    }
}

为什么选择assertor

  1. 丰富的断言方法:提供比标准库更全面的断言选项
  2. 清晰的错误信息:失败时提供详细的错误描述,便于调试
  3. 链式调用:支持流畅的API设计,使测试代码更易读
  4. 类型安全:充分利用Rust的类型系统,减少运行时错误
  5. 活跃维护:定期更新,与Rust生态系统保持同步

assertor是Rust测试工具链中的强大补充,特别适合需要编写大量测试或复杂断言的项目。通过其丰富的API,可以显著提高测试代码的可读性和维护性。

回到顶部