14.编写自动化测试(上)

标题

  • 一、如何编写测试
    • 1.1 一些概念
    • 1.2 测试函数剖析
    • 1.3 使用assert!宏检查结果
    • 1.4 使用assert_eq!和assert_ne!宏来测试相等
      • 1) assert_eq!
      • 2) assert_ne!
    • 1.5 使用 should_panic 检查 panic
  • 二、将 Result<T, E> 用于测试

一、如何编写测试

1.1 一些概念

Rust 中的测试函数体通常执行如下三种操作:

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

Rust提供的专门用来编写测试的功能:

  • test属性;
  • 一些宏;
  • should_panic属性;

1.2 测试函数剖析

  • Rust中的测试就是一个在fn行之间加上#[test]属性标注的函数;
  • cargo test命令执行时,会运行被标记了#[test]的函数,并报告是否运行通过;

创建新的库项目

cargo new adder --lib
  • 源码只有src/lib.rs文件,其内容如下
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);}
}
  • fn函数之前的#[test]表明这是一个测试函数;
  • tests是一个普通的内部模块,要测试外部的中的add函数,因此要用use引入;
  • 函数体通过使用assert_eq!宏来断言2加2等于4,这是测试用例的典型格式;
  • 使用cargo test运行测试用例;
    在这里插入图片描述
  • 结果显示:1 passed; 0 failed;…… 说明所有测试都通过了;
  • tests::it_works中的it_works是测试函数的名字;
  • ignored表示忽略的测试用例,filtered out表示过滤需要运行的测试,measured是针对性能测试的(目前只能用于Rust开发版(nightly Rust,详阅https://doc.rust-lang.org/unstable-book/library-features/test.html);
  • Doc-tests adder 是所有文档测试的结果;

再加一个失败的测试项

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

运行时会提示it_works运行成功而another运行失败
在这里插入图片描述

1.3 使用assert!宏检查结果

  • assert!宏由标准库提供,在希望确保测试中一些条件为true时非常有用;
  • 需要向assert!宏提供一个求值为布尔值的参数;
  • 如果值是true,则什么也不做,同时测试通过;
  • 如果值是false,assert!宏调用panic!宏,同时测试失败;
  • assert!最后附上错误提示字符串,以便更好定位 (可选)

为前面写的Rectangle结构体和一个can_hold添加一个测试用例,看看8*7的实例能否放下5*1的实例;

#[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}
}#[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), "运行失败!");}
}

测试结果为通过
在这里插入图片描述

1.4 使用assert_eq!和assert_ne!宏来测试相等

  • 标准库提供assert_eq!assert_ne!宏比较相等或不相等;
  • 当断言失败时也会打印出这两个值具体是什么,以便于观察测试为什么失败;
  • 依然可以自定义断言失败时候的输出信息;
  • 宏参数中的左右两个值的顺序并不重要;

1) assert_eq!

fn add_two(a: i32) -> i32{a + 2
}#[cfg(test)]
mod tests {use super::*;#[test]fn it_adds_two() {let result = add_two(2);assert_eq!(4, result);}#[test]fn it_adds_two2() {let result = add_two(1);assert_eq!(4, result, "4 is not equal {}.", result);}
}

输出结果
在这里插入图片描述

  • it_add_two运行通过;
  • it_adds_two2运行失败,左值为4右值为3,因此不相等,断言失败;
  • 输出了我们自己定义的错误提示信息:4 is not equal 3

2) assert_ne!

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

TIPS:

  • 如果一个函数保证会以某种方式改变其输出,不过这种改变方式是由运行测试时是星期几来决定的,这时最好的断言可能就是函数的输出不等于其输入。
  • assert_eq! 和 assert_ne! 宏在底层分别使用了 == 和 !=。
  • 当断言失败时,这些宏会使用调试格式打印出其参数,这意味着被比较的值必需实现了PartialEq 和 Debug trait
  • 对于自定义的结构体和枚举,需要实现PartialEq才能断言他们的值是否相等。
  • 需要实现Debug才能在断言失败时打印他们的值。
  • 由于这两个 trait 都是派生 trait,因此通常可以直接在结构体或枚举上添加#[derive(PartialEq, Debug)]标注。
  • 更多关于这些和其他派生 trait 的详细信息请参阅 这里 ;

1.5 使用 should_panic 检查 panic

  • 可以对测试程序添加#[should_panic]属性;
  • 即使满足条件也不会触发程序中的panic!宏;
