Rust测试断言库hamcrest2的使用:增强单元测试和集成测试的断言功能与匹配器
Rust测试断言库hamcrest2的使用:增强单元测试和集成测试的断言功能与匹配器
Hamcrest2是Hamcrest库的Rust移植版本,它是一个维护良好的fork,提供了额外的匹配器、更好的文档以及对Rust 2018 edition的支持。
安装
在Cargo.toml中添加以下依赖:
[dev-dependencies]
hamcrest2 = "*"
使用
最简单的方式是导入所有匹配器:
use hamcrest2::prelude::*;
如果需要选择性导入,请确保同时导入HamcrestMatcher
trait。
示例代码
通用匹配器
// 相等和不等匹配
assert_that!(1, eq(1)); // 也可以使用equal_to()
assert_that!(1, not(eq(2)));
// 比较匹配
assert_that!(1, lt(2)); // 也可以使用less_than()
assert_that!(1, leq(1)); // 也可以使用less_than_or_equal_to()
assert_that!(2, gt(1)); // 也可以使用greater_than()
assert_that!(2, geq(2)); // 也可以使用greater_than_or_equal_to()
// 类型匹配
assert_that!(123usize, type_of::<usize>());
assert_that!("test", type_of::<&str>());
// 正则匹配
assert_that!("1234", matches_regex(r"\d"));
assert_that!("abc", does_not(match_regex(r"\d")));
数值匹配器
assert_that!(1e-40f32, close_to(0.0, 0.01));
assert_极客时间
assert_that!(1e-40f32, not(close_to(0.0, 0.000001)));
文件系统匹配器
let path = Path::new("./README.md");
assert_that!(path, path_exists());
assert_that!(path, file_exists());
assert_that!(path, not(dir_exists()));
Option和Result匹配
// has匹配器
let var: Option<i8> = Some(5);
assert_that!(var, has(5));
let var: Result<i8, String> = Ok(5);
assert_that!(var, has(5));
// ok匹配器
let var: Result<i8, String> = Ok(5);
assert_that!(var, ok());
assert_that!(&var, ok());
assert_that!(Ok极客时间(5), ok::<i8, String>());
assert_that!(&Ok(5), ok::<i8, String>());
let var: Result<i8, String> = Err("bad!".to_string());
assert_that!(var, not(ok()));
assert_that!(&var, not(ok()));
// err匹配器
let var: Result<i8, String> = Err("bad!".to_string());
assert_that!(var, err());
assert_that!(&var, err());
assert_that!(Err("bad!".to_string()), err::<i8, String>());
assert_that!(&Err("bad!".to_string()), err::<i8, String>());
let var: Result<i8, String> = Ok(5);
assert_that!(var, not(err()));
assert_that!(&var, not(err()));
// some匹配器
let var: Option<i8> = Some(5);
assert_that!(var, some());
assert_that!(&var, some());
assert_that!(Some(1), some::<u8>());
assert_that!(&Some(1), some::<u8>());
let var: Option<i8> = None;
assert_that!(var, not(some()));
assert_that!(&var, not(some()));
// none匹配器
let var: Option<i8> = None;
assert_that!(var, none());
assert_that!(&var, none());
assert_that!(None, none::<u8>());
assert_that!(&None, none::<u8>());
assert_that!(Some(1), not(none::<u8>()));
assert_that!(&Some(1), not(none::<u8>()));
集合匹配器
assert_that!(&vec!(1, 2, 3), contains(vec!(1, 2)));
assert_that!(&vec!(1, 2, 3), contains(1));
assert_that!(&vec!(1, 2, 3), not(contains(4i)));
assert_that!(&vec!(1, 2, 3), contains(vec!(1, 2, 3)).exactly());
assert_that!(&vec!(1, 2, 3), not(contains(vec!(1, 2)).exactly()));
assert_that!(&vec!(1, 2, 3), contains(vec!(1, 2)).in_order());
assert_that!(&vec!(1, 2, 3), not(contains(vec!(1, 3)).in_order()));
// 长度匹配
assert_that!(&vec!(1, 2, 3), len(3));
assert_that!(&vec!(1, 2, 极客时间3), not(len(4)));
// 空集合匹配
assert_that!(&Vec::<i32>::new(), empty());
assert_that!(&vec![1, 2, 3], not(empty()));
复合匹配器
// all匹配器
assert_that!(4, all!(lt(5), gt(3))); // 也可以使用and!()
assert_that!(
&vec![1, 2, 3],
all!(contains(vec![1, 2]), not(contains(vec![4])))
);
// any匹配器
assert_that!(4, any!(less_than(2), greater_than(3))); // 也可以使用or!()
assert_that!(
&vec![1, 2, 3],
any!(contains(vec![1, 2, 5]), not(contains(vec![4])))
);
其他匹配器
// 布尔匹配
assert_that!(true, is(true));
assert_that!(false, is(false));
// 任意值匹配
assert_that!(42, anything());
assert_that!("test", is(anything()));
完整示例Demo
// 示例测试模块
#[cfg(test)]
mod tests {
use hamcrest2::prelude::*;
use std::path::Path;
#[test]
fn test_basic_assertions() {
// 数值比较
assert_that!(10, gt(5));
assert_that!(3.14, close_to(3.14159, 0.01));
// 字符串匹配
assert_that!("hello world", matches_regex(r"hello"));
assert_that!("12345", matches_regex(r"\d+"));
// 文件系统测试
let test_file = Path::new("Cargo.toml");
assert_that!(test_file, file_exists());
}
#[test]
fn test_collections() {
let numbers = vec![1, 2, 3, 4, 5];
// 集合包含测试
assert_that!(&numbers, contains(3));
assert_that!(&numbers, contains(vec![2, 4]));
assert_that!(&numbers, len(5));
// 精确匹配
assert_that!(&numbers, contains(vec![1, 2, 3, 4, 5]).exactly());
}
#[test]
fn test_options_results() {
// Option测试
let some_value: Option<i32> = Some(42);
assert_that!(some_value, some());
assert_that!(some_value, has(42));
// Result测试
let ok_result: Result<&str极客时间, &str> = Ok("success");
assert_that!(ok_result, ok());
assert_that!(ok_result, has("success"));
let err_result: Result<(), &str> = Err("failure");
assert_that!(err_result, err());
}
#[test]
fn test_complex_conditions() {
// 复合条件测试
assert_that!(
15,
all!(
gt(10),
lt(20),
is(15)
)
);
// 使用or条件
assert_that!(
"test string",
any!(
matches_regex(r"test"),
matches_regex(r"string")
)
);
}
}
许可证
Hamcrest2采用以下许可证:
- Apache License, Version 2.0
- MIT license
您可以选择其中任何一种许可证使用。
1 回复
Rust测试断言库hamcrest2使用指南
hamcrest2是一个Rust测试断言库,提供了丰富的匹配器(matchers)来增强单元测试和集成测试的断言功能。它基于Hamcrest模式,为测试提供了更灵活和表达性强的断言方式。
安装
在Cargo.toml中添加依赖:
[dev-dependencies]
hamcrest2 = "0.3.0"
基本使用
use hamcrest2::prelude::*;
#[test]
fn test_basic_assertions() {
// 等于匹配
assert_that!(42, eq(42));
// 不等于匹配
assert_that!("hello", ne("world"));
// 大于匹配
assert_that!(10, gt(5));
}
常用匹配器
值匹配
#[test]
fn test_value_matchers() {
let value = 42;
// 等于
assert_that!(value, eq(42));
// 不等于
assert_that!(value, ne(0));
// 大于
assert_that!(value, gt(40));
// 小于
assert_that!(value, lt(50));
// 在范围内
assert_that!(value, is(within(40..=45)));
}
字符串匹配
#[test]
fn test_string_matchers() {
let text = "Rust programming language";
// 包含子串
assert_that!(text, contains_str("program"));
// 以...开头
assert_that!(text, starts_with("Rust"));
// 以...结尾
assert_that!(text, ends_with("language"));
// 正则匹配
assert_that!(text, matches_regex(r"Rust .* language"));
}
集合匹配
#[test]
fn test_collection_matchers() {
let vec = vec![1, 2, 3, 4, 5];
// 集合长度
assert_that!(vec, has_length(5));
// 包含元素
assert_that!(vec, contains(3));
// 不包含元素
assert_that!(vec, not(contains(6)));
// 所有元素满足条件
assert_that!(vec, every_item(gt(0)));
}
组合匹配器
#[test]
fn test_combinators() {
let value = 15;
// 逻辑与
assert_that!(value, all_of![gt(10), lt(20)]);
// 逻辑或
assert_that!(value, any_of![eq(10), eq(15)]);
// 逻辑非
assert_that!(value, not(eq(0)));
}
Option和Result匹配
#[test]
fn test_option_result_matchers() {
// Option匹配
let some_value: Option<i32> = Some(42);
assert_that!(some_value, is_some());
assert_that!(some_value, is_some_with(eq(42)));
let none_value: Option<i32> = None;
assert_that!(none_value, is_none());
// Result匹配
let ok_result: Result<i32, &str> = Ok(42);
assert_that!(ok_result, is_ok());
assert_that!(ok_result, is_ok_with(eq(42)));
let err_result: Result<i32, &str> = Err("error");
assert_极速running("error"));
}
自定义匹配器
你可以创建自己的匹配器:
use hamcrest2::core::*;
fn is_even() -> Matcher<'static, i32> {
Matcher::new(
|x: &i32| x % 2 == 0,
"even number",
"odd number",
)
}
#[test]
fn test_custom_matcher() {
assert_that!(42, is_even());
assert_that!(43, not(is_even()));
}
错误信息
当断言失败时,hamcrest2会提供详细的错误信息:
#[test]
fn test_error_messages() {
let vec = vec![1, 2, 3];
// 失败时会显示:Expected: collection containing <4> but: was <[1, 2, 3]>
assert_that!(vec, contains(4));
}
hamcrest2通过丰富的匹配器和组合能力,可以编写出更清晰、更具表达力的测试断言,特别适合复杂条件的测试场景。