网站首页 > 文章精选 正文
7.4 集成测试库和工具
用于单元测试的大多数工具和库也适用于集成测试。
然而,有一些crate可以大大简化集成测试的工作,我们将在本节中探讨。
7.4.1 使用assert_cmd测试CLI应用程序
对于测试命令行应用程序,让我们来看看assert_cmd crate(https://crates.io/crates/assert_cmd),它使得运行命令和检查结果变得容易。为了演示,我们将为我们的快速排序实现创建一个命令行界面,它从CLI参数中排序整数,如下所示的列表。
我们可以通过运行 cargo run 5 4 3 2 1 来测试这个,它将打印出 [1, 2, 3, 4, 5]。
现在,让我们在下面的列表中使用 assert_cmd 来编写一些测试。
这些测试是好的,但为了测试已知值,我们可以做得更好一些。
我们不必在源代码中硬编码,可以创建一些简单的基于文件的固定装置(fixtures),以程序化的方式测试已知值。
首先,我们将在文件系统上创建一个简单的目录结构来存储我们的测试固定装置。这个结构由编号的文件夹组成,每个文件夹里有一个用于参数(args)的文件和一个用于预期结果(expected)的文件:
接下来,我们将创建一个测试,它会遍历树中的每个目录,并读取参数和预期结果;然后运行我们的测试;最后,检查结果,如下所示的列表。
7.4.2 在集成测试中使用proptest
接下来,为了使我们的测试更加健壮,我们可以将我们在上一章讨论过的proptest crate添加到我们的快速排序实现中,在下面的列表中作为一个集成测试。
值得注意的是,使用像proptest这样的工具自动生成测试数据进行测试可能会产生意外后果,尤其是当你的测试具有外部副作用,比如进行网络请求或写入外部数据库时。你应该尝试设计你的测试来考虑这一点,要么在每个测试前后搭建和拆除整个环境,要么提供其他方式在测试运行前后返回到已知的良好状态。在使用随机数据时,你可能会发现一些意想不到的边缘情况。
注意:当作为集成测试运行时,proptest crate会打印以下警告:proptest: FileFailurePersistence::SourceParallel已设置,但未能找到lib.rs或main.rs。这个警告可以忽略;更多详细信息请参考GitHub上的问题:https://github.com/AltSysrq/proptest/issues/233。
7.4.3 其他集成测试工具
以下是一些值得提及的,可以加速你的集成测试的额外crates(Rust语言的包):
- rexpect—自动化并测试交互式命令行界面应用程序(https://crates.io/crates/rexpect)。
- assert_fs—为消费或生成文件的应用程序提供文件系统夹具(https://crates.io/crates/assert_fs)。
7.5 模糊测试
模糊测试类似于我们本章已经讨论过的属性测试。
然而,两者之间的区别在于,在模糊测试中,你使用随机生成的数据测试你的代码,这些数据不一定是有效的。当我们进行属性测试时,我们通常将输入集限制为我们认为有效的值。进行属性测试的原因是,通常没有意义测试所有可能的输入,我们也没有无限的时间来测试所有可能的输入组合。
另一方面,模糊测试摒弃了有效和无效的概念,简单地将随机字节输入到你的代码中,这样你就可以看到会发生什么。模糊测试在安全敏感的环境中尤其受欢迎,你希望了解当代码被误用时会发生什么。
一个常见的例子是面向公众的数据源,如网页表单。网页表单可以填充来自任何需要解析、验证和处理的数据源。由于这些表单在野外,没有什么可以阻止有人用随机数据填充网页表单。例如,想象一个带有用户名和密码的登录表单,有人(或某物)可以尝试每一种用户名和密码的组合,或者最常见的组合列表,以获得系统的访问权限,无论是通过猜测正确的组合还是注入一些“神奇”的字节集,这会导致内部代码失败并绕过认证系统。这类漏洞出奇地常见,模糊测试是减轻它们的一种策略。
模糊测试的主要问题是,测试每一套可能的输入组合可能需要不切实际的时间,但实际上,你并不一定需要测试每一个输入位组合来找到错误。你可能会对模糊测试在你认为是无懈可击的代码中发现错误的速度之快感到惊讶。
为了进行模糊测试,我们将使用一个名为libFuzzer(https://llvm.org/docs/LibFuzzer.html)的库,这是LLVM项目的一部分。你可以直接使用libFuzzer与FFI(我们在第4章中探讨了FFI),但相反,我们将使用一个名为cargo-fuzz的crate,它负责为libFuzzer提供Rust API并为我们生成模板代码。
在我们深入代码示例之前,让我们讨论一下libFuzzer在高层次上的工作原理:该库将用包含函数参数的随机数据填充你提供的一个结构,并反复调用你的代码的函数。如果数据触发了错误,这将被库检测到,并构建一个测试用例来触发这个错误。
一旦我们使用cargo install cargo-fuzz命令安装了cargo-fuzz crate,我们就可以编写一个测试了。在接下来的代码示例中,我构建了一个看起来像是工作的相对简单的函数,但实际上,它包含了一个在特定条件下会触发的微妙错误。
这个函数将接受一个字符串作为输入,并将字符串解析为一个i32整数,前提是该字符串长度在1到10位之间,并且可选地,前面可以有一个-(负号)符号。如果输入不符合模式,则返回None。该函数不应导致我们的程序在无效输入时崩溃。这看起来足够无害,但实际上存在一个严重的bug。
这类bug出奇地常见,我们可能都曾经写过。像这样的边缘情况bug可能导致未定义的行为,在安全上下文中,这可能导致不好的事情发生。
接下来,让我们使用cargo-fuzz创建一个小的模糊测试。首先,我们需要通过运行cargo fuzz init来初始化样板代码。这将在我们的项目中创建以下结构:
在这里,我们可以看到cargo-fuzz在fuzz子目录中创建了一个新的项目,并且有一个测试在fuzz_target_1。我们可以使用cargo fuzz list列出fuzz目标(或测试),它将打印出fuzz_target_1。
接下来,我们需要编写模糊测试。为了测试我们的函数,我们只需用随机字符串调用它,这些字符串由模糊测试库提供。我们将使用Arbitrary(https://crates.io/crates/arbitrary)crate来派生我们需要的形式的数据。模糊测试如下面的代码所示。
现在,我们准备运行模糊测试并看看会发生什么。你可能已经知道此时存在一个bug,所以我们预期它会崩溃。当使用cargo fuzz run fuzz_target_1运行模糊器时,我们将看到如下所示的输出(由于模糊器生成了大量的日志输出,因此已经缩短了)。
请注意,运行模糊测试器可能需要相当长的时间,即使在快速机器上也是如此。
尽管这个例子应该会相对较快地触发(在大多数情况下,60秒内),但更复杂的测试可能需要更长的时间。对于无界数据(例如,没有长度限制的字符串),模糊测试器可能会花费无限的时间。
在输出的底部,cargo-fuzz会打印出导致崩溃的输入信息。此外,它还会为我们创建一个测试用例,我们可以使用它来确保将来不会再触发这个错误。对于前面的例子,我们可以简单地运行cargo fuzz run fuzz_target_1 fuzz/artifacts/fuzz_target_1/crash-105eb7135ad863be4e095db6ffe64dc1b9a1a466来用相同的输入再次测试我们的代码,这将使我们能够轻松测试修复这个错误的补丁,而无需重新从头开始运行模糊测试器。找到触发崩溃的测试用例可能需要很长时间,所以这有助于限制我们需要花费在运行模糊测试器上的时间。
作为练习,请尝试修改函数,使其不再崩溃。解决这个问题有几种不同的方法,我会提供一个提示:parse()方法已经为我们返回了一个Result。有关使用cargo-fuzz的更多详细信息,请查阅文档,网址为https://rust-fuzz.github.io/book。
概要
- 集成测试补充单元测试,但它们在一个主要方面有所不同:集成测试仅适用于公共接口。
- 我们可以使用集成测试作为一种方式来测试我们的API设计,并确保它对最终用户来说是合适且设计良好的。
- Rust内置的集成测试框架提供了最小的功能,但它对于大多数目的来说已经足够了。
- 像单元测试一样,Rust的集成测试使用libtest库,这是Rust核心的一部分。
- 像proptest、assert_cmd、assert_fs和rexpect这样的crates可以用来进一步增强我们的集成测试。
- cargo-fuzz crate提供了libFuzzer集成和Cargo命令,用于设置和运行模糊测试。
猜你喜欢
- 2025-01-16 4.精通APM-精准测试覆盖率Jacoco
- 2025-01-16 博茨瓦纳首颗卫星BotSat-1成功完成组装、集成和测试
- 2025-01-16 web 自动化测试,一定得掌握的 8 个核心知识点
- 2025-01-16 软件集成测试计划
- 2025-01-16 Spring Boot微服务测试:集成与契约测试
- 2025-01-16 使用Playwright搭建自动化测试工程
- 2025-01-16 Spring Boot集成测试:确保应用质量
- 2025-01-16 集成电路制造工艺-测试工程
- 2025-01-16 专业的嵌入式软件测试工具TESSY,针对C/C++代码单元/集成测试
- 2025-01-16 软件集成测试策略和方法
- 最近发表
- 标签列表
-
- newcoder (56)
- 字符串的长度是指 (45)
- drawcontours()参数说明 (60)
- unsignedshortint (59)
- postman并发请求 (47)
- python列表删除 (50)
- 左程云什么水平 (56)
- 计算机网络的拓扑结构是指() (45)
- 稳压管的稳压区是工作在什么区 (45)
- 编程题 (64)
- postgresql默认端口 (66)
- 数据库的概念模型独立于 (48)
- 产生系统死锁的原因可能是由于 (51)
- 数据库中只存放视图的 (62)
- 在vi中退出不保存的命令是 (53)
- 哪个命令可以将普通用户转换成超级用户 (49)
- noscript标签的作用 (48)
- 联合利华网申 (49)
- swagger和postman (46)
- 结构化程序设计主要强调 (53)
- 172.1 (57)
- apipostwebsocket (47)
- 唯品会后台 (61)
- 简历助手 (56)
- offshow (61)