Rust编程-编写自动化测试

编写单元测试步骤:

  1. 准备所需的数据

  2. 调用需要测试的代码

  3. 断言运行结果与我们所期望的一致

Rust的test元数据:

#[cfg(test)]是一个属性宏(attribute macro)。用于控制特定的代码段仅在测试环境中编译。

#[cfg(test)]
mod tests {
    // 测试函数
    #[test]
    fn my_test() {
        // 测试代码
    }
}

**#[cfg(test)]**的作用 是确保tests模块内的代码仅在执行cargo test命令时被编译和运行。

cfg还可以用于更复杂的条件编译场景:

#[cfg(target_os = "linux")]
fn os_specific_function() {
    // Linux-specific code
}

#[cfg(target_os = "windows")]
fn os_specific_function() {
    // Windows-specific code
}

cfg指定目标操作系统,选择性的编译代码

#[test] 关键字:表示是测试函数

测试函数:将#[test] 添加到fn关键字的上一行就将函数转变为测试函数

单元测试执行命令:

cargo test命令来运行测试

这个命令会构建并执行一个用于测试的**可执行文件,**该文件在执行过程中会逐一调用所有标注了test属性的函数,并生成统计测试运行成功或失败的报告。

Rust能够编译在API文档中出现的任何代码示例

assert_eq! 宏

rust 复制代码
 assert_eq!(2 + 2, 4);

用于断言两个值相等。如果不相当则panic,单元测试失败

assert_ne!宏:

断言两个值不相等,单元测试则通过

确定它绝不可能 是某些值的时候的使用

总结:

assert_eq! 和assert_ne! 宏分别使用了==和!=运算符来进行判断,并在断言失败时使用调试输出格式({:?})将参数值打印出来,它们的参数必须同时实现PartialEq和Debug这两个trait

这两个trait都是可派生trait,可以通过在自定义的结构体或枚举的定义的上方添加#[derive(PartialEq, Debug)]标注来自动实现这两个trait。

assert! 宏检查结果

assert! 宏由标准库提供,它可以确保测试中某些条件的值为true

assert! 宏可以检查代码是否按照我们预期的方式运行。

assert! 宏接收一个能够被计算为布尔类型的值作为参数:当这个值为true时,assert! 宏正常通过测试。当值为false时,assert! 宏就会调用panic! 宏,进而导致测试失败。

assert!宏传入两个值==,则等价于assert_eq!

添加自定义的错误提示信息

任何在assert!、assert_eq! 或assert_ne! 的必要参数之后出现的参数都会一起被传递给format! 宏:

rust 复制代码
assert!(
        result.contains("Carol"),
        "Greeting did not contain name, value was `{}`", result
)

其中,第二个参数会被传给format!宏

should_panic检查panic

should_panic:编写一个测试来检查使用了非法值是否会如期发生panic

新属性:should_panic。标记了这个属性的测试函数会在代码发生panic时顺利通过,而在代码不发生panic时执行失败。

将#[should_panic]属性放在了#[test]属性之后、对应的测试函数之前

rust 复制代码
pub struct Guess{
    value:u32,
}


impl Guess{
    pub fn new(value:u32) ->  Guess{
        if value <1 || value > 100{
            panic!("Guess value must be between 1 and 100,got {}",value);
        }
        Guess{
            value
        }
    }
}

#[cfg(test)]

mod tests{
    use super::*;

    #[test]
    #[should_panic]
    fn greater_than_100(){
        Guess::new(200);
    }
}

should_panic 属性中添加**可选参数expected,**让should_panic测试更加精确一些

