Rust 软件测试基础

RustRustBeginner
立即练习

This tutorial is from open-source community. Access the source code

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

在本实验中,我们将探讨使用 Rust 进行软件开发时测试的重要性,以及如何编写不同类型的测试,如单元测试和集成测试。我们还将学习如何在 Rust 项目中组织测试,并使用 cargo test 命令运行它们。此外,我们将讨论并发运行测试可能出现的潜在问题,并提供一个示例来说明这一点。

注意:如果实验未指定文件名,你可以使用任何你想要的文件名。例如,你可以使用 main.rs,并通过 rustc main.rs &&./main 进行编译和运行。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL rust(("Rust")) -.-> rust/BasicConceptsGroup(["Basic Concepts"]) rust(("Rust")) -.-> rust/DataStructuresandEnumsGroup(["Data Structures and Enums"]) rust(("Rust")) -.-> rust/DataTypesGroup(["Data Types"]) rust(("Rust")) -.-> rust/ControlStructuresGroup(["Control Structures"]) rust(("Rust")) -.-> rust/FunctionsandClosuresGroup(["Functions and Closures"]) rust(("Rust")) -.-> rust/MemorySafetyandManagementGroup(["Memory Safety and Management"]) rust/BasicConceptsGroup -.-> rust/variable_declarations("Variable Declarations") rust/BasicConceptsGroup -.-> rust/mutable_variables("Mutable Variables") rust/DataTypesGroup -.-> rust/boolean_type("Boolean Type") rust/DataTypesGroup -.-> rust/string_type("String Type") rust/ControlStructuresGroup -.-> rust/for_loop("for Loop") rust/FunctionsandClosuresGroup -.-> rust/function_syntax("Function Syntax") rust/FunctionsandClosuresGroup -.-> rust/expressions_statements("Expressions and Statements") rust/MemorySafetyandManagementGroup -.-> rust/lifetime_specifiers("Lifetime Specifiers") rust/DataStructuresandEnumsGroup -.-> rust/method_syntax("Method Syntax") subgraph Lab Skills rust/variable_declarations -.-> lab-99339{{"Rust 软件测试基础"}} rust/mutable_variables -.-> lab-99339{{"Rust 软件测试基础"}} rust/boolean_type -.-> lab-99339{{"Rust 软件测试基础"}} rust/string_type -.-> lab-99339{{"Rust 软件测试基础"}} rust/for_loop -.-> lab-99339{{"Rust 软件测试基础"}} rust/function_syntax -.-> lab-99339{{"Rust 软件测试基础"}} rust/expressions_statements -.-> lab-99339{{"Rust 软件测试基础"}} rust/lifetime_specifiers -.-> lab-99339{{"Rust 软件测试基础"}} rust/method_syntax -.-> lab-99339{{"Rust 软件测试基础"}} end

测试

如我们所知,测试对于任何软件来说都是不可或缺的!Rust 对单元测试和集成测试提供了一流的支持(请参阅《Rust 程序设计语言》(TRPL)中的这一章)。

从上面链接的测试章节中,我们了解了如何编写单元测试和集成测试。在组织方面,我们可以将单元测试放在它们所测试的模块中,而将集成测试放在它们自己的 tests/ 目录中:

foo
├── Cargo.toml
├── src
│   └── main.rs
│   └── lib.rs
└── tests
    ├── my_test.rs
    └── my_other_test.rs

tests 目录中的每个文件都是一个单独的集成测试,即一个旨在测试你的库的测试,就好像它是从一个依赖的 crate 中被调用一样。

测试章节详细阐述了三种不同的测试风格:单元测试、文档测试和集成测试。

cargo 自然提供了一种简单的方法来运行你所有的测试!

$ cargo test

你应该会看到如下输出:

[object Object]

你也可以运行名称匹配某个模式的测试:

$ cargo test test_foo
[object Object]

需要注意的一点是:Cargo 可能会并发运行多个测试,所以要确保它们不会相互竞争。

这种并发导致问题的一个例子是,如果两个测试都输出到一个文件,如下所示:

#[cfg(test)]
mod tests {
    // 导入必要的模块
    use std::fs::OpenOptions;
    use std::io::Write;

    // 这个测试写入一个文件
    #[test]
    fn test_file() {
        // 打开文件 ferris.txt,如果不存在则创建一个。
        let mut file = OpenOptions::new()
         .append(true)
         .create(true)
         .open("ferris.txt")
         .expect("Failed to open ferris.txt");

        // 打印 "Ferris" 5 次。
        for _ in 0..5 {
            file.write_all("Ferris\n".as_bytes())
             .expect("Could not write to ferris.txt");
        }
    }

    // 这个测试尝试写入同一个文件
    #[test]
    fn test_file_also() {
        // 打开文件 ferris.txt,如果不存在则创建一个。
        let mut file = OpenOptions::new()
         .append(true)
         .create(true)
         .open("ferris.txt")
         .expect("Failed to open ferris.txt");

        // 打印 "Corro" 5 次。
        for _ in 0..5 {
            file.write_all("Corro\n".as_bytes())
             .expect("Could not write to ferris.txt");
        }
    }
}

尽管预期的结果是这样:

$ cat ferris.txt
Ferris
Ferris
Ferris
Ferris
Ferris
Corro
Corro
Corro
Corro
Corro

但实际写入 ferris.txt 的内容却是这样:

$ cargo test test_foo
Corro
Ferris
Corro
Ferris
Corro
Ferris
Corro
Ferris
Corro
Ferris

总结

恭喜你!你已经完成了测试实验。你可以在 LabEx 中练习更多实验来提升你的技能。