【Rust】——编写自动化测试(一)

这篇具有很好参考价值的文章主要介绍了【Rust】——编写自动化测试(一)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

🎃个人专栏:

🐬 算法设计与分析:算法设计与分析_IT闫的博客-CSDN博客

🐳Java基础:Java基础_IT闫的博客-CSDN博客

🐋c语言:c语言_IT闫的博客-CSDN博客

🐟MySQL:数据结构_IT闫的博客-CSDN博客

🐠数据结构:​​​​​​数据结构_IT闫的博客-CSDN博客

💎C++:C++_IT闫的博客-CSDN博客

🥽C51单片机:C51单片机(STC89C516)_IT闫的博客-CSDN博客

💻基于HTML5的网页设计及应用:基于HTML5的网页设计及应用_IT闫的博客-CSDN博客​​​​​​

🥏python:python_IT闫的博客-CSDN博客

🐠离散数学:离散数学_IT闫的博客-CSDN博客

​​​​​​🥽Linux:​​​​Linux_Y小夜的博客-CSDN博客

🚝Rust:Rust_Y小夜的博客-CSDN博客

欢迎收看,希望对大家有用!

目录

🎯编写和运行测试

🎃测试(函数)

🎃解剖测试函数

🎯 断言(Assert)

🎃使用assert!宏检查测试结果

🎃使用assert_eq!和assert_ne!测试相等性

🎯自定义错误信息

🎯使用should_panic检查恐慌

🎃让should_panic更加精准

🎯在测试中使用Result,e>


🎯编写和运行测试

🎃测试(函数)

Rust 中的测试函数是用来验证非测试代码是否是按照期望的方式运行的。测试函数体通常执行如下三种操作:

  1. 设置任何所需的数据或状态
  2. 运行需要测试的代码
  3. 断言其结果是我们所期望的

🎃解剖测试函数

        测试成功:

        Rust 中的测试就是一个带有 test 属性注解的函数。属性(attribute)是关于 Rust 代码片段的元数据;第五章中结构体中用到的 derive 属性就是一个例子。为了将一个函数变成测试函数,需要在 fn 行之前加上 #[test]。当使用 cargo test 命令运行测试时,Rust 会构建一个测试执行程序用来调用被标注的函数,并报告每一个测试是通过还是失败。

        每次使用 Cargo 新建一个库项目时,它会自动为我们生成一个测试模块和一个测试函数。这个模块提供了一个编写测试的模板,为此每次开始新项目时不必去查找测试函数的具体结构和语法了。因为这样当然你也可以额外增加任意多的测试函数以及测试模块。

        实际编写测试代码之前,让我们先通过尝试那些自动生成的测试模版来探索测试是如何工作的。接着,我们会写一些真正的测试,调用我们编写的代码并断言它们的行为的正确性。

$ cargo new adder --lib
     Created library `adder` project
$ cd adder
#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        let result = 2 + 2;
        assert_eq!(result, 4);
    }
}

        现在让我们暂时忽略 tests 模块和 #[cfg(test)] 注解并只关注函数本身。注意 fn 行之前的 #[test]:这个属性表明这是一个测试函数,这样测试执行者就知道将其作为测试处理。tests 模块中也可以有非测试的函数来帮助我们建立通用场景或进行常见操作,必须每次都标明哪些函数是测试。

        测试失败:

        当测试函数中出现 panic 时测试就失败了。每一个测试都在一个新线程中运行,当主线程发现测试线程异常了,就将对应测试标记为失败。

#[cfg(test)]
mod tests {
    #[test]
    fn exploration() {
        assert_eq!(2 + 2, 4);
    }

    #[test]
    fn another() {
        panic!("Make this test fail");
    }
}

🎯 断言(Assert)

🎃使用assert!宏检查测试结果

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

#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

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

🎃使用assert_eq!和assert_ne!测试相等性

        测试功能的一个常用方法是将需要测试代码的值与期望值做比较,并检查是否相等。可以通过向 assert! 宏传递一个使用 == 运算符的表达式来做到。不过这个操作实在是太常见了,以至于标准库提供了一对宏来更方便的处理这些操作 —— assert_eq! 和 assert_ne!。这两个宏分别比较两个值是相等还是不相等。当断言失败时它们也会打印出这两个值具体是什么,以便于观察测试 为什么 失败,而 assert! 只会打印出它从 == 表达式中得到了 false 值,而不是打印导致 false 的两个值。

pub fn add_two(a: i32) -> i32 {
    a + 2
}

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

    #[test]
    fn it_adds_two() {
        assert_eq!(4, add_two(2));
    }
}

        我们传递给 assert_eq! 宏的第一个参数 4 ,它等于调用 add_two(2) 的结果。测试中的这一行 test tests::it_adds_two ... ok 中 ok 表明测试通过!

        在代码中引入一个 bug 来看看使用 assert_eq! 的测试失败是什么样的。修改 add_two 函数的实现使其加 3

pub fn add_two(a: i32) -> i32 {
    a + 3
}
$ cargo test
   Compiling adder v0.1.0 (file:///projects/adder)
    Finished test [unoptimized + debuginfo] target(s) in 0.61s
     Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)

