在Rust中编写自动化测试
1.摘要
Rust中的测试函数是用来验证非测试代码是否是按照期望的方式运行的, 测试函数体通常需要执行三种操作:1.设置任何所需的数据或状态;2.运行需要测试的代码;3.断言其结果是我们所期望的。本篇文章主要探讨了Rust自动化测试的几种常见场景。
2.测试函数详解
在Rust项目工程中, 可以对任意函数进行自动化测试, 前提是需要在被测试函数上面加上#[test]注解, 然后运行cargo test命令进行函数自动化测试, Rust会查找所有被#[test]注解的函数并自动进行测试。
先看下面一段代码:
#[test]
fn add_calc() {let result = 1 + 2;assert_eq!(result, 3);
}
在上面的代码中, 我实现了一个加法计算的函数: add_calc(), 将加法结果保存到不可变变量result中, 并使用了assert_eq!宏来断言1+2的结果, assert!宏由标准库提供, 在希望确保测试过程中一些条件为true时非常有用。在函数上方加上了#[test]注解, 表示该函数将执行自动化测试, 运行: cargo test看下结果:

从测试结果中, 可以看到test add_calc ... ok 这行, 表示该函数测试通过了。
现在我修改下断言的结果, 将代码修改为:
#[test]
fn add_calc() {let result = 1 + 2;assert_eq!(result, 4);
}
再次运行cargo test命令, 返回结果如下:

可以看到, 计算的结果是3, 但断言相等的条件是等于4, 因此函数执行失败, add_calc()函数自动化测试不通过。
接下来我们再加入一个函数, 看看在具有多个函数的前提下, 同时具备成功和失败的情况, 代码如下:
#[test]
fn add_calc() {let result = 1 + 2;assert_eq!(result, 3);
}
#[test]
fn another_method() {panic!("执行失败,抛出一个异常!")
}
在上面的代码中, 增加了一个名为another_method()的函数, 该函数直接使用panic!抛出一个异常, 直接扮演了函数执行失败的角色, 而上面的add_calc()函数我讲assert_eq!宏修改正确, 将扮演执行成功的角色, 使用cargo test命令看下结果:

可以看到, add_calc()函数测试没问题, 后面用绿色ok表示, 而another_method()函数执行失败, 使用红色的FAILED标记。
3.自定义失败信息
在上面的案例中, 我使用了assert_eq!宏来断言结果, 同样, 也可以向宏传递一个可选的失败信息参数, 可以在测试失败时将自定义的失败信息一并打印出来, 使用自定义信息有个好处, 当测试失败时, 能更好的理解代码到底出了什么问题, 看一段下面的代码:
pub fn make_string(name: &str) -> String {format!("Hello,{}!", name)
}
#[test]
fn is_contain_name() {let result = make_string("cargo");assert!(result.contains("cargo"));
}
在这段代码中, 定义了一个函数make_string, 该函数接收一个字符串参数, 并在函数内部通过format!宏格式化字符串后返回, 在函数is_contain_name()中, 传入一个字符串"cargo", assert!会判断make_string()函数返回的字符串中是否会包含"cargo"字符串,如果包含就是成功的,否则就失败, 这里我们能预言结果应该是成功的, 测试一下看看:

结果跟我们预想的一样, 现在再加入一些更详细的变化信息看看, 代码如下:
pub fn make_string(name: &str) -> String {format!("Hello,{}!", name)
}
#[test]
fn is_contain_name() {let result = make_string("rustup");assert!(result.contains("cargo"), "make_string中不包含该字符串,值为:`{}`", result);
}
我在assert!宏中加入了变量打印, 假如make_string()函数没有返回预期的结果, 那结果到底是什么,这里我们将能看到失败原因, 测试结果如下:

从结果可以看到, 函数的确测试失败了, 但我们看到了关键信息, 失败的原因是因为make_string()函数返回的字符串内容为:Hello,rustup!,这个结果与断言中的result.contains("cargo")结果是不同的, “Hello,rustup!”字符串中并不包含"cargo"字符串,所以函数测试失败。
4.检查崩溃异常
除了使用断言宏之外, Rust还提供了一个should_panic用来检测程序中的panic,并且提供了一个名为expected的参数用来自定义消息,看一段下面的代码:
pub fn number_calc(value: i32) -> i32 {let ret_value = 40;if value < 0 {panic!("值必须大于0,传参的值为:{}", value)}return ret_value
}
#[test]
#[should_panic(expected = "传参不能小于0")]
fn is_contain_name() {let result = number_calc(-1);
}
在number_calc()函数中, 如果判断参数传入的值小于0, 会抛出一个panic, 为了监视是什么原因导致, 在函数is_contain_name()上面使用should_panic进行监控, 并使用expected参数指定自定义消息, 如果遇到传入的参数小于0, 将触发该消息打印, 使用cargo test运行一下看看结果:

