2016年10月14日金曜日

単体テストフレームワーク CUnit


Javaでコードをテストするときには JUnitを使用しているが、C/C++でもそのようなのがあったら便利だと思った。
2006年ごろ、自社製(まだ会社設立前だったが)の Java VM(TCK通してないので、公式には“もどき”)の品質が悪く、ちゃんと細部までテストをしたいなというのが始まりだった。
ネット上で検索すると沢山の CUnitが見つかり、そのうちのいくつかを試してみた。
しかし、どれもあまりパッとしなかった。 使いたくないと感じたのは、
  1. プロジェクトが放置されて久しいもの
  2. 完成度があまりにも低いもの
  3. 手続きが多くて使いにくいもの
  4. ドキュメントが全く無いもの
  5. エラーが発生したときの処理が貧弱なもの
  6. レポートを見て「ワクワク」しないもの

3の使いにくいとは、リポジトリとかテストスイートなどのオブジェクトを作り、テストケースを1個ずつ追加しなければならないのは、無精者の自分には向かないと思った。
テストケースを追加したのに、テストスイートに追加を忘れると、エラーにもならずに黙ってテスト漏れになってしまう。

しばらく我慢して使っていたがあまりにも作業効率が悪いので、自分も CUnitを作ろうということになった。(VM作りに集中せず、横道に逸れてしまうのだが)

今なら Google Testを使うでしょう。 Google Testレポートはワクワクしないけど、Softiesの CUnitの目標と共通している点も多い。 ただ当時は日文のドキュメントが多くなかったので Google Testは不採用とした。(なんと無謀な…。 皆さんは真似してはいけません。時間の無駄です。 Google Testを使いましょう。)

CUnitの目標は
  1. JUnitライクとする。(Cではアノテーションができないので 3.8ベース)
  2. リポジトリやスイートはデフォルトで不要または自動とする。
  3. JUnit同様、テスト関数の結果が他のテスト関数に影響しない。(ファイルや DBを除く)
  4. テスト中にエラーが発生してプロセスが停止しても、次にテスト関数は実行できること。
  5. 赤と緑を使った刺激的でモチベーションを維持できるレポートを出力できること。

では細かな機能紹介は別にするとして、テストケースの記述例とテストレポートのスナップショットをご覧頂きましょう。
(バージョンは違うが、以前、パッケージ一覧でも例示してある。)

テストケースのサンプル

テストプログラムの冒頭


テストケースの仕様をドキュメントコメント @fileタグで記述する。

スタブ(必要なときのみ)


フィクスチャ


テストケース


テスト関数の仕様をドキュメントコメントで記述する。
Assertクラスのコメントもテストレポートに引用される。

main関数


main関数はスタティックリンク(デフォルト)する場合に必要。
CUnitクラスの testメソッドを呼ぶだけのため、覚えるのは簡単。
main関数の中で argc, argvの内容を testメソッドを呼ぶ前に書き換えることも可能。

テストレポートのスナップショット

テストケース一覧


テスト関数一覧


テスト関数の実行結果(1)


テストレポートに事前条件の表示が無いため、事後条件の検証結果に唐突感がある。
事前条件の表示は今後の課題。
printf等で標準出力に出力した結果は、"stdout"に表示される。(この例では空)
標準エラー出力に出力した結果は、"stderr"に表示される。
malloc, free, reallocは追跡され、"heap"に表示される。 この例ではメモリリークが起きているがこれはテストケースでおきたものではなく、softiesが使用している libbfdのバグによるもの。
なお、softiesが未公開の理由の1つはこの libbfdが GPLライセンスであるため。 これを排除して softiesを公開する予定であるが、まだ時間を要する。

テスト関数の実行結果(2)


テストによりテキストファイルのほか、イメージや動画、オーディオファイルが出力されると、自動的にテストレポート中に表示される。

2 件のコメント:

  1. こんにちは。

    cunitでの取り組み、面白いですね!

    返信削除
    返信
    1. 師子乃さん、コメントありがとう。 アカウントのパスワード忘れて返信が遅くなりました。 cunitは同名のフレームワークがいくつも存在するようです。 私が使っているのは自社製のものです。最近は業務の関係で bashunitというのを作って使っています。

      削除