Rust从入门到实战系列一百零九:使用 assert! 宏来检查结果

assert! 宏由标准库提供,在希望确保测试中一些条件为 true 时非常有用。需要向 assert! 宏提供一个求值为布尔值的参数。如果值是 true,assert! 什么也不做,同时测试会通过。如果值为 false,assert! 调用 panic! 宏,这会导致测试失败。assert! 宏帮助我们检查代码是否以期望的方式运行。
将他们放进 src∕lib.rs 并使用 assert! 宏编写一些测试。

struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
}

can_hold 方法返回一个布尔值,这意味着它完美符合 assert! 宏的使用场景。在示例 11-6 中,让我们编写一个 can_hold 方法的测试来作为练习,这里创建一个长为 8 宽为 7 的 Rectangle 实例,并假设它可以放得下另一个长为 5 宽为 1 的 Rectangle 实例:

# struct Rectangle {
# width: u32,
# height: u32,
# }
#
# impl Rectangle {
# fn can_hold(&self, 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,
height: 7,
};
let smaller = Rectangle {
width: 5,
height: 1,
};
assert!(larger.can_hold(&smaller));
}
}

注意在 tests 模块中新增加了一行:use super:😗;。tests 是一个普通的模块,它遵循第七章 ” 路径用于引用模块树中的项” 部分介绍的可见性规则。因为这是一个内部模块,要测试外部模块中的代码,需要将其引入到内部模块的作用域中。这里选择使用 glob 全局导入,以便在 tests 模块中使用所有在外部模块定义的内容。
我们将测试命名为 larger_can_hold_smaller,并创建所需的两个 Rectangle 实例。接着调用 assert! 宏并传递larger.can_hold(&smaller) 调用的结果作为参数。这个表达式预期会返回 true,所以测试应该通过。让我们拭目以待!

Compiling rectangle v0.1.0 (file:///projects/rectangle)
Finished test [unoptimized + debuginfo] target(s) in 0.66s
Running unittests (target/debug/deps/rectangle-6584c4561e48942e)
running 1 test
test tests::larger_can_hold_smaller ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests rectangle
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

它确实通过了!再来增加另一个测试,这一回断言一个更小的矩形不能放下一个更大的矩形:

# struct Rectangle {
# width: u32,
# height: u32,
# }
#
# impl Rectangle {
# fn can_hold(&self, 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,
# height: 7,
# };
# let smaller = Rectangle {
# width: 5,
# height: 1,
# };
#
# assert!(larger.can_hold(&smaller));
}
#[test]
fn smaller_cannot_hold_larger() {
let larger = Rectangle {
width: 8,
height: 7,
};
let smaller = Rectangle {
width: 5,
height: 1,
};
assert!(!smaller.can_hold(&larger));
}
}

因为这里 can_hold 函数的正确结果是 false ,我们需要将这个结果取反后传递给 assert! 宏。因此can_hold 返回 false 时测试就会通过:

Compiling rectangle v0.1.0 (file:///projects/rectangle)
Finished test [unoptimized + debuginfo] target(s) in 0.66s
Running unittests (target/debug/deps/rectangle-6584c4561e48942e)
running 2 tests
test tests::larger_can_hold_smaller ... ok
test tests::smaller_cannot_hold_larger ... ok
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests rectangle
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

两个通过的测试!现在让我们看看如果引入一个 bug 的话测试结果会发生什么。将 can_hold 方法中比较长度时本应使用大于号的地方改成小于号:

# struct Rectangle {
# width: u32,
# height: u32,
# }
#
// --snip--
impl Rectangle {
fn can_hold(&self, 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,
# height: 7,
# };
# let smaller = Rectangle {
# width: 5,
# height: 1,
# };
#
# assert!(larger.can_hold(&smaller));
# }
#
# #[test]
# fn smaller_cannot_hold_larger() {
# let larger = Rectangle {
# width: 8,
# height: 7,
# };
# let smaller = Rectangle {
# width: 5,
# height: 1,
# };
#
# assert!(!smaller.can_hold(&larger));
# }
# }

现在运行测试会产生:

Compiling rectangle v0.1.0 (file:///projects/rectangle)
Finished test [unoptimized + debuginfo] target(s) in 0.66s
Running unittests (target/debug/deps/rectangle-6584c4561e48942e)
running 2 tests
test tests::larger_can_hold_smaller ... FAILED
test tests::smaller_cannot_hold_larger ... ok
failures:
---- tests::larger_can_hold_smaller stdout ----
thread 'main' panicked at 'assertion failed: larger.can_hold(&smaller)', src/lib.rs:28:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
failures:
tests::larger_can_hold_smaller
test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
error: test failed, to rerun pass '--lib'

我们的测试捕获了 bug!因为 larger.length 是 8 而 smaller.length 是 5,can_hold 中的长度比较现在因为 8 不小于 5 而返回 false。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值