Rust-开发必备-cargo_nextest-使你的Rust测试提速3倍

300 阅读3分钟

cargo-nextest

cargo-nextest是一个运行Rust项目测试的程序,官方宣称能够比原生的cargo test快3倍。同时提供以下特性:

  1. 干净、漂亮的用户界面。
  2. 识别跑的慢、或存在进程泄露的测试。
  3. 使用嵌入式语言过滤测试。
  4. 为持续集成设计。
  5. 跨平台支持:支持Linux、类Unixes、macOS以及Windows。

安装

cargo install cargo-nextest --locked

示例

项目

我们通过两个测试文件模拟实际项目当中的测试用例。

image.png

在测试中,我们通过std::thread::sleep模拟实际测试的运行时间。

./tests/test_1.rs

#[cfg(test)]
mod tests {
    use std::{thread::sleep, time::Duration};

    #[test]
    fn test_slow() {
        sleep(Duration::from_secs(60)); // Simulate some delay
        assert_eq!(1 + 1, 2);
    }

    #[test]
    fn test_fast() {
        sleep(Duration::from_secs(6)); // Simulate some delay
        assert_eq!(1 + 1, 2);
    }
}

./tests/test_2.rs

#[cfg(test)]
mod tests {
    use std::{thread::sleep, time::Duration};

    #[test]
    fn test_fast() {
        sleep(Duration::from_secs(60)); // Simulate some delay
        assert_eq!(1 + 1, 2);
    }
}

cargo test

使用cargo test运行测试:

cargo test

可以看到两个测试文件串行运行,不严谨统计大概需要120s时间。

image.png

cargo-nextest

使用cargo-nextest运行测试:

cargo nextest run

可以看到cargo-nextest将两个测试文件并行运行,并且给出测试时间为60.015s。

image.png

为什么cargo-nextest比cargo test更快

cargo test的运行模型

image.png

默认情况下,cargo test每个测试文件都是串行运行的,测试文件内则会并行运行文件内的每个测试。这个模型下有几个问题:

  1. 没有结构化的方法获取单个测试通过或失败的结果,以及每个测试所花费的时间。
  2. 第一个测试文件测试失败后,后续的测试就不再继续执行了。
  3. 测试的性能容易受到瓶颈影响:假设一个测试文件有20个测试,其中19个测试执行完成不超过5s,而剩余一个需要60s,那么这个测试文件的测试最终需要60s完成(如之前示例中所示)。cargo test在这期间是无法开始运行其它测试文件的。

cargo-nextest的运行模型

image.png

cargo-nextest的运行模型有两个阶段:

  • 列表阶段。cargo-nextest首先使用cargo test --no-run构建所有测试文件,然后查询这些文件以生成其中所有测试的列表。
  • 运行阶段。cargo-nextest然后在单独的进程中并行执行每个单独的测试。然后它收集、显示和聚合每个单独测试的结果。

测试建议

  1. 不同的测试集应通过不同的测试文件进行分类。通过cargo-nextest并行模型可以提高测试效率。
  2. 由于cargo-nextest是并行执行测试的,因此有些使用到全局变量的测试(比如普罗的监控)可能需要通过加锁的形式防止测试执行失败。

限制并行数

不限制并行数可能会导致资源过载(常见于容器过载),通过如下命令(示例为8并行数)进行限制:

cargo nextest run -j8

Ref

部分信息及图片来自官方文档。