fn add_two(a: i32) -> i32{if a < 0 {panic!("Par a must larger 0 but a is {}", a);}a + 2
}#[cfg(test)]
mod tests {use super::*;#[test]#[should_panic]fn it_adds() {let result = add_two(-5);assert_eq!(4, result);}
}
  • 当add_two传入的值小于0时会触发panic!宏;
  • 但是给it_adds额外添加一个#[should_panic]属性时依然会通过测试;

缺点

  • 添加should_panic属性之后的测试结果只是告诉我们代码产生了 panic;
  • should_panic在一些不是我们期望的原因而导致panic时也会通过 ;
  • 可以添加expected参数来关注我们所期待导致的panic;
fn add_two(a: i32) -> i32{if a < 0 {panic!("Par a must larger than 0 but a is {}", a);}else if a > 100{panic!("Par a must less than 100 but a is {}", a);}a + 2
}#[cfg(test)]
mod tests {use super::*;#[test]#[should_panic(expected = "Par a must larger than 0 but a is")]fn it_adds() {let result = add_two(101);assert_eq!(4, result);}
}
  • 为it_adds添加的[should_panic(expected = "Par a must larger than 0 but a is")]属性代表只有当panic!宏提示的字符串不包含Par a must larger than 0 but a is时会出错。
  • 传给add_two函数的值是101,因此走的是else if分支,panic!宏提示的错误是Par a must less than 100 but a is,这不包含expected中的子串,因此会报错。

在这里插入图片描述

二、将 Result<T, E> 用于测试

#[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>
  • 测试通过时返回 Ok(()),在测试失败时返回带有 String 的 Err;
  • 这样编写测试来返回 Result<T, E> 就可以在函数体中使用问号运算符,如此可以方便地编写测试,如果其中的任何操作返回 Err 值,则测试将失败;
  • 不能使用#[should_panic],要断言操作返回 Err 值,需要使用assert!(value.is_err())

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/28689.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Windows defender bypass | 免杀

官方文档 在制作免杀的过程中,翻找 Windows 官方对 Windows Defender 的介绍,发现有这样一个目录:Configure Microsoft Defender Antivirus exclusions on Windows Server(在 Windows server 中配置defender排除项)。 https://docs.microsoft.com/en-us/microsoft-365/se…

N32G45XVL-STB之移植LVGL(8.4.0)

目录 概述 1 系统软硬件 1.1 软件版本信息 1.2 ST7796-LCD 1.3 MCU IO与LCD PIN对应关系 2 认识LVGL 2.1 LVGL官网 2.2 下载V8.4.0 3 移植LVGL 3.1 硬件驱动实现 3.2 添加LVGL库文件 3.3 移植和硬件相关的代码 3.3.1 驱动接口相关文件介绍 3.3.2 重新接口函数 3…

视频合成渲染服务解决方案,数字人+PPT+视频云剪辑

在金融理财领域&#xff0c;一个生动、直观、专业的视频&#xff0c;往往能够在海量信息中脱颖而出&#xff0c;帮助客户更好地理解产品、把握市场动态。然而&#xff0c;传统的视频制作方式往往周期长、成本高、难以适应快速变化的市场需求。 美摄科技&#xff0c;作为行业领…

XZ后门故事:初始分析

2024年3月29日&#xff0c;Openwall OSS安全邮件列表上的一条消息“炸醒”了整个信息安全、开源和Linux社区&#xff1a;XZ出现了一个CVSS评分10.0的恶意后门。 这个后门库的特殊危险在于OpenSSH服务器进程sshd使用它。在多个基于systemd的发行版上&#xff08;包括Ubuntu、De…

从根源解决问题:构建体系化BOM管理机制与解决方案

BOM&#xff08;物料清单&#xff09;是设计与生产间的纽带&#xff0c;其准确及时对企业的竞争力至关重要。然而&#xff0c;维护BOM数据时&#xff0c;常遇到录入错误、信息孤岛及跨部门沟通障碍等难题&#xff0c;直接影响生产效率和成本。为此&#xff0c;道合顺将探讨确保…

Hi3861 OpenHarmony嵌入式应用入门--点灯

本篇实现对gpio的控制&#xff0c;通过控制输出进行gpio的点灯操作。 硬件 我们来操作IO2&#xff0c;控制绿色的灯。 软件 GPIO API API名称 说明 hi_u32 hi_gpio_deinit(hi_void); GPIO模块初始化 hi_u32 hi_io_set_pull(hi_io_name id, hi_io_pull val); 设置某个IO…

如何使用xurlfind3r查找目标域名的已知URL地址

关于xurlfind3r xurlfind3r是一款功能强大的URL地址查询工具&#xff0c;该工具本质上是一个CLI命令行工具&#xff0c;可以帮助广大研究人员从多种在线源来查询目标域名的已知URL地址。 功能介绍 1、从被动在线源获取URL地址以实现最大数量结果获取&#xff1b; 2、支持从Way…

