背景
Rustのコードを書いていて、テストカバレッジを取りたいなと思ったのですが、インターネット上の情報が新旧入り混じっており困ったので雑にまとめました。
2021/02/11現在、「rust カバレッジ」で検索すると、以下の記事が上位にヒットしてきました。
- Rustのカバレッジを極める - OPTiM TECH BLOG
- Rustの新しいコードカバレッジ/Source-based code coverage - Qiita
- Rustでkcovを使って行カバレッジを計測する - sgryjp.log
- mozilla/grcovを使ったRustのテストカバレッジ計測 – ぷるぷるした直方体
上記の記事から時間が経って、状況が変化している部分があります。 これらで紹介されているツールをまとめます。
cargo-cov
2018年11月が最後のコミットとなっており、メンテされていないようです。 上記のOPTiMのブログで、「ソースコードの一部をカバレッジ計測から除外する機能が無い」との記述がありますが、メンテ状況からしてその点は変化していないでしょう。
cargo-kcov
cargo-cov
と同じ作者のものなのですが、こちらも2019年12月でメンテが止まっています。
stableでも動くようなので、確認してみたのですが、1.44から動かなくなっているようでした。
issueを見る感じだと、しばらく対応される見込みもないかなという感じです。
grcov
Mozilaがメンテしているのですが、nightlyが必要です(ので検証していません)。
tarpaulin
stableで動きますが、Linux限定のようです。 とはいえ、Windows, MacからはDockerを使えば動かせるので、大きな問題はないかもしれません。
tarpaulinでカバレッジをとる
以下のコード src/main.rs
に対してカバレッジを取ります。
#[cfg(not(tarpaulin_include))] fn main() { println!("{}", square(10, true)); println!("Hello, world!"); } fn square(x: i32, doing: bool) -> i32 { if doing { x * x } else { x } } #[cfg(test)] mod tests { use super::*; #[test] fn square_with_doing() { let x = 10; let result = square(x, true); assert_eq!(result, 100); } #[test] fn square_without_doing() { let x = 10; let result = square(x, false); assert_eq!(result, 10); } }
#[cfg(not(tarpaulin_include))]
のつけられた部分は、カバレッジ計測から除外されます。
実行
シンプルにできます。
$ cargo tarpaulin (...中略...) running 2 tests test tests::square_with_doing ... ok test tests::square_without_doing ... ok test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out Feb 11 06:33:06.671 INFO cargo_tarpaulin::report: Coverage Results: || Tested/Total Lines: || src/main.rs: 12/12 || 100.00% coverage, 12/12 lines covered
結果
オプション無しの実行では、結果は上記の標準出力のみになるようです。
--out Html
をつけると、 tarpaulin-report.html
が生成されます。
ファイル名をクリックすると、ファイルごとのカバレッジが表示されました。
ついでに: オプション管理
出力形式オプションとセットで管理するなら、 cargo-make
などを利用するのがいいかもしれません。
以下の Makefile.toml
を用意すると、 cargo make coverage
でHTML形式の出力が得られます。
[env] CARGO_MAKE_COVERAGE_PROVIDER = "tarpaulin" [tasks.coverage-tarpaulin.linux] command = "cargo" args = ["tarpaulin", "--out", "Html"]
(commandはoverrideする必要ない気がするのですが、しないとできませんでした。バグか仕様かは未調査です)