【RUST学习】测试

测试

用于验证非测试代码的功能是否与预期一致的函数

测试函数体的三个操作

1.准备数据/状态
2.运行被测试的代码
3.断言(Assert)结果

解剖测试函数

测试函数需要使用test属性(Attribute)进行标注.

Attribute就是一段Rust代码的元数据
在函数上加#[test],可以把函数变成测试函数

运行测试

使用cargo test命令运行所有测试,此时rust会构建一个test runner可执行文件,他会运行标注了test的函数,并报告其是否运行成功

当使用cargo创建library项目的时候,会生成一个test module,里面有一个test函数,你可以添加任意数量的test module

输入:

cargo new adder --lib    //创建一个lib库项目

而后会得到一个library文件,内容如下:

pub fn add(left: usize, right: usize) -> usize {
    left + right
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]  //由此判断这是一个测试函数
    fn it_works() {
        let result = add(2, 2);
        assert_eq!(result, 4);
    }
}

测试失败

测试函数中出现panic
每个测试运行在一个新的线程
当主线程看见某个测试挂掉了,那么这个测试标记为失败

Assert断言

使用assert!宏检查结果

assert!宏来自于标准库,用来确定某个状态是否为ture

true代表测试通过。
false代表测试失败,调用panic!。

example:

#[derive(Debug)]
pub struct Rctangle{ //创建结构体
    lenth:u32,
    width:u32,
}

impl Rctangle { //添加结构体内的方法
    pub fn can_hold(&self, other:&Rctangle) -> bool{
        self.lenth > other.lenth && self.width > other.width
    }
}

#[cfg(test)] 
mod tests {
    use super::*;

    #[test]  //表明这是一个测试模块
    fn large_can_hold_small() {
        let large = Rctangle{
            lenth: 8,
            width: 9
        };
        let small = Rctangle{
            lenth:6,
            width:8,
        };//assert!用于判断是否为true,所以can_hold用作测试的时候返回的是一个bool类型	
        assert!(large.can_hold(&small)) //调用了large对象的can_hold()方法,并传入small对象的引用

    }
}
使用assert_eq!和asser_ne!测试相等性

都来自标准库
都是判断两个函数是否相等或者不等
实际上,它们使用的就是==或者!=运算符
断言失败则自动打印出两个参数的值

添加自定义错误消息

可以向assert!、assert_eq!、assert_ne!添加可选的自定义消息
—这些自定义消息和失败消息都会打印出来
—assert!:第一参数必填,自定义消息作为第二个参数。
—assert_eq!和assert_ne!: 前两个参数必填,自定义消息作为第三个参数。
—自定义消息参数会被传递给format!宏,可以使用{}占位符

example:

use std::fmt::format;

pub fn greeting(name: &str) -> String{
    format!("hello {}!",name)
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn greetings_contain_name(){
        let result = greeting("carol");
        assert!(
            result.contains("Carol"),
            "Greeting didn't contain name,value was '{}'",
            result
        );
    }
}

用should_panic检查恐慌

验证错误处理的情况

测试除了验证代码的返回值是否正确,还需要验证代码是否预期的处理了发生的错误
可验证代码在特定情况下是否发生了panic
should_panic属性(attribute):
—函数panic:测试通过
—函数没有panic:测试失败

example:

pub struct Guess{
    value:u32,
}

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

        Guess{value}
    }
}

#[cfg(test)]
mod tests{
    use super::*;

    #[test]
    #[should_panic]

    fn greater_than_100 () {
        Guess::new(100)
    }
}

让should_panic更加精确

pub struct Guess{
    value:u32,
}

impl Guess {
    pub fn new(value:u32)->Guess {
        if value < 1 {
            panic!("Guess value must greater than or equal to 1 ,got {}.",value)
        }else if value > 100 {
            panic!("Guess value must less than or equal than 100, got {}.",value)
        }

        Guess{value}
    }
}

#[cfg(test)]
mod tests{
    use super::*;

    #[test]
    #[should_panic(expected="Guess value must less than or equal than 100")]

    fn greater_than_100 () {
        Guess::new(100);
    }
}

在测试中使用Result<T,E>

无需panic,可使用Result<T,E>作为返回类型的编写测试
—返回OK:测试通过
—返回Err:测试失败
注意:不要在使用Result编写的测试上标注#[should_panic],因为这种测试不会发生恐慌

example:

#[cfg(test)]
mod tests {
    #[test]

    fn it_woks() ->Result<(),String>{
        if 2+2 ==4 {
            Ok(())
        }else {
            Err(String::from("two plus two does not equal four"))
        }
    }
}

控制测试如何运行

我们可以通过添加命令行参数来改变cargo test 的行为
默认行为:
—并行测试
—所有测试
—捕获(不显示)所有输出,使得读取和测试结果相关的输出更加容易
命令行参数:
—针对cargo test的参数,紧跟在cargo test之后
—针对测试可执行程序:放在–之后

并行/连续运行测试

并行

运行多个测试默认使用多个线程来并行运行
—运行快

确保测试之间不会相互依赖且不依赖于某个共享状态(环境、目录、环境变量等)

– test-threads参数

传递给二进制文件
不想以并行方式运行测试,或者想对线程进行细粒度控制
可以使用-- test-threads参数后面跟着线程的数量

显示函数输出

默认,如果测试通过,Rust的test库会捕获所有打印到标准输出的内容(println!输出的内容并不会在终端中看到)
如果想要在成功的测试中看到打印的内容则需要 --show-output

按名称运行测试

选择运行的测试:将测试的名字作为cargo test的参数
单个测试直接在cargo test后面添加函数名,如果运行多个则需要在cargo test后面添加测试名的一部分从而运行测试的部分模块

忽略测试

ignore属性()

#[cfg(test)]
mod tests {
    #[test]
    fn it_woks() ->Result<(),String>{
        if 2+2 ==4 {
            Ok(())
        }else {
            Err(String::from("two plus two does not equal four"))
        }
    }

    #[test]
    #[ignore]    //这个标记下的测试在运行cargo test时不会进行测试运行

    fn expensive_test() {
        assert_eq!(5,1+1+1+1+1)
    }
}

如果需要运行被忽略的测试
输入以下代码

cargo test -- --ignored

测试的分类

单元测试:

目的:将一小段代码隔离出来从而判断功能是否符合预期
小、专注
一次对一个模块进行隔离的测试
可测试private接口
注意:rust允许测试私有函数
example:

pub fn add_two(a:i32) ->i32{
    internal_adder(a, 2)
}//最后的所有权归到了add_twoz()中

fn internal_adder(a:i32, b:i32) ->i32{
    a + b
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]

    fn it_works() {
        assert_eq!(4,internal_adder(2, 2))
    }
}
集成测试

目的:测试被测试库的多个部分能否正确的一起工作
在库的外部。和其他外部代码一样使用你的代码
只能使用public接口
可能在测试中使用到多个模块

创建集成测试的步骤:
1.首先需要创建一个tests目录,tests目录下每个测试文件都是一个单独的crate
——需要将被测试库导入
——这些文件不会共享行为
2.无需标记#[cfg(test)],tests目录被特殊对待
——只有cargo test,才会编译tests下的文件

运行指定的集成测试
1、运行一个特定的集成测试:cargo test 函数名
2、运行某个测试文件内的所有测试:cargo test --test 文件名

针对binary crate的集成测试

如果项目是binary crate,只含有src/main.rs没有src/lib.rs:
—不能在tests目录下创建集成测试
—即使有测试也无法把main.rs导入作用域
只有library crate才能暴露给其他crate用
binary crate意味着独立运行

  • 18
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值