Rust个人学习之单元测试

本文介绍了如何在Rust中使用内嵌的单元测试功能,包括如何标记测试函数,使用cfg(test)进行条件编译,以及使用assert!进行断言检查。此外,还展示了声明式宏在简化代码中的应用,如snapshot_test宏的使用。
摘要由CSDN通过智能技术生成

基础标记说明

Rust 是具备内嵌单元测试模块的。在 Rust 中,可以通过在源代码文件的顶部使用 #[test] 属性来标记一个函数作为测试函数。通常,这些测试函数位于与它们测试的源代码相同的文件中,但位于 mod tests 模块中。这是一个常用做法。
另外还有一个标记属性。#[cfg(test)] 是一个条件编译属性,它允许你编写只在测试构建中编译的代码。这对于定义只在测试时需要的辅助函数、类型或模块特别有用,从而避免在生产代码中引入不必要的开销或依赖。
创建一个测试代码:

fn im_true() -> bool {                                                                                                 true
}

fn is_false() -> bool {
    false
}

fn is_num_three() -> u32 {
    3
}

fn is_string() -> String {
    String::from("hello")
}

接下来测试函数 is_false 的返回是否为布尔值:否,需要先建立一个测试模块,然后建立一个测试函数

#[cfg(test)]                                                                                                       mod test {
    use crate::is_false;

    #[test]
    // check if is_false return false
    fn check_bool_false() {
        let f = is_false();
        assert!(!f, "is not false");
    }

    #[test]
    // check if return true
    fn check_bool_true() {
        let f = is_false();
        assert!(f, "is not true");
    }

}

上面的代码中建立了一个名字为 test 的测试模块,由于标记了#[cfg (test)]标签,所以在执行 cargo build 时是不会执行编译的,只有在执行 cargo test 时会编译执行。另外建立了两个单元测试内容:check_bool_false, check_bool_true,两个函数都用#[test]进行了标记。当执行 cargo test 时会看到两个测试项的结果。上述代码比较简单,应该是一个成功一个失败:

#cargo test
......
running 2 tests
test test::check_bool_false ... ok
test test::check_bool_true ... FAILED

failures:

---- test::check_bool_true stdout ----
thread 'test::check_bool_true' panicked at src/main.rs:37:9:
is not true
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    test::check_bool_true

test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: test failed, to rerun pass `--bin unitestlearn`

成功的单元测试会描述为 ok,而失败的会使用:FAILED 标记进行提示。同时会有标准输出以及总结哪些测试用例失败的描述。

断言

上述代码中有个关键字 assert!,这个关键字是检查给定的布尔表达式是否为真。如果为假,则测试失败。类似的关键字还有很多

关键字说明
assert!检查给定的布尔表达式是否为真。如果为假,则测试失败。
assert_eq!检查两个表达式是否相等。如果不等,则测试失败
assert_ne!检查两个表达式是否不相等。如果相等,则测试失败
Assert_debug_snapshot!用于比较当前代码的调试输出是否与先前存储的快照匹配,这有助于在重构代码时确保其行为未改变 (依赖 insta )

以下是一些案例

#[test]     ----- 布尔值检查
// check if return true
fn check_bool_true() {
    let f = im_true();
    assert!(f, "is not true");
}

#[test]     ---- 数字相等检查
fn check_equal_num() {
    assert_eq!(2,2);
}

#[test]     ----- 数字不等检查
fn check_ne_num() {
    assert_ne!(3,2);
}

#[test]     ----- 快照检查
fn check_snapshot() {
    let mut settings = insta::Settings::clone_current();
    settings.set_snapshot_path("../test/snapshot/");
    settings.bind(|| {
        let name = "helloworld";
        insta::assert_debug_snapshot!(name);
    });
}

快照检查需要多说一下,写快照检查时需要引入一个依赖,所以在 Cargo. Toml 中需要增加如下内容

[dependencies]
insta = "1.38.0"

在项目目录下创建一个 test/snapshot 目录,该目录将作为快照存储的目录,代码中采用 settings.set_snapshot_path 进行设置,settings. Bind 中设置测试流程,第一次执行时测试用例会失败,并自动在快照目录下生成一个快照文件,如上面的用例会生成一个:unitestlearn__test__check_snapshot.snap. New 的文件,生成后将该文件 new 的后缀去掉后保存就作为一个快照保存即可。

声明式宏

在 Rust 中可以通过 macro_rules!进行声明式宏的定义。能够减少重复代码的编写,简化代码,大大提高可读性和编码效率。
以下面为例:

macro_rules! snapshot_test {
($testname:ident, $txtcontent:literal) => {
    #[test]
    fn $testname() {
        let mut settings = insta::Settings::clone_current();
            settings.set_snapshot_path("../test/snapshot/");
            settings.bind(|| {
                let name = $txtcontent;
                insta::assert_debug_snapshot!(name);
            });
        }
    }  
}

snapshot_test!(a_check, "a_check");                      
snapshot_test!(b_check, "b_check");
snapshot_test!(c_check, "c_check");

类似这种及其相似的代码就可以使用宏定义的方式快速实现。Macro_rules 的格式为

macro_rules! [宏定义名称] {
	() => {}
	// 其中括号为入参,大括号为函数体
}

针对宏定义的参数类型有以下几种

类型说明
ident标识符,如变量名或函数名。
block代码块,包括 { ... } 内的所有内容。
stmt语句,如赋值或函数调用。
expr表达式,可以求值为某个值的代码片段。
pat模式,用于匹配值或解构数据。
ty类型表达式,如 intVec<T>
lifetime生命周期标注,如 'a
literal字面量,如字符串、整数或浮点数字面量。
path路径,用于引用模块、类型或值。
meta元项,如属性(attributes)。
tt令牌树(token tree),可以包含任何有效的 Rust 令牌。
item项,可以是一个函数、结构体定义等。
vis可见性修饰符,如 pubpriv
  • 13
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值