Rust代码突变测试工具cargo-mutants的使用,提升Rust项目测试覆盖率与代码质量

Rust代码突变测试工具cargo-mutants的使用,提升Rust项目测试覆盖率与代码质量

cargo-mutants是一个帮助提升Rust程序质量的工具,它能发现代码中可以插入错误但不会导致测试失败的位置。

功能概述

覆盖率测量虽然有用,但它们只能告诉你哪些代码被测试覆盖,并不能说明测试是否真正检查了代码的行为。突变测试提供了不同的信息,它能告诉你测试是否真的检查了代码的行为。

cargo-mutants的目标是:

  • 在任何Rust源代码树中都能轻松运行
  • 告诉你那些可能存在bug或测试不足的区域的有趣信息

安装

cargo install --locked cargo-mutants

快速开始

在Rust源代码目录中运行:

cargo mutants

如果只想对特定文件生成突变:

cargo mutants -f src/something.rs

示例Demo

下面是一个完整的示例,展示如何使用cargo-mutants来测试一个简单的Rust项目:

  1. 首先创建一个简单的Rust项目:
cargo new mutant_demo
cd mutant_demo
  1. 添加一些测试代码到src/lib.rs:
// 计算两个数的和
pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

// 计算两个数的乘积
pub fn multiply(a: i32, b: i32) -> i32 {
    a * b
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_add() {
        assert_eq!(add(2, 2), 4);
    }

    #[test]
    fn test_multiply() {
        assert_eq!(multiply(3, 3), 9);
    }
}
  1. 安装cargo-mutants并运行测试:
cargo install --locked cargo-mutants
cargo mutants

cargo-mutants会尝试修改(add函数中的a + b可能会被改为a - b等),然后运行测试来检查这些修改是否会被测试发现。

  1. 如果测试没有覆盖所有情况,cargo-mutants会报告哪些突变没有被测试捕获,例如:
Found 4 mutants to test
Testing mutant in src/lib.rs:3: replace `a + b` with `a - b`
  ✓ Caught by test_add
Testing mutant in src/lib.rs:8: replace `a * b` with `a + b`
  ✗ Not caught by any test

这表明我们的测试没有覆盖当乘法函数被错误地改为加法的情况。

完整示例

下面是一个更完整的示例,展示如何改进测试以覆盖所有突变情况:

// 计算两个数的和
pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

// 计算两个数的乘积
pub fn multiply(a: i32, b: i32) -> i32 {
    a * b
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_add() {
        assert_eq!(add(2, 2), 4);
        assert_eq!(add(0, 0), 0);  // 测试边界情况
        assert_eq!(add(-1, 1), 0); // 测试负数情况
    }

    #[test]
    fn test_multiply() {
        assert_eq!(multiply(3, 3), 9);
        assert_eq!(multiply(0, 5), 0);  // 测试乘以0的情况
        assert_eq!(multiply(-2, 3), -6); // 测试负数乘法
    }
}

改进后的测试现在能捕获更多潜在的突变,提高了测试覆盖率。

项目状态

截至2025年1月,这是一个积极维护的业余项目。预计每1-2个月会发布一次版本。

该软件"按原样"提供,不提供任何形式的担保。


1 回复

Rust代码突变测试工具cargo-mutants使用指南

工具介绍

cargo-mutants是一个Rust突变测试工具,它通过自动修改(突变)你的源代码来检测测试套件的有效性。突变测试是一种高级测试技术,它通过故意在代码中引入错误(突变)来验证你的测试是否能捕获这些错误。

安装方法

cargo install cargo-mutants

基本使用方法

1. 运行突变测试

在项目根目录下运行:

cargo mutants

这个命令会:

  1. 扫描你的项目代码
  2. 生成各种可能的突变
  3. 对每个突变运行测试
  4. 报告哪些突变没有被测试捕获

2. 查看结果

运行后会显示类似这样的输出:

Found 23 mutants to test
...
✓ 18 mutants caught by tests
✗ 5 mutants survived (not caught by tests)

3. 针对特定目录运行

cargo mutants --dir src/lib

高级用法

1. 生成HTML报告

cargo mutants --html

这会生成一个详细的HTML报告,显示所有突变和测试结果。

2. 排除特定文件或模式

cargo mutants --exclude 'src/legacy/*.rs'

3. 只检查未捕获的突变

cargo mutants --uncaught

示例场景

假设有以下Rust函数:

// src/lib.rs
pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_add() {
        assert_eq!(add(2, 2), 4);
    }
}

运行cargo mutants可能会报告突变未被捕获,因为它可能会将a + b突变为a - b,而你的测试只验证了2+2=4的情况。改进后的测试应该包括更多测试用例:

#[test]
fn test_add() {
    assert_eq!(add(2, 2), 4);
    assert_eq!(add(0, 0), 0);
    assert_eq!(add(-1, 1), 0);
    assert_eq!(add(100, 200), 300);
}

完整示例demo

// src/lib.rs

/// 计算两个数的乘积
pub fn multiply(a: i32, b: i32) -> i32 {
    a * b
}

/// 检查数字是否为偶数
pub fn is_even(n: i32) -> bool {
    n % 2 == 0
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_multiply() {
        // 测试正数
        assert_eq!(multiply(2, 3), 6);
        // 测试负数
        assert_eq!(multiply(-2, 3), -6);
        // 测试零
        assert_eq!(multiply(0, 5), 0);
    }
    
    #[test]
    fn test_is_even() {
        // 测试偶数
        assert!(is_even(2));
        assert!(is_even(0));
        assert!(is_even(-4));
        // 测试奇数
        assert!(!is_even(1));
        assert!(!is_even(-3));
    }
}

集成到CI/CD

可以在项目的CI流程中添加突变测试:

# .github/workflows/test.yml
- name: Run mutation tests
  run: cargo mutants --all

优势

  1. 提高测试覆盖率:发现测试中的盲点
  2. 提升代码质量:迫使你编写更全面的测试
  3. 自动化检测:比人工代码审查更系统化
  4. 快速反馈:在CI流程中快速发现问题

注意事项

  1. 突变测试可能比较耗时,建议在本地开发时针对修改的部分运行
  2. 不是所有突变都需要被捕获,有些可能是无害的
  3. 可以与常规测试覆盖率工具配合使用

通过定期运行cargo-mutants,你可以显著提高Rust项目的测试质量和代码健壮性。

回到顶部