从结果可以看到, 的确检测到了panic产生, panic打印了本身的消息, 最后一行shoud_panic也触发了消息, 并打印出失败的原因。
5.使用Result<T, E>测试
先看一段下面的代码:
pub fn number_calc(value: i32) -> i32 {let ret_value = 40;if value < 0 {return 30}return ret_value
}
#[test]
fn is_contain_name() -> Result<(), String>{if number_calc(2) == 40 {OK(())}else{Err(String::from("结果不等于40,请检查原因!"))}
}
在上面的代码中, is_contain_name()函数的返回类型现在变为:Result<(), String>, 在函数体中, 不同于调用assert_eq!,现在如果测试通过,将返回Ok(()), 在测试失败时, 返回带有String的Err错误。现在传入参数为2, 将显示正常的结果:

现在我们再传入一个小于0的负值看看,结果如下:

可以看到, 如果使用Result<(), String>接收结果, 当出来错误时, 将返回一个Error,并打印对应的自定义消息。
6.总结
在本篇文章中, 我们使用#[test]注解完成了对指定函数的自动化测试, 使用assert!宏对错误进行断言, 在断言中自定义错误显示消息用于查看更详细的错误原因。使用了should_panic对panci错误进行了监控, 最后使用Result<T, E>替代断言分别完成了代码测试和自定义错误消息打印, 在以后的实际应用中, 可能还会有一些组合测试的场景出现, 到时候再具体问题具体分析。
相关文章:
在Rust中编写自动化测试
1.摘要 Rust中的测试函数是用来验证非测试代码是否是按照期望的方式运行的, 测试函数体通常需要执行三种操作:1.设置任何所需的数据或状态;2.运行需要测试的代码;3.断言其结果是我们所期望的。本篇文章主要探讨了Rust自动化测试的几种常见场景。 2.测试函数详解 在Rust项目工…...
羊大师提问,为什么吃得越咸越容易出现健康问题?
羊大师提问,为什么吃得越咸越容易出现健康问题? 在现代社会中,有一种追求咸味食物的趋势,许多人都钟爱于吃咸味食物。吃咸味食物往往容易导致健康问题,引发各种疾病。那么为什么吃的越咸越容易生病呢? 今…...
linux ld 链接器学习笔记
ld链接器笔记 1. 首先编写一段汇编代码 这里的汇编语法时 AT&T语法,是gcc原生支持的语法,底层使用 gas(gnu assembler) 完成汇编,相较于 Intel x86语法, AT&T 语法要更加古老,因此大多数人更加偏向于使用 Intel 的语法. nasm 编译器支持x86语法.自从2.10版本…...
栈模拟先序后序中序遍历(非递归遍历)
先序遍历: vector<int> preorderTraversal(TreeNode* u) {stack<TreeNode*>stk;vector<int>res;if(unullptr) return res;while(stk.size()||u){if(u){res.push_back(u->val);//遍历当前结点stk.push(u);//记录当前递归层uu->left;//遍历左…...
linux 内核软中断介绍
在介绍软中断之前,先来介绍一个概念:中断下半部: 为了避免处理复杂的中断嵌套,中断处理程序是在关闭中断的情况下执行的。可是,如果关闭中断的时间太长,可能导致中断请求丢失。例如周期时钟每隔 10 毫秒发送…...
软考:2024年软考高级:软件工程
软考:2024年软考高级: 提示:系列被面试官问的问题,我自己当时不会,所以下来自己复盘一下,认真学习和总结,以应对未来更多的可能性 关于互联网大厂的笔试面试,都是需要细心准备的 (1…...
Kubernetes(K8s)_15_CNI
Kubernetes(K8s)_15_CNI CNI网络模型UnderlayMAC VLANIP VLANDirect Route OverlayVXLAN CNI插件FlannelCalico CNI配置内置实现 CNI CNI(Container Network Interface): 实现容器网络连接的规范 Kubernetes将网络通信可分为: Pod内容器、Pod、Pod与Se…...
python 生成器的作用
1. 生成器 参考: https://www.cainiaojc.com/python/python-generator.html 1.1. 什么是生成器? 在 python 中,一边循环一边计算的机制,称为生成器:generator. 1.2. 生成器有什么优点? 1、节约内存。p…...
第十五届蓝桥杯(Web 应用开发)模拟赛 2 期-大学组(详细分析解答)
目录 1.相不相等 1.1 题目要求 1.2 题目分析 1.3 源代码 2.三行情书 2.1 题目要求 2.2 题目分析 2.3 源代码 3.电影院在线订票 3.1 题目要求 3.2 题目分析 3.3 源代码 4.老虎坤(不然违规发不出来) 4.1 题目要求 4.2 题目分析 4.3 源代码 …...
图解系列--HTTPS,认证
确保 Web 安全的HTTPS 1.HTTP 的缺点 1.1.通信使用明文可能会被窃听 加密处理防止被窃听 加密的对象可以有这么几个。 (1).通信的加密 HTTP 协议中没有加密机制,但可以通过和 SSL(Secure Socket Layer,安全套接层)或TLSÿ…...
element plus中表格的合计属性和例子
在 element plus 表格中,您可以使用 summary-method 属性来指定一个函数,计算表格中列的合计或平均值等。该函数应该返回一个对象,其中包含每个列的合计值。例如,如果您的表格数据是这样的: [{ name: John, age: 20, …...
计网Lesson1笔记
文章目录 几个简单概念计网的发展史阿帕网和RFCTCP/IP 协议互联网协议计网设计OSI 的七层架构TCP/IP 协议簇 几个简单概念 主机(host):指单个计算机,比如PC,或者其他电子设备。端系统(end system):指一块区域内的多个主机&#x…...
指针数组以及利用函数指针来实现简易计算器及typedef关键字(指针终篇)
文章目录 🚀前言🚀两段有趣的代码✈️typedef关键字 🚀指针数组🚀简易计算器的实现 🚀前言 基于阿辉前两篇博客指针的基础篇和进阶篇对于指针的了解,那么今天阿辉将为大家介绍C语言的指针剩下的部分&#…...
josef JZ-7Y-33静态中间继电器 电压DC220V 板前接线
系列型号: JZ-7Y-201X静态中间继电器;JZ-7J-201X静态中间继电器; JZ-7L-201X静态中间继电器;JZ-7D-201X静态中间继电器; JZ-7Y-201静态中间继电器;JZ-7J-201静态中间继电器; JZ-7L-201静态中…...
Java第二十章 ——多线程
本文主要讲了java中多线程的使用方法、线程同步、线程数据传递、线程状态及相应的一些线程函数用法、概述等。 在这之前,首先让我们来了解下在操作系统中进程和线程的区别: 进程:每个进程都有独立的代码和数据空间(进程上下文…...
【超强笔记软件】Obsidian实现免费无限流量无套路云同步
【超强笔记软件】Obsidian如何实现免费无限流量无套路云同步? 目录 一、简介 软件特色演示: 二、使用免费群晖虚拟机搭建群晖Synology Drive服务,实现局域网同步 1 安装并设置Synology Drive套件 2 局域网内同步文件测试 三、内网穿透群…...
【Linux小项目】实现自己的bash
0. bash原理介绍 bash实际上就是一个负责解析输入字符串工具. 我们需要做的事是这些: 手动分割出输入的字符串判断哪些变量是内建命令(自己执行),哪些命令是普通命令(创建子进程执行)实现的功能有: echo export cd 常规指令 输入、输出流重定向 #include<stdio.h> #i…...
客户案例:EDLP助力金融行业打造高效数据防泄露体系
客户背景 某金融机构是一家以金融科技为核心,致力于为客户提供全方位、智能化、便捷化金融服务的综合性企业。公司总部位于南京,业务范围覆盖全国,拥有强大的技术研发团队和优秀的业务精英,为客户提供全方位的金融服务解决方案。 …...
【JavaFX漏扫开发基础】stage窗口/模式/模态
文章目录 stage一、stage窗口二、stage窗口,模式,模态stage模式(5种样式)模态化窗口stage stage其实就是一个窗口,它啥也不是,打开所有windows的程序都会有一个窗口,这个窗口就是javafx里的stage。里面的内容不属于stage,stage就是一个窗口,就这么简单。 Stage is a…...
MySQL进阶知识:锁
目录 前言 全局锁 表级锁 表锁 元数据锁(MDL) 意向锁 行级锁 行锁 行锁演示 间隙锁/临界锁 演示 前言 MySQL中的锁,按照锁的粒度分,分为以下三类 全局锁:锁定数据库中的所有表。表级锁:每次操…...
OpenClaw安全实践:千问3.5-9B本地化部署方案
OpenClaw安全实践:千问3.5-9B本地化部署方案 1. 为什么选择本地化部署? 去年我在尝试用AI助手处理一些敏感文档时,遇到了一个尴尬的问题——当我需要整理公司内部的技术方案时,既希望AI能帮我快速归纳要点,又担心把文…...
Naive UI 主题色定制实战:从组件覆盖到全局配置
1. 为什么需要定制Naive UI主题色? 当你使用Naive UI开发项目时,默认的绿色主题可能并不符合你的品牌风格。比如我们团队最近接手的一个金融类项目,客户要求整体UI采用深蓝色调,这时候就需要对Naive UI的主题色进行深度定制。主题…...
终极指南:如何用KCN-GenshinServer轻松搭建原神私服
终极指南:如何用KCN-GenshinServer轻松搭建原神私服 【免费下载链接】KCN-GenshinServer 基于GC制作的原神一键GUI多功能服务端。 项目地址: https://gitcode.com/gh_mirrors/kc/KCN-GenshinServer 还在为复杂的命令行配置而头疼吗?KCN-GenshinSe…...
掌握SQL窗口函数,轻松处理复杂数据分析
SQL 窗口函数(Window Function)是一种强大的分析工具,能够在不缩减原始数据行数的前提下执行复杂计算。这种函数通过对一组相关数据行(称为"窗口")进行计算,并将结果直接附加到每一行记录中。窗口…...
.NET 10了,HttpClient还是不能用using吗?我做了一个实验
会突然变成玄学:有的人能跑,有的人会炸,有人说这是一个这是一个“bug”,在某某版本中会修复(其实并没有),有人说这是一个feature,设计就是如此……所以我决定做一个实验,…...
实战应用:在快马平台构建带缺陷的微项目,演练测试面试实战题
今天想和大家分享一个特别实用的软件测试学习方法——通过构建带缺陷的微项目来演练测试面试题。这个方法不仅帮助我顺利通过了最近的面试,还让我对测试工作有了更深入的理解。 为什么选择在线书店作为测试项目? 在线书店系统包含了软件测试中最常见的…...
Factory IO + S7-PLCSIM V18 仿真避坑指南:如何解决传感器信号丢失和传送带卡料问题
Factory IO与S7-PLCSIM V18工业仿真实战:传感器优化与传送带故障排除指南 在工业自动化仿真领域,Factory IO与西门子S7-PLCSIM V18的组合已经成为工程师验证智能工厂逻辑的高效工具链。这套解决方案能够完整模拟从物料加工到仓储的完整产线,但…...
ai生成代码如何管理?快马结合gitbash实现智能开发工作流
今天想和大家分享一个高效的工作流:如何用AI生成代码后,通过GitBash进行规范的版本管理。最近在InsCode(快马)平台实践了这个方法,整个过程非常流畅。 AI生成代码阶段 在快马的AI对话区输入需求:“创建一个带有深色模式切换功能的…...
千问3.5-2B保姆级教程:从模型原理到业务集成的全栈技术路径
千问3.5-2B保姆级教程:从模型原理到业务集成的全栈技术路径 1. 认识千问3.5-2B视觉语言模型 千问3.5-2B是Qwen系列中的小型视觉语言模型,它能够同时理解图片内容和处理自然语言。简单来说,这个模型就像是一个能"看懂"图片并回答问…...
新零售系统开发的关键要素
新零售系统开发需要整合线上线下资源,实现数据驱动的智能化运营。以下是核心开发要点:技术架构设计采用微服务架构实现系统模块化,支持高并发场景。前端可选用React/Vue构建跨平台应用,后端推荐Spring Cloud或Node.js。数据库根据…...
