OpenCppCoverageのつかいかた
当然のことながら"にさんがろく"ひとつではテストとしては穴だらけ、あちこちにあるはずの磨き残しをOpenCppCoverageで探し出しましょう。ちゃんとインストールされていればVisual Studio IDEの"ツール"メニューに"Run OpenCppCoverage"が追加されてるはず。クリックして現れたウィンドウ・ペインの[Run Coverage]ボタンを突っつくと、一連のテストののちにカバレージ計測結果ウィンドウが顔を出します。
このテストで実行されたModule(calc_test.exe、calc.dll)およびModuleを構成するファイルごとのカバレージが表示されてます。さらにここでテスト対象であるcalc.cppを突っつくと……。
通過した行は緑に、通過していない"磨き残し"が赤く染まります(コードをちょっとでも変更するとこの塗り分けは消失します)。この結果を頼りに、通過していない赤い行を通るテストを書き足していけばいい。テストの結果とカバレージが共にall-greenとなればテスト完了です。
Visual C++のオプション:/Zi付きでビルドすると、プログラムデータベース:PDBが生成されます。このPDBにはシンボル情報とともにソースコードのファイル/行とそれに対応する機械語アドレスとの対応表が納められています。Visual StudioはPDBを頼りにソースコード・デバッグを可能にしているのですが、OpenCppCoverageはカバレージの結果生成にこのPDBを利用しています。DLLプロジェクトでもPDBが出力されるのでカバレージが計測できます。アタマいいね。
OpenCppCoverage:Settingウィンドウの主要な設定項目を説明しておきます。
"Current Project"にはスタートアップに設定されたプロジェクト(ここではcalc_test)のパスがデフォルトでセットされます。それと同時に"Program to run"、"Arguments"、"Working Directory"にもスタートアップ・プロジェクトのデバッグ・プロパティに設定された各値が入ります。なのでカバレージ計測対象を変更するときはスタートアップ・プロジェクトを変更ののち[Reset to default]ボタンで再設定するのが妥当な使い方。
"Selected projects"にはソリューション内の全プロジェクトが列挙され、カバレージ計測対象にチェックが入ります。デフォルトでは全プロジェクトにチェックが入っています。このサンプルではgoogle testで書いたテストはカバレージの計測不要ですから、テスト対象であるcalcだけを残して他のはみんなチェックを外していいですね。
"Optimized Build":プロジェクトが-Od(最適化しない)以外の最適化オプションが設定されていた場合、ソースコードと生成された機械語とが大きく異なるためにコード行と機械語との対応がとれずに計測結果に狂いが生じることがあるんです。"Optimized Build"が有効であれば最適化されたコードに対しても正しく対応を付けようとがんばってくれるらしいです。64bit版であれば必ず有効になります。
"Compile before running":カバレージ計測に先立って必ずビルドします。
追加/除外するsource/moduleの設定ですが、ほとんど空欄で構いません。今回は"Excluded source Pattern"にひとつだけ追加しました。テスト対象プロジェクト:calcはcalc.cppとDLLには必須のdllmain()が定義されたdllmain.cppとで構成されています。このうちdllmainはカバレージを取っても意味がないのでExclude(除外)します。
別に計測したカバレージとまとめた結果を出力したいとき、Export Type:BinaryでExportしておいたカバレージをImportできますし、Export Type:Htmlを設定すれば計測結果がHTMLで得られます(日本語コメントがバケるのはご愛嬌)。
"Log verbosity":OpenCppCoverageは実行ログをコンソールに吐くんですよ。そのためコンソール・アプリケーションだと実行ログが出力と混ざって汚れてしまいます。
気になる方はQuietに設定してログを黙らせてください。
例外発生以降もカバレージ計測を続行するなら"Continue after C++ exception"をONにします。
各種設定のコマンドライン版での表現。コマンドライン版をお使いの際はこの出力が参考になりますね。
カバレージの問題
OpenCppCoverageの弱点をひとつ挙げるとすれば"行カバレージ"であることでしょうか。例えば
if ( ... ) { true節 } else { false節 }
のように一行で書かれていると、true節/false節のどちらか一方しか通っていなくても行カバレージとしては通過したと見なされてしまいます。横着せずにきちんと行を分けて書けば解決します。
さらに
if ( A && B ) { ... } if ( C || D ) { ... }
に対し、Aがfalse/Cがtrueなら短絡評価によってB/Dの評価は行われません。行カバレージではB/Dが評価されなかったことを検出できないんです。
もうひとつ、これはカバレージの本質的な問題なのですが、カバレージはあくまでソースコード中の未通過箇所を見つけるものであって、コードが正しいかすなわち設計に忠実に実装されているかを検証するものではありません。作られたものを漏れなく実行したかどうかを教えてはくれますが、思ったとおりに作られていることを検証してくれるわけではありません(それはテストの役目よね)。ココ大事。
ともかくも、OpenCppCoverageはとても簡単にアプリケーション/ライブラリのカバレージを計測できるツールです。テストが足りてないんじゃないかと不安を覚えたら、カバレージを計測してエビデンスを残しましょうね。