kcovを使ってRustプログラムのカバレッジを測定する

本記事は Rust Advent Calendar 2015 13日目の記事です。

前置き

Rust 1.5リリースおめでとうございます!!! cargo install の登場により、Rust製ツール群のインストールが飛躍的に楽になりました。最近のアップデートに追従できていなかったという方も、是非是非ダウンロードしてみてください。

背景

Rustには、 言語組み込みのユニットテスト機能 や、cargo test のインテグレーションテストサポートなど、テストを実行させる方法は充実しているのですが、gcov相当のカバレッジ採取機能については、 2015年12月時点では残念ながらサポートされていません (RFCリポジトリにIssueはあります)。しかし、Rust にはプログラムのDWARF情報 (デバッグ情報) を生成する機能があるため、 kcov というプログラムを利用することでカバレッジを採取することが可能です。

本記事では、 kcov を利用して Rust プログラムのカバレッジを測定する方法について説明します。

kcov のインストール

ディストリビューションでバイナリが配付されていない場合、ソースコードからビルドすることになります。 以下に載っているコマンドラインを参考にしてみてください。

kcov を使う

cargo test --no-runデバッグシンボルのついたテスト用実行ファイルを作成し、kcov 経由で実行します。

$ cargo test --no-run
$ kcov target/cov target/debug/$TEST_EXECUTABLE

上記実行すると、 target/cov ディレクトリ配下にカバレッジ測定結果を格納したHTMLファイルが生成されます。 デフォルトでは、 ~/.cargo 配下のファイル (Cargo.toml で依存関係として指定したライブラリ) についてもカバレッジ測定対象となってしまうため、邪魔であれば以下のように --exclude-pattern オプションを指定することで、カバレッジ測定対象を絞ることが出来ます。

$ kcov --exclude-pattern=/.cargo target/cov target/debug/$TEST_EXECUTABLE
# multirust を使っている場合、以下
$ kcov --exclude-pattern=/.multirust target/cov target/debug/$TEST_EXECUTABLE

また、kcov複数回実行した場合、カバレッジ情報が蓄積されていきます。引数などの条件を変えて何度もコマンドを実行し、それらの結果を合算することなどが可能です。

$ kcov --exclude-pattern=/.cargo target/cov target/debug/$TEST_EXECUTABLE
$ kcov --exclude-pattern=/.cargo target/cov target/debug/$TEST_EXECUTABLE --ignored

Coveralls との連携

Coveralls とは、 GitHub (BitBucketも?) で開発しているソースコードのテストカバレッジを表示してくれるサービスです。 Travis CI と連携して利用します。

kcov には測定したカバレッジCoveralls へと送信してくれる機能があり、.travis.yml 上で kcov を以下のように呼び出すよう設定するだけで Coveralls を利用できます。

$ kcov --coveralls-id=${TRAVIS_JOB_ID} target/cov target/debug/$TEST_EXECUTABLE

ただし、Travis CI にはデフォルトで kcov はインストールされていないため、 .travis.yml 中で kcov をインストールしてやる必要があります。

language: rust
sudo: false
addons:
  apt:
    packages:
      - libcurl4-openssl-dev
      - libelf-dev
      - libdw-dev
before_script:
  - |
      if [ "${TRAVIS_OS_NAME}" = "linux" ]; then
        export KCOV="${TRAVIS_BUILD_DIR}/kcov/build/src/kcov --exclude-pattern=/.cargo --coveralls-id=${TRAVIS_JOB_ID} ${TRAVIS_BUILD_DIR}/coverage"
        wget https://github.com/SimonKagstrom/kcov/archive/master.zip
        unzip master.zip
        mv kcov-master kcov
        mkdir kcov/build
        cd kcov/build
        cmake ..
        make
        cd ${TRAVIS_BUILD_DIR}
      fi
script:
  - ${KCOV} target/debug/$TEST_EXECUTABLE

すこしめんどくさいですね。

travis-cargo を使う

すべての Rust プロジェクトの .travis.yml に kcov のインストール手順を書くのは面倒だというあなたのために、 travis-cargo という便利ツールが公開されています。 rustdoc の生成物を github.io にアップロードするなど、カバレッジ生成採取の便利な機能も搭載されています。

一部、travis-cargo では実現できないこともあるのですが (cargo test で生成されるバイナリ以外のカバレッジ採取する場合など)、多くの場合、 travis-cargo を使うのが便利だと思います。

最後に

筆者が公開している以下リポジトリでは、ビルド時にカバレッジを採取し、バッジとして README に表示しています。.travis.yml の書き方の参考にどうぞ。