header source
my icon
esplo.net
ぷるぷるした直方体
Cover Image for mozilla/grcovを使ったRustのテストカバレッジ計測

mozilla/grcovを使ったRustのテストカバレッジ計測

だいたい7分で読めます

普段、Rustでのテストカバレッジ計測はどのように行っていますか?

kennytm/cargo-kcovxd009642/tarpaulinを使っているケースが多いと思いますが、公式(?)の mozilla/grcov というツールもあります。これはFirefoxのカバレッジ計測のために始められたプロジェクトであり、今後も開発が安定して継続するだろうと期待できます。実際、頻繁にcommitされているのが見て取れます。

https://github.com/mozilla/grcov

本記事では、そんなmozilla/grcovを使ったテストカバレッジ計測を簡単に行うシェルスクリプトを作成します。まだ成熟しておらず、しばらくすると使い方が変わっている恐れがありますので、利用する際は各自で確認しましょう。

準備

実行に際して必要なツールを用意します。

  • grcov
    • 本ツールです。 cargo install grcov で簡単インストール
  • Nightlyのrust
    • テストカバレッジ計測にはおなじみ、Nightly版が必要です。 rustup install nightly で簡単
  • lcov
    • カバレッジレポートをHTMLにするために使います( genhtml )。Macなら brew install lcov など

実行

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_INCREMENTALRUSTFLAGS を設定し、計測に適切な設定を行っています。利用ケースによっては変更して下さい。

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は盛んに開発が行われているので、今後も追いかけてゆきたいです。

Share