お手軽お気楽なWindows C/C++ テスト環境
επιστημη [著] 2008/03/18 14:00

サンプルファイル 10879.40 KB
1 2 3 →

はじめに

 単体テストを効率的に行うため、テスト対象となる言語に応じてさまざまなフレームワーク「xUnit」がリリースされています。例えばJavaならJUnit、.NETならNUnit、CならCUnit、C++ならCppUnitあたりがそれぞれの代表格といったところでしょうか。

 マイクロソフトのオンラインマガジン「MSDNマガジン2008年2月号」で、Windows環境に特化したC/C++対応の単体テストフレームワーク「WinUnit」が紹介されています。実行環境がWindowsに限定されてはいるものの、それを補って余りある使い勝手の良さを実現しています。

CUnit/CppUnitの問題点

 CUnitによる単体テストの例を示します。

CUnitによるテストコード
#include <CUnit.h>
#include "Car.h"
#include <stdio.h>

Car c;

int car_setup(void) {
  c = car_new(50,2);
  return c != NULL ? 0 : 1;
}

int car_teardown(void) {
  car_delete(c);
  return 0;
}

void test_car_init(void) {
  CU_ASSERT_EQUAL(car_distance(c), 0);
  CU_ASSERT_EQUAL(car_remain(c), 0);
}

void test_car_refuel(void) {
  car_refuel(c, 20);
  CU_ASSERT_EQUAL(car_remain(c), 20);
  car_refuel(c, 20);
  CU_ASSERT_EQUAL(car_remain(c), 40);
  car_refuel(c, 20);
  CU_ASSERT_EQUAL(car_remain(c), 50);
}

/*
 * test-suitの構築と実行
 */
static CU_TestInfo test_car[] = {
  { "初期化", test_car_init },
  { "給油",   test_car_refuel },
  CU_TEST_INFO_NULL,
};

static CU_SuiteInfo suites[] = {
  { "Carのテスト",  car_setup, car_teardown, test_car },
  CU_SUITE_INFO_NULL,
};

#include <Basic.h>

int main() {
  CU_initialize_registry();
  CU_register_suites(suites);
  CU_basic_set_mode(CU_BRM_VERBOSE);
  CU_basic_run_tests();
  CU_cleanup_registry();
  return 0;
}

 このコード、中ほどの/* --- */以降の部分はテストそのものではありません。いくつものテスト関数をまとめたスイートを組み上げ、スイート内のテスト関数を順に呼び出してはその結果を収集する(ライブラリ提供の)実行ルーチンを起動しています。テストの追加/削除あるいはテスト関数名の変更に伴ってスイート組み上げ部の修正が必要となります。そのためスイートの修正漏れがあると、コンパイル/リンクエラーとなったり、追加したテストが実行されません。

 かたやこちらは同じテストをNUnit(C++/CLI)で書いたもの。スイートの組み上げやテスト実行部がありません。

NUnitによるテストコード
#include "Car.h"

using namespace System;
using namespace NUnit::Framework;
using namespace NUnit::Framework::SyntaxHelpers;

namespace TestByNUnit {

  [TestFixture]
  public ref class CarTest {
    Car c;
  public:
    [SetUp]
    void SetUp() { c = car_new(50,2); }

    [TearDown]
    void TearDown() { car_delete(c); }

    [Test]
    void init() {
      Assert::That(car_distance(c), Is::EqualTo(0));
      Assert::That(car_remain(c), Is::EqualTo(0));
    }

    [Test]
    void refuel() {
      car_refuel(c, 20);
      Assert::That(car_remain(c), Is::EqualTo(20));
      car_refuel(c, 20);
      Assert::That(car_remain(c), Is::EqualTo(40));
      car_refuel(c, 20);
      Assert::That(car_remain(c), Is::EqualTo(50));
    }
  };

}

 Javaや.NETには生成されたバイトコードやアセンブリからクラス名、メソッド名、引数などを抽出し、インスタンスの生成とメソッドの呼び出しが可能です。JUnit、NUnitは「リフレクション」と呼ばれるこの機能を使ってテストを抽出/実行できるのですが、ネイティブコードを生成するC/C++はリフレクションを持ち合わせていないので、テストスイートの組み立ておよびテストの実行をソースコード内に置いておかなければなりません。

 本稿で紹介するWinUnitはテストコードからDLLを生成することで(簡易版の)リフレクションを実現しています。DLLは他のEXEやDLLから呼び出せるよう、関数名がその内部に埋め込まれています。WinUnitのテスト実行アプリケーション「WinUnit.exe」は、実行時に指定されたDLL内からテスト関数を抽出し呼び出してくれるので、テストコード中のスイート組み上げやテスト実行部(すなわちmain)を必要としないのです。

 Windowsという限られた環境に限定されるものの、CUnit、CppUnitに比べ使い心地/お手軽さが大きく向上しています。


1 2 3
→
INDEX
C/C++に対応した、もうひとつのUnitTestFramework ─ WinUnit
Page1
はじめに
CUnit/CppUnitの問題点
前準備
テストの書き方
VisualStudio からのテスト実行
提供されるASSERT群
おまけとまとめ
プロフィール
επιστημη エピステーメー

C++に首まで浸かったプログラマ。

Microsoft MVP, Visual C++ (2004.01~) だったり
わんくま同盟blog書いてたり
中国茶淹れてにわか茶人を気取ってたり。
 


注目の求人情報
システムエンジニア/IT事業拡大中のベンチャー企業
Web・オープン系システムの設計・開発 開発・テスト・保守業務。使用言語はJava等。...
プログラマ/通販専門Webコンサル企業
PHPでのプログラミング
ビジネス戦略・事業運営/ソーシャルアプリケーション開発会社
社長と一緒に会社の事業戦略を決め、それに責任を持ち、遂行していくのがミッションです。 ...

(最新日付順)
名前(ゲストの方もコメントをどうぞ):*
アイコン:
なし

内容(テキストのみ1200文字まで):*

投稿規定に同意して

スポンサーサイト

この記事のトラックバックURL: