Rust 1.49時点のテストカバレッジ事情雑まとめ

背景

Rustのコードを書いていて、テストカバレッジを取りたいなと思ったのですが、インターネット上の情報が新旧入り混じっており困ったので雑にまとめました。

2021/02/11現在、「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 が生成されます。
f:id:vraisamis:20210211064730p:plain

ファイル名をクリックすると、ファイルごとのカバレッジが表示されました。 f:id:vraisamis:20210211064918p:plain

ついでに: オプション管理

出力形式オプションとセットで管理するなら、 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する必要ない気がするのですが、しないとできませんでした。バグか仕様かは未調査です)