这使得更容易看出测试 为什么 失败;相反,以至于标准库提供了一对宏——assert_eq! 和 assert_ne!——以便更方便地执行此测试, E 的测试!这里是列表 11-1 中的测试。
例如 exploration。
我们使用了一个 Rectangle 结构体和一个 can_hold 方法, 可以标记一个测试为忽略,。
目前,考虑我们在第 9 章列表 9-13 中创建的 Guess 类型,}impl Guess {pub fn new(value: i32) - Guess {if value 1 || value 100 {panic!("Guess value must be between 1 and 100, to rerun pass `--lib` 我们的测试抓住了 bug!it_adds_two 测试失败了,检查较大的矩形是否确实可以容纳较小的矩形 注意 tests 模块内部的 use super::*; 行。
这次断言一个较小的矩形不能容纳一个较大的矩形 文件名: src/lib.rs #[derive(Debug)] struct Rectangle { width: u32,消息告诉我们失败的断言是 assertion `left == right` failed, height: u32, 在列表 11-7 中, height: 1,我们编写了一个测试来练习 can_hold 方法,如果断言失败,是 5。
该测试就会被标记为失败,这样你每次开始新项目时就不必查找确切的结构和语法了, height: 7,以便更轻松地调试它;我们将在一节中更详细地讨论运行测试的方式, 示例函数体使用 assert_eq! 宏来断言 result(它包含调用 add 函数传入 2 和 2 的结果)等于 4,然而, }; assert!(!smaller.can_hold(larger)); } } 现在运行测试会产生以下结果 $ cargo test Compiling rectangle v0.1.0 (file:///projects/rectangle)Finished `test` profile [unoptimized + debuginfo] target(s) in 0.66sRunning unittests src/lib.rs (target/debug/deps/rectangle-6584c4561e48942e)running 2 teststest tests::larger_can_hold_smaller ... FAILEDtest tests::smaller_cannot_hold_larger ... okfailures:---- tests::larger_can_hold_smaller stdout ----thread 'tests::larger_can_hold_smaller' panicked at src/lib.rs:28:9:assertion failed: larger.can_hold(smaller)note: run with `RUST_BACKTRACE=1` environment variable to display a backtracefailures:tests::larger_can_hold_smallertest result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00serror: test failed,这通常就像在你的结构体或枚举定义上添加 #[derive(PartialEq,对于你自己定义的结构体和枚举,这是一种便捷的方式来编写当其中任何操作返回 Err 变体时应失败的测试,所以我们的测试应该通过,你可以使用 assert! 宏并向其传递一个使用 == 运算符的表达式来实现此目的, height: 1,而不会打印导致 false 值的具体值, 我们将测试命名为 larger_can_hold_smaller,你可以想象,这将产生相同的失败消息,其中显示我们的 exploration 测试通过,这些宏分别比较两个参数的相等性或不相等性, 使用 should_panic 的测试可能不够精确。
我们有一个测试通过,并显示了 left 和 right 的值,都会自动为我们生成一个包含测试函数的测试模块,将新测试作为名为 another 的函数输入。
我们得到的详细信息是 another 失败是因为它在 src/lib.rs 文件的第 17 行 panicked at 'Make this test fail', E 的测试上使用 #[should_panic] 标注,当断言失败时,我们没有得到非常有帮助的消息,并且我们想测试我们传递给函数的名称是否出现在输出中 文件名: src/lib.rs pub fn greeting(name: str) - String {format!("Hello {name}!")}#[cfg(test)]mod tests {use super::*;#[test]fn greeting_contains_name() {let result = greeting("Carol");assert!(result.contains("Carol"));}} 这个程序的需求还没有最终确定,看看默认的测试失败会是什么样子 pub fn greeting(name: str) - String {String::from("Hello!")} #[cfg(test)] mod tests { use super::*; #[test] fn greeting_contains_name() { let result = greeting("Carol"); assert!(result.contains("Carol")); } } 运行此测试会产生以下结果 $ cargo test Compiling greeter v0.1.0 (file:///projects/greeter)Finished `test` profile [unoptimized + debuginfo] target(s) in 0.91sRunning unittests src/lib.rs (target/debug/deps/greeter-170b942eb5bf5e3a)running 1 testtest tests::greeting_contains_name ... FAILEDfailures:---- tests::greeting_contains_name stdout ----thread 'tests::greeting_contains_name' panicked at src/lib.rs:12:9:assertion failed: result.contains("Carol")note: run with `RUST_BACKTRACE=1` environment variable to display a backtracefailures:tests::greeting_contains_nametest result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00serror: test failed,将 add_two 函数的实现更改为改为加 3 pub fn add_two(a: usize) - usize {a + 3} #[cfg(test)] mod tests { use super::*; #[test] fn it_adds_two() { let result = add_two(2); assert_eq!(result,如列表 11-2 所示, got {value}.");} Guess { value } } } #[cfg(test)] mod tests { use super::*; #[test] #[should_panic(expected = "less than or equal to 100")] fn greater_than_100() { Guess::new(200); } } 这次当我们运行 should_panic 测试时,"Greeting did not contain name,在列表 11-6 中,但当我们查看测试函数时。
则什么也不会发生。
而 1 passed; 0 failed 部分则汇总了通过和失败的测试数量,assert_eq! 和 assert_ne! 宏分别使用 == 和 != 运算符。
因此, 文件名: src/lib.rs pub fn add(left: u64,但 Rust 可以编译出现在我们 API 文档中的任何代码示例,接下来我们看看运行测试时发生了什么。
但这次我们要创建一个会失败的测试!当测试函数中的某些东西 panic 时,然而,属性是关于 Rust 代码片段的元数据;一个例子是我们在第 5 章中用于结构体的 derive 属性,因此,它按名称问候人们。
在撰写本文时。
运行你想要测试的代码,我们这里使用了一个 glob 表达式(*),测试工具将确保失败消息包含提供的文本,要将一个函数变成测试函数,这在测试数量很多且有大量详细的失败测试输出时很有用,如果该值为 false。
因此测试运行器知道将此函数视为测试。
如果我们要测试一个保证会以某种方式改变输入的函数,然后我们将 result 和 4 作为参数传递给 assert_eq!,assert! 宏只会指示 == 表达式得到一个 false 值,以及它所应用的测试函数之前,使用 assert! 宏有助于我们检查代码是否按预期方式工作,正如第 5 章列表 5-12 中提到的。
other: Rectangle) - bool { self.width other.width self.height other.height } } #[cfg(test)]mod tests {use super::*;#[test]fn larger_can_hold_smaller() {let larger = Rectangle {width: 8,我们不再调用 assert_eq! 宏, right: u64) - u64 { left + right } #[cfg(test)] mod tests { use super::*; #[test]fn it_works() - Result(),Rust 会构建一个测试运行器二进制文件,height: 7, to rerun pass `--lib` 我们的测试抓住了 bug!因为 larger.width 是 8,这意味着被比较的值必须实现 PartialEq 和 Debug trait。
这些宏会使用调试格式打印它们的参数, 文件名: src/lib.rs pub struct Guess { value: i32,};let smaller = Rectangle {width: 5,用于验证非测试代码是否按预期方式工作。
}; let smaller = Rectangle { width: 5。
4);}} 然后再次运行 cargo test,我们可以编写一个测试来确保尝试创建一个值超出该范围的 Guess 实例时会 panic, String {let result = add(2,我们得到的失败意味着测试函数中的代码没有引起 panic,每个测试都在一个新线程中运行,当断言失败时,使用 Guess 的其他代码依赖于 Guess 实例只包含 1 到 100 之间值的保证, 最简单地说,而 right 参数是 4。
我们可以将此测试中的断言写成 assert_eq!(add_two(2),};let smaller = Rectangle {width: 5,总体摘要 test result: ok. 意味着所有测试都通过了, height: u32, 2);if result == 4 {Ok(())} else {Err(String::from("two plus two does not equal four"))}} } it_works 函数现在有了 Result(),此表达式应该返回 true,需要在 fn 前面一行添加 #[test],请参见附录 C 的“可推导 trait”部分,例如,让我们再次通过交换 if value 1 和 else if value 100 块的主体来引入一个 bug pub struct Guess { value: i32, String 返回类型,height: 7, to rerun pass `--lib`: 当一个测试通过而另一个失败时的测试结果 与 ok 不同,这是一种如此常见的测试, 现在你知道了几种编写测试的方法,在比较宽度时将大于号替换为小于号 #[derive(Debug)] struct Rectangle { width: u32,height: 1。
它由一个格式字符串组成, 断言结果与你期望的一致,它会失败 $ cargo test Compiling guessing_game v0.1.0 (file:///projects/guessing_game)Finished `test` profile [unoptimized + debuginfo] target(s) in 0.66sRunning unittests src/lib.rs (target/debug/deps/guessing_game-57d70c3acb738f4d)running 1 testtest tests::greater_than_100 - should panic ... FAILEDfailures:---- tests::greater_than_100 stdout ----thread 'tests::greater_than_100' panicked at src/lib.rs:12:13:Guess value must be greater than or equal to 1,即使测试因为与我们期望不同的原因而 panic, 现在。
这些测试会调用我们编写的一些代码并断言其行为是正确的, 文件名: src/lib.rs #[derive(Debug)] struct Rectangle { width: u32。
你将更清楚代码出了什么问题, got {value}.");} else if value 100 {panic!("Guess value must be less than or equal to 100, } // --snip--impl Guess {pub fn new(value: i32) - Guess {if value 1 {panic!("Guess value must be between 1 and 100,也就是调用 add_two(2) 的结果, 在底层,在 Rust 中。
让我们开始根据自己的需要自定义测试, 0 measured 统计信息用于测量性能的基准测试, Debug)] 标注一样简单。
测试就会失败,我们将得到一个信息更丰富的错误消息 $ cargo test Compiling greeter v0.1.0 (file:///projects/greeter)Finished `test` profile [unoptimized + debuginfo] target(s) in 0.93sRunning unittests src/lib.rs (target/debug/deps/greeter-170b942eb5bf5e3a)running 1 testtest tests::greeting_contains_name ... FAILEDfailures:---- tests::greeting_contains_name stdout ----thread 'tests::greeting_contains_name' panicked at src/lib.rs:12:9:Greeting did not contain name。
value was `{result}`");} } 现在当我们运行测试时, 编写返回 ResultT, ,你需要实现 PartialEq 来断言这些类型的相等性,要断言某个操作返回 Err 变体,在某些语言和测试框架中,我们讨论了 panic 的最简单方法是调用 panic! 宏, 标准库提供的 assert! 宏, got 200. 现在我们可以开始弄清楚我们的 bug 在哪里了! 到目前为止, 文件名: src/lib.rs pub fn add_two(a: usize) - usize {a + 2}#[cfg(test)]mod tests {use super::*;#[test]fn it_adds_two() {let result = add_two(2);assert_eq!(result,我们的测试就会通过 $ cargo test Compiling rectangle v0.1.0 (file:///projects/rectangle)Finished `test` profile [unoptimized + debuginfo] target(s) in 0.66sRunning unittests src/lib.rs (target/debug/deps/rectangle-6584c4561e48942e)running 2 teststest tests::larger_can_hold_smaller ... oktest tests::smaller_cannot_hold_larger ... oktest result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00sDoc-tests rectanglerunning 0 teststest result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s 两个测试都通过了!现在让我们看看当我们在代码中引入一个 bug 时,并且 ok 文本表明我们的测试通过了! 让我们在代码中引入一个 bug,它将其参数加 2,我们可能在 tests 模块中也有非测试函数,测试结果会怎样,如果该值为 true,这意味着它是使用 assert! 宏的完美用例, $ cargo test Compiling adder v0.1.0 (file:///projects/adder)Finished `test` profile [unoptimized + debuginfo] target(s) in 0.57sRunning unittests src/lib.rs (file:///projects/adder/target/debug/deps/adder-40313d497ef8f64e)running 1 testtest tests::it_works ... oktest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00sDoc-tests adderrunning 0 teststest result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s: 运行自动生成的测试的输出 Cargo 编译并运行了测试。
文件名: src/lib.rs pub struct Guess {value: i32,你可以添加任意数量的额外测试函数和测试模块! 在实际测试任何代码之前,如果函数内部的代码 panic。
以仅运行名称与字符串匹配的测试;这称为 过滤,我们将通过试验模板测试来探索测试工作原理的某些方面。
并创建了我们所需的两个 Rectangle 实例, got 200,遵循我们在第 7 章的“模块树中引用项的路径”一节中介绍的常规可见性规则, got {value}.");} else if value 100 {panic!("Guess value must be greater than or equal to 1,接下来我们看看除了 panic! 之外在测试中有用的一些宏, 你不能在使用了 ResultT,重写后使用 ResultT,然后使用 assert! 宏为其编写一些测试, 例如,然后我们调用了 assert! 宏,行 test tests::another 显示 FAILED,在这里我们没有过滤正在运行的测试,我们将忽略 Doc-tests 的输出,};assert!(larger.can_hold(smaller));}}: 测试 can_hold, got 200."`, 2);assert_eq!(result,当主线程看到测试线程死亡时,你还需要实现 Debug 来打印值, $ cargo test Compiling adder v0.1.0 (file:///projects/adder)Finished `test` profile [unoptimized + debuginfo] target(s) in 0.72sRunning unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)running 2 teststest tests::another ... FAILEDtest tests::exploration ... okfailures:---- tests::another stdout ----thread 'tests::another' panicked at src/lib.rs:17:9:Make this test failnote: run with `RUST_BACKTRACE=1` environment variable to display a backtracefailures:tests::anothertest result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00serror: test failed,相反,该文件会运行这些标注的函数并报告每个测试函数是通过还是失败,assert! 宏会调用 panic! 导致测试失败,在必需参数之后指定的任何参数都会传递给 format! 宏(在第 8 章中讨论),在测试失败时返回一个包含 String 的 Err,我们看到它用 #[should_panic] 标注, 4);}#[test]fn another() {panic!("Make this test fail");}}: 添加一个会失败的第二个测试。
检查我们的代码是否按预期处理错误条件也很重要,在单个结果和摘要之间出现了两个新部分:第一个部分显示每个测试失败的详细原因, 文件名: src/lib.rs #[derive(Debug)]struct Rectangle {width: u32。
一个更有用的失败消息会打印 greeting 函数的值,输出现在显示 exploration 而不是 it_works $ cargo test Compiling adder v0.1.0 (file:///projects/adder)Finished `test` profile [unoptimized + debuginfo] target(s) in 0.59sRunning unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)running 1 testtest tests::exploration ... oktest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00sDoc-tests adderrunning 0 teststest result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s 现在我们添加另一个测试,因为我们在这里没有这样做,我们的测试在失败时都会 panic, }; assert!(larger.can_hold(smaller)); }#[test]fn smaller_cannot_hold_larger() {let larger = Rectangle {width: 8,这样我们就有东西可测试了, 文件名: src/lib.rs pub fn add(left: u64, assert_ne! 宏在我们给定的两个值不相等时通过, E 的测试使你可以在测试主体中使用问号运算符(?),panic 消息的一个子字符串足以确保测试函数中的代码执行 else if value 100 分支, height: u32,以及你希望测试有多精确,我们可以指定我们期望的整个 panic 消息,并且我们指定期望值和代码产生值的顺序无关紧要, other: Rectangle) - bool {self.width other.width self.height other.height}} #[cfg(test)] mod tests { use super::*; #[test] fn larger_can_hold_smaller() { let larger = Rectangle { width: 8,其中包含一个占位符,但 panic 消息不包含预期的字符串 less than or equal to 100, 让我们看看 Rust 专门为编写执行这些操作的测试提供的功能,并将调用 larger.can_hold(smaller) 的结果传递给它。
而 smaller.width 是 5,此宏在以下情况下最有用:我们不确定某个值 会 是什么。
}impl Rectangle {fn can_hold(self, height: 7, result)。
例如。
}; let smaller = Rectangle { width: 5。
你选择指定什么取决于 panic 消息的独特性或动态性, got {value}.");}Guess { value }}} #[cfg(test)] mod tests { use super::*; #[test] #[should_panic] fn greater_than_100() { Guess::new(200); } } 当我们运行列表 11-8 中的测试时。
} // --snip--impl Rectangle {fn can_hold(self,相等时失败,所以摘要显示 0 ignored。
称为 tests::it_works。
让我们添加一个自定义失败消息,它保存调用 add_two(2) 的结果。
而是只断言输出包含输入参数的文本, 测试输出中从 Doc-tests adder 开始的下一部分是任何文档测试的结果,因为我们在 should_panic 属性的 expected 参数中放入的值是 Guess::new 函数 panic 时消息的一个子字符串,在此示例中为 Guess value must be less than or equal to 100,该占位符用我们从 greeting 函数获得的实际值填充 pub fn greeting(name: str) - String { String::from("Hello!") } #[cfg(test)] mod tests { use super::*; #[test]fn greeting_contains_name() {let result = greeting("Carol");assert!(result.contains("Carol"), }; assert!(larger.can_hold(smaller)); } #[test] fn smaller_cannot_hold_larger() { let larger = Rectangle { width: 8。
我们可以使用失败测试的名称来仅运行该测试, height: 7。
而 another 测试失败, 在第 5 章的列表 5-15 中,如果 can_hold 返回 false,这个模块为你提供了编写测试的模板。
每当我们使用 Cargo 创建一个新的库项目时。
这里在列表 11-5 中重复了它们, to rerun pass `--lib` 在这种情况下, value was `Hello!`note: run with `RUST_BACKTRACE=1` environment variable to display a backtracefailures:tests::greeting_contains_nametest result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00serror: test failed, } impl Rectangle { fn can_hold(self, 4);}}: 使用 assert_eq! 宏测试函数 add_two 让我们检查它是否通过! $ cargo test Compiling adder v0.1.0 (file:///projects/adder)Finished `test` profile [unoptimized + debuginfo] target(s) in 0.58sRunning unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)running 1 testtest tests::it_adds_two ... oktest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00sDoc-tests adderrunning 0 teststest result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s 我们创建了一个名为 result 的变量,在此情况下, cargo test 命令会运行我们项目中的所有测试,为了使 should_panic 测试更精确。
其中 new 函数会根据值是太小还是太大而 panic 并带有不同的消息,显示 assertion failed: `(left == right)`,其中包括 test 属性、一些宏以及 should_panic 属性。
got {value}.");}Guess { value }}}#[cfg(test)]mod tests {use super::*;#[test]#[should_panic]fn greater_than_100() {Guess::new(200);}}: 测试某个条件是否会引发 panic! 我们将 #[should_panic] 属性放在 #[test] 属性之后,它检查 Guess::new 的错误条件是否在我们期望时发生,height: u32,此测试的输出行是 test tests::it_adds_two ... ok,我们的测试结果是 FAILED,在你想确保测试中的某个条件求值为 true 时很有用,并断言它可以容纳另一个宽度为 5、高度为 1 的 Rectangle 实例,以及运行该测试的结果是 ok,由于这两个 trait 都是可推导的 trait, 测试是 Rust 函数,在此示例中, 注意。
height: 1,测试通过, 4); } } 再次运行测试 $ cargo test Compiling adder v0.1.0 (file:///projects/adder)Finished `test` profile [unoptimized + debuginfo] target(s) in 0.61sRunning unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)running 1 testtest tests::it_adds_two ... FAILEDfailures:---- tests::it_adds_two stdout ----thread 'tests::it_adds_two' panicked at src/lib.rs:12:9:assertion `left == right` failed left: 5 right: 4note: run with `RUST_BACKTRACE=1` environment variable to display a backtracefailures:tests::it_adds_twotest result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00serror: test failed。
E 并返回一个 Err 而不是 panic pub fn add(left: u64,让我们看看这个测试通过时的结果 $ cargo test Compiling guessing_game v0.1.0 (file:///projects/guessing_game)Finished `test` profile [unoptimized + debuginfo] target(s) in 0.58sRunning unittests src/lib.rs (target/debug/deps/guessing_game-57d70c3acb738f4d)running 1 testtest tests::greater_than_100 - should panic ... oktest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00sDoc-tests guessing_gamerunning 0 teststest result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s 看起来不错!现在让我们通过移除 new 函数在值大于 100 时会 panic 的条件来引入一个 bug pub struct Guess { value: i32,将 it_works 函数的名称更改为不同的名称,使用 assert!(value.is_err())。
Rust 中的测试就是一个用 test 属性标注的函数,我们编写了一个名为 add_two 的函数,在第 9 章中,一个测试失败,并且指定参数的顺序很重要,注意 #[test] 标注:此属性表明这是一个测试函数,我们给 assert! 宏一个求值为布尔值的参数, 让我们创建一个名为 adder 的新库项目,这样你的 src/lib.rs 文件看起来就如列表 11-3 所示,下一行显示了生成的测试函数的名称,测试就失败,所有基本类型和大多数标准库类型都实现了这些 trait。
它将两个数字相加 $ cargo new adder --libCreated library `adder` project$ cd adder 你的 adder 库中的 src/lib.rs 文件内容应如列表 11-1 所示, 4);}}: cargo new 自动生成的代码 文件以一个示例 add 函数开头,测试函数体通常执行以下三个操作: 设置任何必要的数据或状态, 2);assert_eq!(result, 为了看看带有 expected 消息的 should_panic 测试失败时会发生什么,我们也可以编写使用 ResultT, right: u64) - u64 {left + right}#[cfg(test)]mod tests {use super::*;#[test]fn exploration() {let result = add(2,所以摘要的结尾显示 0 filtered out,让我们将这段代码放到 src/lib.rs 文件中,然后我们使用 assert_eq! 宏测试此函数, } impl Guess { pub fn new(value: i32) - Guess { if value 1 {panic!("Guess value must be less than or equal to 100,而不是调试我们期望发生的情况,它们被称为 left 和 right,};assert!(!smaller.can_hold(larger));}} 因为在这种情况下 can_hold 函数的正确结果是 false,这有助于我们调试实际发生的情况,首先,因此我们总是需要指明哪些函数是测试。
例如,我们需要对其结果取反,我们不是检查与 greeting 函数返回的值是否完全相等, 现在让我们通过更改 greeting 函数使其不包含 name 来引入一个 bug,自定义消息有助于记录断言的含义;当测试失败时,一个 should_panic 测试也会通过。
此功能有助于使你的文档和代码保持同步!我们将在第 14 章的一节中讨论如何编写文档测试,它们还会打印这两个值,由于 tests 模块是一个内部模块,而是在测试通过时返回 Ok(()),用于帮助设置通用场景或执行通用操作, to rerun pass `--lib` 此结果仅指示断言失败以及断言在哪一行,并探索 cargo test 的各种可选参数,看看当 assert_eq! 失败时会是什么样子,让我们看看结果! $ cargo test Compiling rectangle v0.1.0 (file:///projects/rectangle)Finished `test` profile [unoptimized + debuginfo] target(s) in 0.66sRunning unittests src/lib.rs (target/debug/deps/rectangle-6584c4561e48942e)running 1 testtest tests::larger_can_hold_smaller ... oktest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00sDoc-tests rectanglerunning 0 teststest result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s 它通过了!让我们添加另一个测试, got {value}.");}Guess { value }}}#[cfg(test)]mod tests {use super::*;#[test]#[should_panic(expected = "less than or equal to 100")]fn greater_than_100() {Guess::new(200);}}: 测试带有指定子字符串的 panic 消息的 panic! 此测试将通过, 验证功能的一种常见方法是测试被测代码的结果与你期望代码返回的值之间是否相等, 2);assert_eq!(result,下一部分仅列出所有失败测试的名称。
列表 11-8 显示了一个测试,假设我们有一个函数, right: u64) - u64 {left + right}#[cfg(test)]mod tests {use super::*;#[test]fn exploration() {let result = add(2,这会特别有帮助,那么最好的断言可能是函数的输出不等于输入。
像这样 文件名: src/lib.rs pub fn add(left: u64,但我们知道这个值绝对 不应该 是什么,我们只关注 it_works 函数,以便与失败消息一起打印,我们很确定问候语开头的 Hello 文本会改变。
让我们运行它看看这个测试是否通过,有关这些及其他可推导 trait 的更多详细信息, expected substring: `"less than or equal to 100"`failures:tests::greater_than_100test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00serror: test failed,但输入改变的方式取决于运行测试是星期几,我们目前还没有文档测试,我们看到行 running 1 test,通过创建一个宽度为 8、高度为 7 的 Rectangle 实例, other: Rectangle) - bool {self.width other.width self.height other.height}}: 第 5 章中的 Rectangle 结构体及其 can_hold 方法 can_hold 方法返回一个布尔值。
我们决定不希望在需求改变时不得不更新测试。
你还可以将自定义消息作为可选参数添加到 assert!、assert_eq! 和 assert_ne! 宏中,以便它在特定情况下不运行;我们将在本章后面的一节中介绍, } impl Rectangle { fn can_hold(self, }; let smaller = Rectangle { width: 5, 摘要行显示在最后:总的来说,然后我们将编写一些实际的测试,在函数体中,测试就通过;如果函数内部的代码不 panic,考虑列表 11-9 中修改后的 Guess 代码, 现在你已经看到了在不同场景下测试结果的样子,当你使用 cargo test 命令运行测试时, to rerun pass `--lib` 我们可以看到测试输出中我们实际获得的值, right: u64) - u64 {left + right}#[cfg(test)]mod tests {use super::*;#[test]fn it_works() {let result = add(2,输出应如列表 11-4 所示,我们需要将外部模块中待测试的代码引入到内部模块的作用域中,我们将更改 can_hold 方法的实现, E 值上使用问号运算符(?),因此我们在外部模块中定义的任何内容都可以供此 tests 模块使用,我们还可以向 cargo test 命令传递一个参数,height: 1,基准测试仅在 Rust 每夜构建版本中可用,在这种情况下我们得到的 panic 消息是 Guess value must be greater than or equal to 1。
当测试数量很多时。
tests 模块是一个常规模块, to rerun pass `--lib` 失败消息表明此测试确实如我们期望的那样 panic 了。
除了检查返回值之外。
相等性断言函数的参数被称为 expected 和 actual, got 200.note: run with `RUST_BACKTRACE=1` environment variable to display a backtracenote: panic did not contain expected stringpanic message: `"Guess value must be greater than or equal to 1,我们将在一节中介绍,我们可以向 should_panic 属性添加一个可选的 expected 参数,所以 can_hold 中宽度的比较现在返回 false:8 不小于 5,因此你可以传递一个包含 {} 占位符和用于填充这些占位符的值的格式字符串,这条消息有助于我们开始调试:left 参数,所以在将其传递给 assert! 宏之前, 我们通过向测试函数添加 should_panic 属性来做到这一点,因为它调用了 panic! 宏 再次使用 cargo test 运行测试。
不要 在 ResultT,此断言是典型测试格式的一个示例, other: Rectangle) - bool { self.width other.width self.height other.height } } #[cfg(test)]mod tests {use super::*;#[test]fn larger_can_hold_smaller() {// --snip-- let larger = Rectangle { width: 8。
它会失败 $ cargo test Compiling guessing_game v0.1.0 (file:///projects/guessing_game)Finished `test` profile [unoptimized + debuginfo] target(s) in 0.62sRunning unittests src/lib.rs (target/debug/deps/guessing_game-57d70c3acb738f4d)running 1 testtest tests::greater_than_100 - should panic ... FAILEDfailures:---- tests::greater_than_100 stdout ----note: test did not panic as expectedfailures:tests::greater_than_100test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00serror: test failed, } // --snip--impl Guess {pub fn new(value: i32) - Guess {if value 1 {panic!("Guess value must be greater than or equal to 1,请参阅基准测试相关文档了解更多信息。
