14.2 文档测试

Rust 将文档与代码紧密结合,其文档注释(doc comments)不仅用于生成 API 文档,还能直接嵌入可执行的示例代码。这些示例通过 文档测试(doctest)机制自动编译和运行,确保文档始终与代码行为一致,避免“过时文档”这一常见问题。

编写文档测试

使用 /////! 注释中的代码块即可定义 doctest:

/// Adds two integers together.
///
/// # Examples
///
/// ```
/// use my_crate::add;
///
/// assert_eq!(add(2, 3), 5);
/// ```
pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

当运行 cargo test 时,Rust 会自动提取所有文档中的代码块,将其包装为独立测试函数并执行。若示例无法编译或断言失败,测试将报错。

代码块的类型

Rust 根据代码块是否以 # 开头或包含特定标记判断其用途:

  • 普通示例:会被完整编译和运行;
  • 隐藏行:以 # 开头的行在生成文档时被隐藏,但参与编译:
    /// ```
    /// # fn main() {
    /// let x = 5;
    /// assert_eq!(x, 5);
    /// # }
    /// ```
    
    上述写法常用于绕过 main 函数限制或隐藏样板代码;
  • 忽略测试:使用 no_runignorecompile_fail 控制行为:
    /// ```no_run
    /// // 会编译但不运行(如涉及 I/O)
    /// std::fs::read_to_string("file.txt").unwrap();
    /// ```
    ///
    /// ```compile_fail
    /// // 预期编译失败(用于演示错误用法)
    /// let _ = add("a", "b");
    /// ```
    

模块与路径

文档测试在独立的上下文中运行,因此必须显式引入所需项。常见做法是在示例开头添加 use 语句:

/// ```
/// use my_crate::{Config, parse_config};
///
/// let cfg = parse_config("input");
/// assert!(cfg.is_ok());
/// ```

对于二进制 crate(无 public API),可在 src/main.rs 顶部使用 #![doc(test(no_crate_inject))] 并手动指定 extern crate,但更推荐将核心逻辑移至 lib.rs 以便测试。

最佳实践

  • 所有公共 API 应包含至少一个可运行的示例;
  • 示例应简洁、自包含,并展示典型用法;
  • 避免在文档测试中使用外部依赖或文件系统操作(可用 no_run);
  • 利用 # 隐藏辅助代码,保持文档清晰;
  • 定期运行 cargo test --doc 单独验证文档测试。

小结

文档测试是 Rust “文档即契约”理念的体现。它不仅提升了文档的可信度,还鼓励开发者编写可验证的使用示例。通过将示例纳入测试套件,Rust 有效防止了文档与实现脱节的问题。合理利用 doctest,既能提高库的易用性,又能增强整体质量保障体系。

#Rust 入门教程 分享于 5 天前

内容由 AI 创作和分享,仅供参考