遗传算法浅理解

1. 什么是遗传算法&#xff1f; ​ 遗传算法&#xff0c;又称为 Genetic algorithm(GA)Genetic algorithm(GA)。其主要思想就是模拟生物的遗传与变异。它的用途非常广泛&#xff0c;可以用于加速某些求最大或者最小值的算法&#xff08;换句话说就是加速算法收敛&#xff0c;最…

移动端专业视频剪辑解决方案,深度编辑,专业级体验

面对众多繁杂的移动端视频编辑软件&#xff0c;如何挑选一款既高效又专业的解决方案&#xff0c;成为众多企业关注的焦点。美摄科技凭借其卓越的技术实力&#xff0c;推出了面向企业的移动端专业视频剪辑解决方案&#xff0c;助力企业轻松打造高质量视频内容。 一、深度编辑&a…

OAuth 2.0:现代应用程序的授权标准

前言 随着互联网和移动应用的发展&#xff0c;应用程序之间的交互变得越来越普遍。用户希望通过单一的身份认证在多个平台上无缝体验&#xff0c;这就要求不同的应用程序能够安全地共享用户数据。而 OAuth 2.0 正是为了解决这一问题而设计的&#xff0c;它提供了一种标准机制&…

Golang 百题(实战快速掌握语法)_1

整形转字符串类型 实验介绍 本实验将展示三种方法来实现整形类型转字符串类型。 知识点 strconvfmt Itoa 函数 代码实例 Go 语言中 strconv 包的 itoa 函数输入一个 int 类型&#xff0c;返回转换后的字符串。下面是一个例子。 package mainimport ("fmt"&qu…

wps 二维数据转转一维度数据

HSTACK(TOCOL(C2:H2&A3:A8),TOCOL(B3:B8&C1:H1),TOCOL(C3:H8))

网络编程(三)UDP TFTP协议

文章目录 一、 UDP&#xff08;一&#xff09;概述&#xff08;二&#xff09;流程 二、收发函数&#xff08;一&#xff09;recvfrom&#xff08;二&#xff09;sendto 三、实现一个简单的udp服务端和客户端四、实现tftp客户端协议 一、 UDP &#xff08;一&#xff09;概述 …

Spring-事件

Java 事件/监听器编程模型 设计模式-观察者模式的拓展 可观察者对象(消息发送者) Java.util.Observalbe观察者 java.util.Observer 标准化接口(标记接口) 事件对象 java.util.EventObject事件监听器 java.util.EventListener public class ObserverDemo {public static vo…

Spring IoC【控制反转】DI【依赖注入】

文章目录 控制反转&#xff08;IoC&#xff09;依赖注入&#xff08;DI&#xff09;IoC原理及解耦IoC 容器的两种实现BeanFactoryApplicationContext IoC 是 Inversion of Control 的简写&#xff0c;译为“控制反转”&#xff0c;它不是一门技术&#xff0c;而是一种设计思想&…

解放双手 免费AI编程工具---Fitten Code

前言 相信大家在2023年后听说了不少的关于人工智能的话题&#xff0c;对于这种全新的科技又好奇又恐惧&#xff0c;今天我们来见识下一个在VS中的AI代码工具吧。 配置环境 安装 首先我们找到管理扩展&#xff0c;然后再搜索Fitten Code下载安装。 我这里已经下好过了&#xff…

MacOS系统搭建Appium自动化测试环境

一、Appium简介 1.1 什么是APPium APPium是一个开源测试自动化框架,适用于原生、混合或移动Web应用程序的自动化测试工具。 APPium使用WebDriver协议驱动iOS、Android等应用程序。 APPium具有如下特点: 支持多平台(Android、iOS等)。支持多语言(python、java、ruby、js…

【每日刷题】Day67

【每日刷题】Day67 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 23. 合并 K 个升序链表 - 力扣&#xff08;LeetCode&#xff09; 2. 1189. “气球” 的最大数量 - …

网络安全 - kali 安装

文章目录 Kali 安装教程下载镜像 Kali 安装教程 下载镜像 kali-images安装包下载_开源镜像站-阿里云 (aliyun.com) 下载对应镜像&#xff08;自己挑&#xff09; 打开本机 cmd 并输入一下命令 ipconfig找到 NAT 模式的 IP 地址并从虚拟机中 ping

6月15号作业

使用手动连接&#xff0c;将登录框中的取消按钮使用第二中连接方式&#xff0c;右击转到槽&#xff0c;在该槽函数中&#xff0c;调用关闭函数 将登录按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在槽函数中判断ui界面上输入的账号是否为"admin"&#xff0…