running 1 test
test tests::it_adds_two ... FAILED

failures:

---- tests::it_adds_two stdout ----
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `4`,
 right: `5`', src/lib.rs:11:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    tests::it_adds_two

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

error: test failed, to rerun pass `--lib`

        测试捕获到了 bug!it_adds_two 测试失败,错误信息告诉我们断言失败了,它告诉我们 assertion failed: `(left == right)` 以及 left 和 right 的值是什么。这个错误信息有助于我们开始调试:它说 assert_eq! 的 left 参数是 4,而 right 参数,也就是 add_two(2) 的结果,是 5。可以想象当有很多测试在运行时这些信息是多么的有用。

        需要注意的是,在一些语言和测试框架中,断言两个值相等的函数的参数被称为 expected 和 actual,而且指定参数的顺序非常重要。然而在 Rust 中,它们则叫做 left 和 right同时指定期望的值和被测试代码产生的值的顺序并不重要。这个测试中的断言也可以写成 assert_eq!(add_two(2), 4),这时失败信息仍同样是 assertion failed: `(left == right)`

   assert_ne! 宏在传递给它的两个值不相等时通过,而在相等时失败。在代码按预期运行,我们不确定值  是什么,不过能确定值绝对 不会 是什么的时候,这个宏最有用处。

   assert_eq! 和 assert_ne! 宏在底层分别使用了 == 和 !=。当断言失败时,这些宏会使用调试格式打印出其参数,这意味着被比较的值必须实现了 PartialEq 和 Debug trait。所有的基本类型和大部分标准库类型都实现了这些 trait。对于自定义的结构体和枚举,需要实现 PartialEq 才能断言它们的值是否相等。需要实现 Debug 才能在断言失败时打印它们的值。因为这两个 trait 都是派生 trait。

🎯自定义错误信息

        也可以向 assert!assert_eq! 和 assert_ne! 宏传递一个可选的失败信息参数,可以在测试失败时将自定义失败信息一同打印出来。任何在 assert! 的一个必需参数和 assert_eq! 和 assert_ne! 的两个必需参数之后指定的参数都会传递给 format! 宏,所以可以传递一个包含 {} 占位符的格式字符串和需要放入占位符的值。自定义信息有助于记录断言的意义;当测试失败时就能更好的理解代码出了什么问题。

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"));
    }
}

        这个程序的需求还没有被确定,因此问候文本开头的 Hello 文本很可能会改变。然而我们并不想在需求改变时不得不更新测试,所以相比检查 greeting 函数返回的确切值,我们将仅仅断言输出的文本中包含输入参数。

        让我们通过将 greeting 改为不包含 name 在代码中引入一个 bug 来测试失败时是怎样的:

pub fn greeting(name: &str) -> String {
    String::from("Hello!")
}

        如果仅仅告诉了我们断言失败了和失败的行号。一个更有用的失败信息应该打印出 greeting 函数的值。让我们为测试函数增加一个自定义失败信息参数:带占位符的格式字符串,以及 greeting 函数的值:

    #[test]
    fn greeting_contains_name() {
        let result = greeting("Carol");
        assert!(
            result.contains("Carol"),
            "Greeting did not contain name, value was `{}`",
            result
        );
    }

🎯使用should_panic检查恐慌

        除了检查返回值之外,检查代码是否按照期望处理错误也是很重要的。

        可以通过对函数增加另一个属性 should_panic 来实现这些。这个属性在函数中的代码 panic 时会通过,而在其中的代码没有 panic 时失败。

pub struct Guess {
    value: i32,
}

impl Guess {
    pub fn new(value: i32) -> 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更加精准

