14 个版本 (破坏性)
0.12.0 | 2024年8月2日 |
---|---|
0.11.0 | 2024年1月12日 |
0.10.0 | 2023年8月25日 |
0.9.0 | 2023年7月14日 |
0.2.0 | 2022年12月27日 |
#15 in 测试
每月下载量 33,207
用于 14 个 crate(直接使用10个)
550KB
9K SLoC
GoogleTest Rust
此库将 Google 的 C++ 测试库 GoogleTest 的丰富断言类型引入 Rust。它提供
- 一个用于编写匹配器的框架,可以组合使用以对数据进行各种断言
- 一套丰富的匹配器,提供类似于 GoogleTest 中包含的匹配器的功能
- 一套新的断言宏,提供类似于 GoogleTest 的功能
最低支持的 Rust 版本是 1.66.
⚠️ API 仍处于不稳定状态,在发布 1.0 版本之前可能会发生变化。
此外,任何以
__
(双下划线)开头的项目或模块都不应直接使用。这些项目或模块仅供内部使用,其 API 可能会更改,而无需进行主要版本更新。
学习资源
如果您刚开始使用 googletest
,可以考虑阅读"Rust 应用高级测试"的第一个章节,这是一门自学 Rust 课程:它提供了一个关于库的引导介绍,包括练习,帮助您熟悉 googletest
宏、其匹配器及其整体理念。
断言和匹配器
GoogleTest 的核心是其 匹配器。匹配器表明正在断言实际值的一个方面:(不)相等性、包含、正则表达式匹配等。
要使用匹配器进行断言,GoogleTest 提供了三个宏
assert_that!
如果断言失败,则会引发恐慌,终止测试。expect_that!
会记录断言失败,将测试标记为失败,但允许测试继续运行(称为非致命断言)。它需要在测试本身上使用googletest::test
属性宏。verify_that!
没有副作用,并评估为Result<()>
类型,其Err
变体描述了断言失败,如果有的话。结合?
操作符,可以在不引发恐慌的情况下在断言失败时终止测试。这也是上面两个宏的基础。
例如
use googletest::prelude::*;
#[test]
fn fails_and_panics() {
let value = 2;
assert_that!(value, eq(4));
}
#[googletest::test]
fn two_logged_failures() {
let value = 2;
expect_that!(value, eq(4)); // Test now failed, but continues executing.
expect_that!(value, eq(5)); // Second failure is also logged.
}
#[test]
fn fails_immediately_without_panic() -> Result<()> {
let value = 2;
verify_that!(value, eq(4))?; // Test fails and aborts.
verify_that!(value, eq(2))?; // Never executes.
Ok(())
}
#[test]
fn simple_assertion() -> Result<()> {
let value = 2;
verify_that!(value, eq(4)) // One can also just return the last assertion.
}
该库包含了一套丰富的匹配器,涵盖
- 等价性、数值不等式和近似等价性;
- 字符串和正则表达式;
- 容器和集合论匹配。
匹配器是可组合的
use googletest::prelude::*;
#[googletest::test]
fn contains_at_least_one_item_at_least_3() {
let value = vec![1, 2, 3];
expect_that!(value, contains(ge(3)));
}
它们也可以进行逻辑组合
use googletest::prelude::*;
#[googletest::test]
fn strictly_between_9_and_11() {
let value = 10;
expect_that!(value, gt(9).and(not(ge(11))));
}
模式匹配
可以使用宏 matches_pattern!
创建一个复合匹配器,用于匹配结构体或枚举的字段与其他匹配器
use googletest::prelude::*;
struct AStruct {
a_field: i32,
another_field: i32,
a_third_field: &'static str,
}
#[test]
fn struct_has_expected_values() {
let value = AStruct {
a_field: 10,
another_field: 100,
a_third_field: "A correct value",
};
expect_that!(value, matches_pattern!(AStruct {
a_field: eq(10),
another_field: gt(50),
a_third_field: contains_substring("correct"),
}));
}
编写匹配器
可以通过编写额外的匹配器来扩展库。为此,创建一个包含匹配器数据的结构体,并使其实现 Matcher
特性
struct MyEqMatcher<T> {
expected: T,
}
impl<T: PartialEq + Debug + Copy> Matcher<T> for MyEqMatcher<T> {
fn matches(&self, actual: T) -> MatcherResult {
(self.expected == actual).into()
}
fn describe(&self, matcher_result: MatcherResult) -> String {
match matcher_result {
MatcherResult::Match => {
format!("is equal to {:?} the way I define it", self.expected)
}
MatcherResult::NoMatch => {
format!("isn't equal to {:?} the way I define it", self.expected)
}
}
}
}
建议公开一个构造匹配器的函数
pub fn eq_my_way<T: PartialEq + Debug>(expected: T) -> impl Matcher<T> {
MyEqMatcher { expected }
}
然后,新匹配器可以用于断言宏
#[googletest::test]
fn should_be_equal_by_my_definition() {
expect_that!(10, eq_my_way(10));
}
非致命断言
使用非致命断言,单个测试能够记录多次断言失败。任何单个断言失败都会导致测试被认为是失败的,但执行将继续,直到测试完成或终止。
这类似于GoogleTest中的 EXPECT_*
宏系列。
要创建非致命断言,请使用宏 expect_that!
。测试还必须使用 googletest::test
而不是Rust标准的 #[test]
。
use googletest::prelude::*;
#[googletest::test]
fn three_non_fatal_assertions() {
let value = 2;
expect_that!(value, eq(2)); // Passes; test still considered passing.
expect_that!(value, eq(3)); // Fails; logs failure and marks the test failed.
expect_that!(value, eq(4)); // A second failure, also logged.
}
这可以在与 verify_that!
相同的测试中使用,在这种情况下,测试函数还必须返回 Result<()>
use googletest::prelude::*;
#[googletest::test]
fn failing_non_fatal_assertion() -> Result<()> {
let value = 2;
expect_that!(value, eq(3)); // Just marks the test as having failed.
verify_that!(value, eq(2))?; // Passes, so does not abort the test.
Ok(()) // Because of the failing expect_that! call above, the
// test fails despite returning Ok(())
}
use googletest::prelude::*;
#[googletest::test]
fn failing_fatal_assertion_after_non_fatal_assertion() -> Result<()> {
let value = 2;
verify_that!(value, eq(3))?; // Fails and aborts the test.
expect_that!(value, eq(3)); // Never executes, since the test already aborted.
Ok(())
}
互操作性
您可以使用 #[googletest::test]
宏与其他许多库(如 rstest)一起使用。只需将两个属性宏都应用到测试上即可
#[googletest::test]
#[rstest]
#[case(1)]
#[case(2)]
#[case(3)]
fn rstest_works_with_google_test(#[case] value: u32) -> Result<()> {
verify_that!(value, gt(0))
}
请确保在 #[googletest::test]
之前 放置 #[rstest]
。否则,由于两个宏都会尝试将测试注册到Rust测试框架中,标记的测试将运行两次。
该宏还可以与 使用Tokio的异步测试 以相同的方式一起使用
#[googletest::test]
#[tokio::test]
async fn should_work_with_tokio() -> Result<()> {
verify_that!(3, gt(0))
}
当运行异步测试时有一个需要注意的地方:如果断言发生在运行测试的不同线程上,则通过 and_log_failure
的测试失败报告将无法正常工作。
谓词断言
宏 verify_pred!
提供了类似于 GoogleTest 的 EXPECT_PRED
宏家族的谓词断言。将谓词调用包裹在 verify_pred!
调用中,将其转换为当谓词返回 true
时才通过的测试断言。
fn stuff_is_correct(x: i32, y: i32) -> bool {
x == y
}
let x = 3;
let y = 4;
verify_pred!(stuff_is_correct(x, y))?;
断言失败消息将显示参数及其评估的值
stuff_is_correct(x, y) was false with
x = 3,
y = 4
verify_pred!
调用将评估为一个 Result<()>
,就像 verify_that!
一样。还有一个宏 expect_pred!
可以进行非致命的谓词断言。
无条件生成测试失败
宏 fail!
无条件评估为一个表示测试失败的 Result
。它可以类似于 verify_that!
和 verify_pred!
使用,以导致测试失败,并可选择格式化的消息。
#[test]
fn always_fails() -> Result<()> {
fail!("This test must fail with {}", "today")
}
配置
该库可以通过环境变量进行配置。由于配置不影响测试是否失败,而只影响失败的显示方式,我们建议在个人的 ~/.cargo/config.toml
中设置这些变量,而不是在项目范围的 Cargo.toml
中。
配置变量列表
变量名 | 描述 |
---|---|
NO_COLOR | 禁用彩色输出。请参阅 https://no-color.org/。 |
FORCE_COLOR | 即使输出被重定向到文件,也强制使用颜色。 |
提交更改
请阅读 CONTRIBUTING.md 了解如何为该项目做出贡献的详细信息。
依赖关系
~2.6–4.5MB
~83K SLoC