OpenCppCoverageとは
アプリケーションにせよライブラリにせよ、プログラムを書いたらテストします。思ったとおりに動くことを確認するのがテストの目的ですが、テストにはいくつか弱点があります。ひとつは「それが正しいテストであることを保証できない」こと。テストはテストできませんから。そしてもうひとつは「テストに抜けがないことを保証できない」こと。前者については与えられた仕様とテストとが合致するかを確認することになります。後者はかなり厄介です。プログラム中に分岐がn個あったとすると、テストの総数は最大2^n通りになるわけで、とてもじゃないですがそれらすべてを列挙しテストに反映できる数ではありません。
そこでテスト戦術を考えます。ひとまず考え付く限りのテストを行い、そのテストによって通過したコード上の行を緑で塗りつぶします。一連のテストを実行し、緑に塗られていない行は現テストではカバーできていないのですから、その行を通過するテストを追加します。これを繰り返し、塗り残された行がなくなれば実装したすべての行をテストによって通過した(=実行した)ことになります。正しい実装か否かは別として、少なくともテストしていない行はないことが保証されます。歯医者さんがくれる赤い染料みたいなものです。磨き残しがある箇所を探し、そこをちゃんと磨きましょう、と。
カバレージ(網羅度)を計測するツールはLinux g++/gccなら処理系にはじめっからオマケでついてきます。コンパイル/リンク時にオプション:--coverageを付けておくとコンパイル単位ごとにファイル:~.gcnoが生成されます。どうやらこいつは生成された機械語と、それに対応するソースコードのファイル名/行番号との対応表らしい。実行すると~.gcdaが生成され、オマケのツール:gcovがgcnoとgcdaからコードの各行を通過した回数を勘定するってカラクリ。
このgcovと同様の機能、Visual StudioではUltimateとかEnterpriseとか、かなりお高いエディションでしか提供されていないんですよ。残念なことに。
Communityエディションにも使え、しかも無償のカバレージ・ツールがないものかと探してみたらありました。OpenCppCoverageという代物で、Visual Studioのメニュー:"拡張機能と更新プログラム"からプラグインがインストールできます。
マニュアルやソースコード一式はGithubから入手できます。コマンドライン版も32bit/64bitの両方あって、64bit版は32bitアプリのカバレージ計測もできるみたいです。さっそくお味見してみましょうか。
カバレージ計測対象の準備
おためしに用意したのはちいさな関数をひとつだけ定義したDLL:calcです。足し算の繰り返しでふたつのint値の積を求めるint multiplies(int x、int y)を実装しました。
#ifndef CALC_H__ #define CALC_H__ #ifdef CALC_IMPL #define CALC_DLL __declspec(dllexport) #else #define CALC_DLL __declspec(dllimport) #endif #ifdef __cplusplus extern "C" { #endif CALC_DLL int multiplies(int x, int y); #ifdef __cplusplus } #endif #endif
#define CALC_IMPL #include "calc.h" /* * 加算の繰り返しによってふたつの int の積を求める */ CALC_DLL int multiplies(int x, int y) { // x回、result += y; するが そのまえに... // x, y それぞれ、負ならば符号反転する bool negative = false; if ( x < 0 ) { negative = !negative; x = -x; } if ( y < 0 ) { negative = !negative; y = -y; } int result = 0; /* * loop回数を減らすため x > y であるときは x と y を交換する */ if ( x > y ) { int tmp = x; x = y; y = tmp; } for ( int i = 0; i < x; ++i ) { result += y; } if ( negative ) { result = -result; } return result; }
Visual Studio 2017 CommunityでVisual C++ DLLプロジェクトのひな型を作り、上記calc.h/cppを追加してx64/Releaseモードでビルドしました。DLLですからdllmain()が定義されたdllmain.cppもプロジェクトに含まれています。
次にテスト。テストは何度となく使って手慣れたgoogle testを使います。Linux g++/gccでのお仕事も少なくないのでWindows/Linuxの両方で使えるgoogle testは僕のお気に入りです。
まずはともあれ"にさんがろく"をテストしましょう。コンソールアプリ・プロジェクト:calc_testを用意しテストをひとつ書きます。
#include <gtest/gtest.h> #include "calc.h" TEST( multiplies,get_start ) { ASSERT_EQ(6, multiplies( 2, 3)); }