mozilla/grcovを使ったRustのテストカバレッジ計測
普段、Rustでのテストカバレッジ計測はどのように行っていますか?
kennytm/cargo-kcovやxd009642/tarpaulinを使っているケースが多いと思いますが、公式(?)の mozilla/grcov というツールもあります。これはFirefoxのカバレッジ計測のために始められたプロジェクトであり、今後も開発が安定して継続するだろうと期待できます。実際、頻繁にcommitされているのが見て取れます。
本記事では、そんなmozilla/grcovを使ったテストカバレッジ計測を簡単に行うシェルスクリプトを作成します。まだ成熟しておらず、しばらくすると使い方が変わっている恐れがありますので、利用する際は各自で確認しましょう。
準備
実行に際して必要なツールを用意します。
- grcov
- 本ツールです。
cargo install grcov
で簡単インストール
- 本ツールです。
- Nightlyのrust
- テストカバレッジ計測にはおなじみ、Nightly版が必要です。
rustup install nightly
で簡単
- テストカバレッジ計測にはおなじみ、Nightly版が必要です。
- lcov
- カバレッジレポートをHTMLにするために使います(
genhtml
)。Macならbrew install lcov
など
- カバレッジレポートをHTMLにするために使います(
実行
TL;DR
#!/usr/bin/env bash
set -eux
PROJ_NAME=$(cat Cargo.toml | grep -E "^name" | sed -E 's/name[[:space:]]=[[:space:]]"(.*)"/\1/g' | sed -E 's/-/_/g')
rm -rf target/debug/deps/${PROJ_NAME}-*
export CARGO_INCREMENTAL=0
export RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off -Zno-landing-pads"
cargo +nightly build --verbose
cargo +nightly test --verbose
grcov ./target/debug/deps -s . -t lcov --llvm --branch --ignore-not-existing --ignore-dir "/*" -o lcov.info
genhtml -o report/ --show-details --highlight --ignore-errors source --legend lcov.info
これをプロジェクトルートで叩くと、 report/index.html
にレポートが現れます。
詳細
grcovのREADME内のtravis版スクリプトを参考にしてシェルスクリプトを作ってゆきます。ゴールは「 叩くだけで計測レポートができあがる 」ことです。
まず、フラグを確認します。 CARGO_INCREMENTAL
と RUSTFLAGS
を設定し、計測に適切な設定を行っています。利用ケースによっては変更して下さい。
export CARGO_INCREMENTAL=0
export RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off -Zno-landing-pads"
フラグでnightlyの機能を使っているため、 +nightly
で利用するchannelを指定します。
cargo +nightly build --verbose
cargo +nightly test --verbose
testが完了したら、ようやく grcov
の出番です。 ./target/debug/deps
を指定しているのが少し意外ですが、 GCNA/GCNO
ファイルはこちらに生成されます。概要はcovで説明されていますので、樹になる方は一読ください。
grcov ./target/debug/deps -s . -t lcov --llvm --branch --ignore-not-existing --ignore-dir "/*" -o lcov.info
-o
で指定した箇所に一時ファイルが生成されます。このファイルをHTMLにして一般的な人間に読めるようにします。結果は -o
で指定したディレクトリに吐き出されます。
genhtml -o report/ --show-details --highlight --ignore-errors source --legend lcov.info
さて、ここまでの手順だけで上手く行けば良かったのですが、実際に運用すると、コード変更時にエラーが出ることに気づきます。
+ grcov ./target/debug/deps -s . -t lcov --llvm --branch --ignore-not-existing --ignore-dir '/*' -o lcov.info
Error in computing counters:
Unexpected number of edges (in xxx) in xxx
インクリメンタルにしてしまっているのでしょうか。毎回 cargo clean
をすると上手く動きますが、依存関係の再ビルドを行うため非常に長い時間がかかり実用的ではありません。原因を掴みかねた(ご存知の方はぜひコメントください)ので、とりあえず下記のように 該当のGCNA/GCNOファイルを消す ことで対応しました。なお、汎用性を高めるため、 PROJ_NAME
は直書きではなく Cargo.toml
から取ってきています。
PROJ_NAME=$(cat Cargo.toml | grep -E "^name" | sed -E 's/name[[:space:]]=[[:space:]]"(.*)"/\1/g' | sed -E 's/-/_/g')
rm -rf target/debug/deps/${PROJ_NAME}-*
場合によってはこれでも上手くいかない可能性はあるので、ビルド速度が重要でない場合は毎度 cargo clean
を事前に走らせるのが良いでしょう。
これで完成です。以上をまとめると、TL;DRで示したシェルスクリプトになります。
まとめ
mozilla/grcovを使ってテストカバレッジを計測するスクリプトを作製しました。変更した場合も依存関係の再ビルドは行われないので、実用的なスピードで計測ができると考えられます。grcovは盛んに開発が行われているので、今後も追いかけてゆきたいです。