编写自动化测试
在 1972 年的论文《谦卑的程序员》中,Edsger W. Dijkstra 说过:"程序测试是一种非常有效的展示 bug 存在的方式,但对于展示 bug 的不存在却完全无能为力。"这并不意味着我们不应该尽可能多地去测试!
我们程序中的正确性,是指我们的代码在多大程度上做到了我们想让它做的事情。Rust 在设计时高度关注程序的正确性,但正确性十分复杂,并不容易证明。Rust 的类型系统承担了这一负担的绝大部分,但类型系统并不能捕获所有问题。因此,Rust 包含了对编写自动化软件测试的支持。
假设我们编写了一个函数 add_two,它会给传入的任意数字加 2。该函数的签名接收一个整数作为参数,并返回一个整数作为结果。当我们实现并编译该函数时,Rust 会执行你目前所学的所有类型检查和借用检查,以确保例如我们没有向该函数传入 String 值或无效引用。但 Rust 无法检查该函数是否会精确地完成我们的意图,即返回参数加 2,而不是比如参数加 10 或参数减 50!这正是测试发挥作用的地方。
我们可以编写测试来断言,例如,当我们向 add_two 函数传入 3 时,返回值是 5。每当我们对代码进行修改时,都可以运行这些测试,以确保任何已有的正确行为没有改变。
测试是一项复杂的技能:虽然我们无法在一个章节中涵盖如何编写优秀测试的每个细节,但在本章中,我们将讨论 Rust 测试功能的机制。我们会介绍编写测试时可用的注解和宏、运行测试时提供的默认行为和选项,以及如何将测试组织为单元测试和集成测试。