#mutation #testing #testing-cargo #file #darwin #line #mutation-testing

bin+lib cargo-darwin

Darwin 会对你的代码进行变异,如果你的代码仍然通过检查测试,则说明你的代码测试不足

4 个版本 (2 个破坏性更新)

0.3.1 2024年3月23日
0.3.0 2024年3月23日
0.2.0 2024年3月23日
0.1.0 2024年3月23日

#220Cargo 插件

每月下载量 43 次

MIT/Apache

53KB
986

Cargo Darwin

cargo-darwin 是一个基于 cargo 工具的插件。

Darwin 会对你的代码进行变异,如果你的代码仍然通过检查测试,则说明你的代码测试不足。

安装

cargo install cargo-darwin

用法

cargo darwin /path/to/project/to/test

将显示类似以下内容

[Missing] : Tests pass, the mutation hasn't been caught, suspicion of missing test
[OK]      : Tests failed, the mutation has been caught
[Timeout] : Mutation introduces infinite loop, inconclusive
[Killed]  : Mutation introduces non buildable modification
  ---
[OK] : Mutation #0 replace - by + in function "sub" of file src\a\toto.rs at line 11:6
[OK] : Mutation #1 replace - by * in function "sub" of file src\a\toto.rs at line 11:6
[Killed] : Mutation #2 replace - by && in function "sub" of file src\a\toto.rs at line 11:6
[Missing] : Mutation #3 replace + by - in function "add" of file src\lib.rs at line 5:6
[Missing] : Mutation #4 replace + by * in function "add" of file src\lib.rs at line 5:6
[Missing] : Mutation #5 replace + by - in function "add" of file src\lib.rs at line 5:10
[Missing] : Mutation #6 replace + by * in function "add" of file src\lib.rs at line 5:10

存在一个 --dry-run 模式,只列出变异而不实际应用测试。

cargo darwin --dry-run /path/to/project/to/test

详细信息

Darwin 遍历提供的路径(如果没有提供,则获取当前目录)。对于每个以 .rs 扩展名结尾的文件,Darwin 会分析文件并尝试找到可变函数。如果一个函数没有任何 #[test]#[tokio::test] 属性,则该函数是可变的。

fn mutable() {}
#[test]
fn non_mutable() {}
#[tokio::test]
async fn non_mutable_async() {}

该项目的开发非常早期,因此变异非常有限,实际上只是二进制表达式,如 a + ba - b。例如这个可变函数

fn add(x: u8, y:u8) -> u8 {
    x + y
}

将变为

fn add(x: u8, y:u8) -> u8 {
    x - y
}

然后 Darwin 创建实际项目的副本并在复制的文件上应用修改。一旦项目发生变异,Darwin 就会运行 cargo build,如果项目编译成功,则变异是可持续的。如果是这样,Darwin 将运行 cargo test,有以下三种可能情况

  • 项目测试通过:项目的测试效率低下,因为变异没有被捕获
  • 测试失败:项目至少有一个测试捕获了变异
  • 超时:即使编译成功,也会引入循环或导致测试无限运行的突变

报告

所有报告都可以在“突变路径”下的“报告”文件夹中找到。例如,如果您运行了darwin,则会得到以下树

cargo darwin --mutation-path /tmp/darwin /path/to/project/to/test

...

tmp/
├─ darwin/
  ├─ reports/
  │  ├─ mutation_0.log
  │  ├─ mutation_1.log
  │  ├─ summary
  ├─ 0/
  ├─ 1/

突变项目

如果定义了--keep标志,在测试后,您可以访问生成的项目。每个项目都有一个突变ID,相关的突变ID可以在摘要文件中找到

摘要

总结应用的突变以及每个突变的结果。

[OK] : Mutation #0 replace - by + in function "sub" of file src\a\toto.rs at line 11:6
[OK] : Mutation #1 replace - by * in function "sub" of file src\a\toto.rs at line 11:6
[Killed] : Mutation #2 replace - by && in function "sub" of file src\a\toto.rs at line 11:6
[Missing] : Mutation #3 replace + by - in function "add" of file src\lib.rs at line 5:6
[Missing] : Mutation #4 replace + by * in function "add" of file src\lib.rs at line 5:6
[Missing] : Mutation #5 replace + by - in function "add" of file src\lib.rs at line 5:10
[Missing] : Mutation #6 replace + by * in function "add" of file src\lib.rs at line 5:10

有关突变的更多信息,请检查相关的mutation_ID.log文件

突变报告

reports/mutation_X.log文件是突变的详细视图。它们按照以下命名法构建

  • 突变文件
  • 突变
  • 突变状态
  • 突变差异
  • 测试或构建输出。以下是一个输出示例
Mutation of file F:\Projets\Lab\Rust\darwin\playground\src\a\toto.rs
Mutation reason: replace - by *
Status : OK => Mutation Caught
Mutation diff:
@@ -8,7 +8,7 @@
 //
 fn sub(x: i8, y: i8) -> i8 {
     let u = 8;
-    x - y
+    x * y
 }
Output:
 #[test]
stderr:
   Compiling playground v0.1.0 (F:\Projets\Lab\Rust\darwin\tmp\1)
    Finished test [unoptimized + debuginfo] target(s) in 0.18s
     Running unittests src\lib.rs (target\debug\deps\playground-29148ab9d23d3c5d.exe)
error: test failed, to rerun pass `--lib`
stdout:
running 2 tests
test a::toto::test_sub ... FAILED
test a::toto::async_test_sub ... FAILED
failures:
---- a::toto::test_sub stdout ----
thread 'a::toto::test_sub' panicked at src\a\toto.rs:16:5:
assertion `left == right` failed
  left: 10
 right: 3
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
---- a::toto::async_test_sub stdout ----
thread 'a::toto::async_test_sub' panicked at src\a\toto.rs:21:5:
assertion `left == right` failed
  left: 10
 right: 3
failures:
    a::toto::async_test_sub
    a::toto::test_sub
test result: FAILED. 0 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

由于测试失败,突变被捕获,因此对于这个特定的突变,代码已经足够测试了

限制

该项目唯一的目的是理解突变测试及其实现方式。

这就是为什么到目前为止突变集是硬编码的。

并且非常有限

a + b给出

  • a-b
  • a*b

a - b给出

  • a+b
  • a*b
  • a&&b

趣闻

“Darwin”代表“自然选择定律”,生命通过突变适应环境,因此在进行cargo-darwin时,突变是不希望的。

我想称它为“Malcom”,以纪念《侏罗纪公园》中的“Ian Malcom”,但这个参考太牵强了^^‘

依赖项

~14–24MB
~413K SLoC