rust 复制代码
#[should_panic(expected = "Guess value must be less than or equal to 100")]
    fn greater_than_100() {

测试某个条件会触发带有特定错误提示信息的panic!

使用Result<T, E>编写测试:

rust 复制代码
#[cfg(test)]
mod tests{
    use super::*;
    #[test]
    fn it_works() -> Result<(),String>{
        if 2+2 == 4{
            Ok(())
        }else {
            Err(String::from("two plus two does not equal for"))
        }
    }
}

不要在使用Result<T, E>编写的测试上标注#[should_panic]

编写返回Result<T, E>的测试,就可以在测试函数体中使用问号运算符了。

在测试运行失败时,我们应当直接返回一个Err值

控制测试的运行方式:

cargo test同样会在测试模式下编译代码,并运行生成的测试二进制文件

cargo test生成的二进制文件默认会并行执行所有的测试

可以为cargo test指定命令行参数,也可以为生成的测试二进制文件指定参数:

分隔符--

cargo test --help会显示出cargo test的可用参数

运行cargo test -- --help则会显示出所有可以用在--之后的参数

并行或串行地进行测试

Rust会默认使用多线程来并行执行

开发者必须保证测试之间不会互相依赖,或者依赖到同一个共享的状态或环境上

cargo test -- --test-threads=1

指定测试执行的线程数

显示函数输出

默认只有在测试失败时,我们才能在错误提示信息的上方观察到打印至标准输出(println!)中的内容。

cargo test -- --nocapture

在测试通过时也将值打印出来

只运行部分特定名称的测试

cargo test one_hundred

给cargo test传递一个测试函数的名称来单独运行该测试

cargo test add

指定测试名称的一部分来作为参数,任何匹配这一名称的测试都会得到执行

通过显式指定来忽略某些测试

#[ignore]

添加#[ignore]属性宏

cargo test -- --ignored

通过--ignored参数单独运行添加了#[ignore]属性宏的测试函数

测试的组织结构:

测试分类:单元测试(unit test)和集成测试(integration test)

单元测试小而专注,每次只单独测试一个模块或私有接口

集成测试完全位于代码库之外,访问公共接口,并且在一次测试中可能会联用多个模块。

标注#[cfg(test)]可以让Rust只在执行cargo test命令时编译和运行该部分测试代码,而在执行cargo build时剔除它们。

不需要对集成测试标注#[cfg(test)],因为集成测试 本身就放置在独立的目录

单元测试:

一般将单元测试与需要测试的代码存放在src 目录下的同一文件中。同时也约定俗成地在每个源代码文件中都新建一个tests模块来存放测试函数,并使用cfg(test)对该模块进行标注。

集成测试:

集成测试是完全位于代码库之外。意味着你只能调用对外公开提供的那部分接口。集成测试的目的在于验证库的不同部分能否协同起来正常工作

集成测试首先需要建立一个**tests 目录:项目根目录下创建tests 文件夹,它和src 文件夹并列。**Cargo会自动在这个目录下寻找集成测试文件。我们可以在这个目录下创建任意多个测试文件,Cargo在编译时会将每个文件都处理为一个独立的包。

成测试需要在代码顶部添加语句**use 包名:**因为tests 目录下的每一个文件都是一个独立的包,所以我们需要将目标库导入每一个测试包中

cargo test 输出中出现了单元测试、集成测试和文档测试这3部分

cargo test --test integration_test

cargo test时使用--test并指定文件名,可以单独运行某个特定集成测试文件 下的所有测试函数

创建tests/common/mod.rs 将功能函数放在该文件中,这是可以被Rust理解的命名规范, rust不会将common模块看成集成测试文件了**。原因:tests 子目录中的文件不会被视作单独的包进行
编译,更不会在测试输出中拥有自己的区域。**

mod common; 声明了需要引用的模块

二进制包的集成测试

只有代码包(librarycrate)才可以将函数暴露给其他包来调用,而二进制包只被用于独立执行

相关推荐
Lizhihao_5 分钟前
JAVA-队列
java·开发语言
远望清一色23 分钟前
基于MATLAB边缘检测博文
开发语言·算法·matlab
何曾参静谧31 分钟前
「Py」Python基础篇 之 Python都可以做哪些自动化?
开发语言·python·自动化
Prejudices35 分钟前
C++如何调用Python脚本
开发语言·c++·python
我狠狠地刷刷刷刷刷1 小时前
中文分词模拟器
开发语言·python·算法
wyh要好好学习1 小时前
C# WPF 记录DataGrid的表头顺序,下次打开界面时应用到表格中
开发语言·c#·wpf
AitTech1 小时前
C#实现:电脑系统信息的全面获取与监控
开发语言·c#
qing_0406031 小时前
C++——多态
开发语言·c++·多态
孙同学_1 小时前
【C++】—掌握STL vector 类:“Vector简介:动态数组的高效应用”
开发语言·c++
froginwe111 小时前
XML 编辑器:功能、选择与使用技巧
开发语言