【Rust自学】11.10. 集成测试

server/2025/1/12 8:12:42/

喜欢的话别忘了点赞、收藏加关注哦(加关注即可阅读全文),对接下来的教程有兴趣的可以关注专栏。谢谢喵!(=・ω・=)
请添加图片描述

11.10.1. 什么是集成测试

在Rust里,集成测试完全位于被测试库的外部。集成测试调用库的方式和其他代码一样,这也意味着集成测试只能调用对外公开的API。

集成测试的目的是验证被测试库的多个部分能否正确地一起工作,这一点有别于单元测试单元测试比较小也比较专注,每次只对一个模块进行隔离的测试,还可以测试私有的(private)接口。

有时候能够独立运行的一些单元代码在合在一起运用时也会发生问题,集成测试正是为了今早发现和解决这种问题存在的。所以说,集成测试的覆盖率很重要

11.10.2. tests目录

创建集成测试需要先创建tests目录。

这个目录是与src目录并列,cargo会自动在这个目录下寻找集成测试文件。在这个目录下可以创建任意多的集成测试文件,cargo会在编译时把每个测试文件都处理为一个单独的包,也就是一个单独的crate

下面来演示一下创建集成测试文件:

1. 创建tests目录

在与src同级的目录下创建名为tests的文件夹:
请添加图片描述

2. 创建测试文件

tests目录下创建.rs的测试文件,给它取个名字,这里我起的是integration_test.rs
请添加图片描述

3. 把测试代码移到测试文件里

以上一篇文章的代码为例(lib.rs):

rust">pub fn add_two(a: usize) -> usize {internal_adder(a, 2)
}fn internal_adder(left: usize, right: usize) -> usize {left + right
}#[cfg(test)]
mod tests {use super::*;#[test]fn internal() {let result = internal_adder(2, 2);assert_eq!(result, 4);}
}

由于每一个集成测试文件都是一个单独的crate,所以这个文件(integration_test.rs)想要测试lib.rs这个crate的内容就得先导入作用域。

在这个例子中,由于我给这个项目命名为RustStudy,所以这个package(包)的名字就是RustStudy,如果你不清楚可以到你的cargo.toml里看name这个参数。在这个例子中,导入作用域写:use RustStudy;即可,如果你想指定到具体的函数也行。

导入完后直接写测试函数就可以,不需要写#[cfg(test)],因为tests目录下的代码只会在运行cargo test的时候被执行,只需要给测试函数标注#[test]即可。

整体代码如下(integration_test.rs):

rust">use RustStudy;#[test]
fn it_adds_two() {let result = RustStudy::add_two(2);assert_eq!(result, 4);
}

输出:

