CppUnit 導入ガイド
ダウンロードとインストール
CppUnitは http://sourceforoge/projects/cppunit/ からダウンロードできます。2002.11時点での最新版は1.8.0(βは1.9.10)です。
zipもしくはtar+gzipで圧縮されているので、適当なディレクトリに展開してください。
以下の説明はWindows/Visual C++ v6.0 環境で、CppUnitのルート・ディレクトリを<CPPUNIT>と表記します。
ライブラリのビルド
CppUnitはツール/ユーティリティの類ではありません。テスト対象およびテストコードと一緒にリンクして実行モジュールを生成する’ライブラリ’です。
CppUnitは様々なOS/処理系に対応しており、その使用に先だってライブラリをビルドしなければなりません。
Visual Studio IDE から プロジェクト:<CPPUNIT>\src\CppUnitLibraries.dsw をオープンし、ビルド/バッチビルド-ダイアログからcppunitおよびcppunit_dllをチェックしてビルドします。
これによって、<CPPUNIT>\libに必要なライブラリ(とDLL)が生成されます。DLLはパスの通ったディレクトリにコピーしておくとよいでしょう。DLL版CppUnitはテストの実行モジュール・サイズを小さく抑えることができます。
cppunit/cppunit_dll以外のライブラリはMFC環境下でテスト結果をグラフィカルに表示するときに利用します。詳しくはCppUnitディストリビューションに同梱されているドキュメントをご覧ください。
テストコードの雛型
テストコードの雛型を示します。この雛型は様々なテストに応じて書き換えて利用してください。
XXXTest.cpp
/* * test skeleton XXXTest.cpp [1] */ // 必要なヘッダの #include [2] // ex. #include "XXX.h" #include <cppunit/extensions/HelperMacros.h> #include <cppunit/TestAssert.h> // XXX をテストする [3] class XXXTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(XXXTest); // [4] CPPUNIT_TEST(test_one); // [5] CPPUNIT_TEST(test_two); // [5] CPPUNIT_TEST(test_three); // [5] CPPUNIT_TEST(test_four); // [5] CPPUNIT_TEST(test_five); // [5] CPPUNIT_TEST(test_six); // [5] CPPUNIT_TEST_SUITE_END(); // [4] private: // 必要な メンバ変数/関数 [6] public: /* * コンストラクタ/デストラクタ [7] */ XXXTest() { } ~XXXTest() { } /* * 初期化/後始末 [8] */ virtual void setUp() { } virtual void tearDown() { } /* * テスト・ケース [9] */ void test_one() { CPPUNIT_ASSERT( 0 == 1 ); } void test_two() { CPPUNIT_ASSERT_MESSAGE( "0 is not equal to 1", 0 == 1 ); } void test_three() { CPPUNIT_FAIL( "never reached here!" ); } void test_four() { CPPUNIT_ASSERT_EQUAL( 0, 1 ); } void test_five() { CPPUNIT_ASSERT_EQUAL_MESSAGE( "1 is not equal to 0", 0, 1 ); } void test_six() { CPPUNIT_ASSERT_DOUBLES_EQUAL( 1.23, 1.24, 0.001 ); } }; /* * register test suite */ CPPUNIT_TEST_SUITE_REGISTRATION(XXXTest); // [10]
- [1] ファイル名
- 慣習的に、テスト対象であるモジュール名の末尾に’Test’を付加します。たとえば、’Counter’のテストコードは’CounterTest.cpp’のように。
- [2] インクルード
- 必要なインクルードをここに記述します。
- [3] テストクラス
-
テストクラスはテスト対象に対するテスト・ケースの集合体で、
ファイル名と同じクラス名とするのが望ましいでしょう。 - [4] テスト・スイート
-
CPPUNIT_TEST_SUITE(
テストクラス名);
とCPPUNIT_TEST_SUITE_END();
の間にテスト・ケースを記述します。 - [5] テスト・ケース(メソッド)の登録
-
CPPUNIT_TEST(
テスト・ケース名);
によって、テスト・ケースを登録します。 - [6] メンバ変数/関数
- 各テスト・ケースの実行に必要なメンバ変数/関数を宣言します。
- [7] コンストラクタ/デストラクタ
- 必要に応じ、コンストラクタ/デストラクタを定義します。なお、テストクラスのインスタンスは各テスト・ケース毎に生成されます。
- [8] 初期化/後始末
-
setUp
(初期化)とtearDown
(後始末)は、それぞれ各テスト・ケース実行の直前/直後に呼び出されます。 - [9] テスト・ケース(メソッド)
- テスト・ケースは引数/戻り値を持たないメソッドで、テスト項目毎に用意します。
- [10] テスト・スイート登録
-
CPPUNIT_TEST_SUITE_REGISTRATION(
テストクラス名);
によって、テスト・スイートが登録されます。
アサート・マクロ
各テスト・ケースの中では、テスト対象が正常に機能しているかを検証するコードを記述します。
以下のアサート・マクロが用意されています。
各アサート・マクロはそれぞれ特定の条件を満たさないとき、テスト失敗(failre)とみなしてそれ以降の処理をせずにテスト・ケースから脱出し、次のテスト・ケースに移ります。
CPPUNIT_ASSERT( condition );
- conditionが偽(false,0)であったとき、失敗します。
CPPUNIT_ASSERT_MESSAGE( message, condition );
- conditionが偽であったとき、失敗します。このときmessageを出力します。
CPPUNIT_FAIL( message );
- 必ず失敗します。messageを出力します。
CPPUNIT_ASSERT_EQUAL( expected, actual );
- 得られた結果actualが期待する値expectedでなかったとき、すなわちexpected != actualのときに失敗します。
CPPUNIT_ASSERT_EQUAL_MESSAGE( message, expected, actual );
- 得られた結果actualが期待する値expectedでなかったとき、すなわちexpected != actualのときに失敗します。このときmessageを出力します。
CPPUNIT_ASSERT_DOUBLES_EQUAL( expected, actual, delta );
- 得られた結果actualと期待する値expectedとの差がdeltaより大きいとき、失敗します。
メイン・ルーチン
以上のようにして作られたいくつかのテスト・スイートを実行し、その結果を出力するメイン・ルーチンの雛形を示します。
出力フォーマットに応じ、3種の雛形を用意しました。それぞれの出力結果をコードと併せて示します。
テキスト形式
#include <cppunit/ui/text/TestRunner.h> #include <cppunit/TextOutputter.h> #include <cppunit/extensions/TestFactoryRegistry.h> int main() { CppUnit::TextUi::TestRunner runner; runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest()); CppUnit::Outputter* outputter = new CppUnit::TextOutputter(&runner.result(),std::cout); runner.setOutputter(outputter); return runner.run() ? 0 : 1; }
!!!FAILURES!!! Test Results: Run: 6 Failures: 6 Errors: 0 1) test: XXXTest::test_one (F) line: 49 XXXTest.cpp assertion failed - Expression: 0 == 1 2) test: XXXTest::test_two (F) line: 53 XXXTest.cpp assertion failed - 0 is not equal to 1 3) test: XXXTest::test_three (F) line: 57 XXXTest.cpp forced failure - never reached here! 4) test: XXXTest::test_four (F) line: 61 XXXTest.cpp equality assertion failed - Expected: 0 - Actual : 1 5) test: XXXTest::test_five (F) line: 65 XXXTest.cpp equality assertion failed - Expected: 0 - Actual : 1 - 1 is not equal to 0 6) test: XXXTest::test_six (F) line: 69 XXXTest.cpp equality assertion failed - Expected: 1.23 - Actual : 1.24
コンパイラ出力形式
#include <cppunit/ui/text/TestRunner.h> #include <cppunit/CompilerOutputter.h> #include <cppunit/extensions/TestFactoryRegistry.h> int main() { CppUnit::TextUi::TestRunner runner; runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest()); CppUnit::Outputter* outputter = new CppUnit::CompilerOutputter(&runner.result(),std::cout); runner.setOutputter(outputter); return runner.run() ? 0 : 1; }
XXXTest.cpp(44):Assertion Test name: XXXTest::test_one assertion failed - Expression: 0 == 1 XXXTest.cpp(48):Assertion Test name: XXXTest::test_two assertion failed - 0 is not equal to 1 XXXTest.cpp(52):Assertion Test name: XXXTest::test_three forced failure - never reached here! XXXTest.cpp(56):Assertion Test name: XXXTest::test_four equality assertion failed - Expected: 0 - Actual : 1 XXXTest.cpp(60):Assertion Test name: XXXTest::test_five equality assertion failed - Expected: 0 - Actual : 1 - 1 is not equal to 0 XXXTest.cpp(64):Assertion Test name: XXXTest::test_six equality assertion failed - Expected: 1.23 - Actual : 1.24 Failures !!! Run: 6 Failure total: 6 Failures: 6 Errors: 0
XML形式
#include <cppunit/ui/text/TestRunner.h> #include <cppunit/XmlOutputter.h> #include <cppunit/extensions/TestFactoryRegistry.h> int main() { CppUnit::TextUi::TestRunner runner; runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest()); CppUnit::Outputter* outputter = new CppUnit::XmlOutputter(&runner.result(),std::cout); runner.setOutputter(outputter); return runner.run() ? 0 : 1; }
<?xml version="1.0" encoding='ISO-8859-1' standalone='yes' ?> <TestRun> <FailedTests> <FailedTest id="1"> <Name>XXXTest::test_one</Name> <FailureType>Assertion</FailureType> <Location> <File>XXXTest.cpp</File> <Line>49</Line> </Location> <Message>assertion failed - Expression: 0 == 1 </Message> </FailedTest> <FailedTest id="2"> <Name>XXXTest::test_two</Name> <FailureType>Assertion</FailureType> <Location> <File>XXXTest.cpp</File> <Line>53</Line> </Location> <Message>assertion failed - 0 is not equal to 1 </Message> </FailedTest> <FailedTest id="3"> <Name>XXXTest::test_three</Name> <FailureType>Assertion</FailureType> <Location> <File>XXXTest.cpp</File> <Line>57</Line> </Location> <Message>forced failure - never reached here! </Message> </FailedTest> <FailedTest id="4"> <Name>XXXTest::test_four</Name> <FailureType>Assertion</FailureType> <Location> <File>XXXTest.cpp</File> <Line>61</Line> </Location> <Message>equality assertion failed - Expected: 0 - Actual : 1 </Message> </FailedTest> <FailedTest id="5"> <Name>XXXTest::test_five</Name> <FailureType>Assertion</FailureType> <Location> <File>XXXTest.cpp</File> <Line>65</Line> </Location> <Message>equality assertion failed - Expected: 0 - Actual : 1 - 1 is not equal to 0 </Message> </FailedTest> <FailedTest id="6"> <Name>XXXTest::test_six</Name> <FailureType>Assertion</FailureType> <Location> <File>XXXTest.cpp</File> <Line>69</Line> </Location> <Message>equality assertion failed - Expected: 1.23 - Actual : 1.24 </Message> </FailedTest> </FailedTests> <SuccessfulTests></SuccessfulTests> <Statistics> <Tests>6</Tests> <FailuresTotal>6</FailuresTotal> <Errors>0</Errors> <Failures>6</Failures> </Statistics> </TestRun>