        然而 should_panic 测试结果可能会非常含糊不清。should_panic 甚至在一些不是我们期望的原因而导致 panic 时也会通过。为了使 should_panic 测试结果更精确,我们可以给 should_panic 属性增加一个可选的 expected 参数。测试工具会确保错误信息中包含其提供的文本。

// --snip--

impl Guess {
    pub fn new(value: i32) -> Guess {
        if value < 1 {
            panic!(
                "Guess value must be greater than or equal to 1, got {}.",
                value
            );
        } else if value > 100 {
            panic!(
                "Guess value must be less than or equal to 100, 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 属性中 expected 参数提供的值是 Guess::new 函数 panic 信息的子串。我们可以指定期望的整个 panic 信息,在这个例子中是 Guess value must be less than or equal to 100, got 200. 。 expected 信息的选择取决于 panic 信息有多独特或动态,和你希望测试有多准确。在这个例子中,错误信息的子字符串足以确保函数在 else if value > 100 的情况下运行。

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

        目前为止,我们编写的测试在失败时都会 panic。我们也可以使用 Result<T, E> 编写测试!这是一个延伸自示例 11-1 的测试,使用 Result<T, E> 重写,并在失败时返回 Err 而非 panic:

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

        现在 it_works 函数的返回值类型为 Result<(), String>。在函数体中,不同于调用 assert_eq! 宏,而是在测试通过时返回 Ok(()),在测试失败时返回带有 String 的 Err

        不能对这些使用 Result<T, E> 的测试使用 #[should_panic] 注解。为了断言一个操作返回 Err 成员,不要使用对 Result<T, E> 值使用问号表达式(?)。而是使用 assert!(value.is_err())文章来源地址https://www.toymoban.com/news/detail-845413.html

到了这里,关于【Rust】——编写自动化测试(一)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ChatGPT辅助编写自动化测试

    大家好,我是洋子,ChatGPT已经越来越火爆,国内百度、阿里等互联网大厂也纷纷投入大模型研究,OpenAI官网中提供了许多ChatGPT应用场景,例如SQL翻译、语言翻译、代码解释等 作为一名QA,我更关注ChatGPT生成的自动化测试脚本质量如何,借助ChatGPT能否提升自动化测试编写效率

    2024年02月10日
    浏览(19)
  • 自动化测试脚本编写(超详细)

    🍅 视频学习: 文末有免费的配套视频可观看 🍅  关注公众号【互联网杂货铺】,回复 1  ,免费获取软件测试全套资料,资料在手,涨薪更快 什么是自动化测试? 自动化测试是验证和验证软件是否满足所有用户需求,并使用自动化工具按预期运行。它检查在产品开发阶段

    2024年04月26日
    浏览(14)
  • python+pytest接口自动化(12)-自动化用例编写思路 (使用pytest编写一个测试脚本)

    经过之前的学习铺垫,我们尝试着利用pytest框架编写一条接口自动化测试用例,来厘清接口自动化用例编写的思路。 我们在百度搜索 天气查询 ,会出现如下图所示结果: 接下来,我们以该天气查询接口为例,编写接口测试用例脚本。 针对某个功能做接口测试,首先我们需

    2024年02月04日
    浏览(21)
  • Selenium如何用于编写自动化测试脚本?

    Selenium如何用于编写自动化测试脚本?它提供了许多测试工具和API,可以与浏览器交互,模拟用户操作,检查网页的各个方面。下面是一些步骤,可以帮助你编写Selenium自动化测试脚本。 1、安装Selenium库和浏览器驱动程序 首先,你需要安装Selenium库和浏览器驱动程序,例如C

    2024年02月09日
    浏览(18)
  • 自动化用例编写思路 (使用pytest编写一个测试脚本)

    目录 一,明确测试对象 二,编写测试用例 构造请求数据 封装测试代码 断言设置 三,执行脚本获取测试结果 四,总结 经过之前的学习铺垫,我们尝试着利用pytest框架编写一条接口自动化测试用例,来厘清接口自动化用例编写的思路。 我们在百度搜索天气查询,会出现如下

    2024年02月16日
    浏览(20)
  • 如何提升编写自动化测试case的效率?

    提升编写自动化测试case的效率需要考虑以下几个方面: 1. 待测应用程序的测试计划 首先,需要清晰地了解待测应用程序的测试计划,具体包括哪些功能需要测试、如何测试以及测试的优先级等。这有助于更好地规划测试用例的编写和执行。 如果你想学习自动化测试,我这边

    2024年02月11日
    浏览(25)
  • 编写http接口api及接口自动化测试

    片言 此文中代码都是笔者工作中源码,所以不会很完整,主要摘常见场景的api片段用以举例说明 另:此文主要针对自动化测试人员,尤其有python基础阅读更佳。 笔者使用 python3.6 + postgresql10 + flask 0.12 的环境 场景介绍  我们要实现后台管理中的 用户管理 功能,实现对用户的增

    2024年04月16日
    浏览(20)
  • 用selenium IDE手工编写自动化测试脚本

    目录 一、打开selenium IDE插件  二、输入脚本 1.元素定位的验证  console验证Xpath定位 2.元素定位的验证   console验证css定位 selenium IDE属于玩具型自动化测试脚本编写工具,它简单、易上手,对于web自动化测试入门来说,是个非常不错的选择。 使用seleniium IDE插件录制脚本非常容

    2023年04月27日
    浏览(22)
  • AI测试 | 我试着让ChatGPT辅助编写自动化测试,结果……

    作者的话: ChatGPT最近备受关注,官网中提供了许多ChatGPT应用场景,例如SQL翻译、语言翻译、代码解释等。作为一名QA,我更关注 ChatGPT生成的自动化测试脚本质量如何,借助ChatGPT能否提升自动化测试编写效率。当提到自动化测试时,我们通常将其分为单元测试、接口测试和

    2024年02月06日
    浏览(21)
  • web自动化测试入门篇07 ——— 用例编写技巧

        😏 作者简介:博主是一位测试管理者,同时也是一名对外企业兼职讲师。 📡 主页地址:【Austin_zhai】 🙆 目的与景愿:旨在于能帮助更多的测试行业人员提升软硬技能,分享行业相关最新信息。 💎 声明:博主日常工作较为繁忙,文章会不定期更新,各类行业或职场问

    2023年04月25日
    浏览(24)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包