$ cargo testCompiling adder v0.1.0 (file:///projects/adder)Finished `test` profile [unoptimized + debuginfo] target(s) in 1.31sRunning unittests src/lib.rs (target/debug/deps/adder-1082c4b063a8fbe6)running 1 test
test tests::internal ... oktest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00sRunning tests/integration_test.rs (target/debug/deps/integration_test-1082c4b063a8fbe6)running 1 test
test it_adds_two ... oktest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00sDoc-tests adderrunning 0 teststest result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

可以看到,这个输出显示运行了两个测试,这是因为一个是来自lib.rs的测试(单元测试),一个是来自integration_test.rs的测试(集成测试)。

11.10.3. 运行指定的集成测试

运行一个特定的集成函数,可以使用cargo test 指定的函数名;运行某个测试文件内的所有测试函数,可以使用cargo test --test 文件名

看个例子:
请添加图片描述

现在tests下有两个文件,如果我只希望运行integration_test.rs里的测试函数,那么就输入指令:

cargo test --test integration_test

11.10.4. 集成测试中的子模块

由于tests目录下的每个文件被编译成单独的crate,所以这些文件互不共享行为(与src目录下的文件规则不同)。

那如果我想将测试函数中重复出现的逻辑提取到一个helper函数中,避免代码重复,该怎么写呢?

举个例子,我在tests目录下写了common.rs这个文件用于存储helper函数:
请添加图片描述

试试执行测试:

$ cargo testCompiling adder v0.1.0 (file:///projects/adder)Finished `test` profile [unoptimized + debuginfo] target(s) in 0.89sRunning unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)running 1 test
test tests::internal ... oktest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00sRunning tests/common.rs (target/debug/deps/common-92948b65e88960b4)running 0 teststest result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00sRunning tests/integration_test.rs (target/debug/deps/integration_test-92948b65e88960b4)running 1 test
test it_adds_two ... oktest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00sDoc-tests adderrunning 0 teststest result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

可以看到,在测试结果中出现了对common.rs的测试。但因为common.rs是用来存储helper函数的,所以它本身不需要也没必要被测试,这种写法是错误的。

正确的做法是在tests目录下创建一个common目录,在里面创建mod.rs,把helper函数都放到这里面来,把原来的common.rs删掉即可:
请添加图片描述

这实际上是另外一种可以被Rust理解的命名规范,Rust不会把common模块视作为集成测试文件,而在测试输出中也不会出现common了,因为tests下的子目录不会被视为单独的crate进行编译。

如果要在集成测试文件中使用这里面的内容,只需要在文件开头写mod 文件夹名;即可,在这个例子中就是mod common;。使用时写common::你想要的函数,在这个例子中就是common::setup()

11.10.5. 针对binary crate的集成测试

如果项目是二进制包(binary crate),也就是只含有src/main.rs没有src/lib.rs,就不可以在tests目录下创建集成测试,即使有,也无法把main.rs的函数导入作用域。因为只有library crate(也就是有lib.rs)才能暴露函数给其它crate用。

binary crate意味着独立运行。因此,Rust的binary项目通常会把这些逻辑都放在lib.rs里,而在main.rs里只有简单的调用。这样做项目就会被视为library crate,就可以使用集成测试来检查代码。


http://www.ppmy.cn/server/157708.html

相关文章

【Linux】Linux常见指令(上)

个人主页~ 初识Linux 一、Linux基本命令1、ls指令2、pwd命令3、cd指令4、touch指令5、mkdir指令6、rmdir指令7、rm指令8、man指令9、cp指令10、mv命令 Linux是一个开源的、稳定的、安全的、灵活的操作系统,Linux下的操作都是通过指令来实现的 一、Linux基本命令 先…

Android广播和阿里云消息推送服务

一、什么是广播? 广播(Broadcast)在Android开发中是一个重要的概念,它类似于现实生活中的广播电台,通过“大喇叭”将消息传递给所有感兴趣的接收者。广播机制在Android系统中用于在不同组件之间传递信息,是…

分布式ID—雪花算法

背景 现在的服务基本是分布式、微服务形式的,而且大数据量也导致分库分表的产生,对于水平分表就需要保证表中 id 的全局唯一性。 对于 MySQL 而言,一个表中的主键 id 一般使用自增的方式,但是如果进行水平分表之后,多…

linux-磁盘io性能指标!

一. 引文: 平时查看或者监控磁盘io时,基本上都是用的现成的工具/脚本, 对其了解的还是很浅,特参考一些资料整理了下,留个随笔。 二.磁盘I/O性能指标: 磁盘 I/O 是 Unix/Linux 系统管理中一个非常重要的组成部分。磁盘…

Python的模式匹配

python的模式匹配 当我们使用if...elif...else时,面对较多条件就会出现if...elif...elif...elif...elif...elif...else会写很长的一段代码,导致我们代码的可读性变差。 即针对若干种情况我们可以使用match语句(类似于C语言的switch多分支语…

【HarmonyOS Next NAPI 深度探索1】Node.js 和 CC++ 原生扩展简介

【HarmonyOS Next NAPI 深度探索1】Node.js 和 CC 原生扩展简介 如果你用过 Node.js,应该知道它强大的地方在于能处理各种场景,速度还很快。但你有没有想过,Node.js 的速度秘密是什么?今天我们来聊聊其中一个幕后英雄——原生扩展…

CSS语言的网络编程

CSS语言的网络编程 引言 CSS(Cascading Style Sheets,层叠样式表)是一种用于描述HTML或XML文档外观样式的样式表语言。虽然CSS本身并不是一种编程语言,但它在网页设计和开发中发挥着至关重要的作用。随着互联网的发展&#xff0…

Postman接口测试04|批量运行测试用例、参数化、Mock Server、Cookie鉴权、Newman生成测试报告

目录 十一、Postman批量运行测试用例 十二、实现数据驱动(也称参数化) 1、csv文件 1️⃣编辑csv文件 2️⃣更新参数的值 3️⃣修改测试脚本和断言 5️⃣批量运行测试用例 2、Json文件 1️⃣编辑Json文件 2️⃣其他操作和处理csv文件相同 十三、…