ユニットテストの実践: CppUnitの導入(実装編)
木曜日, 5月 1st, 2008 Posted in C++, CppUnitの導入 | 1 Comment »前回、CppUnitを導入しました。今回は実装編です。
本来はテストファーストで、CppUnitでテストケースを実装したあとにメインの実装を行うものなんでしょうけど、今回はすでに実装が終わったプロジェクトのユニットテストを行いました。今回作成したテストアプリはGUI版です。
まずはVCでプロジェクトを新規作成します。MFC AppWizard(exe)でダイアログベースで作成します。
[プロジェクト]-[設定]から[プロジェクトの設定]ダイアログを起動し、[C/C++]タブのカテゴリ[コード生成]で使用するランタイム ライブラリで[マルチスレッド(DLL、デバッグ)]を選択します。
同じく[C/C++]タブのカテゴリ[プロセッサ]インクルードファイルのパスに、メインのプロジェクトのパスを入力します。
[リンク]タブのカテゴリ[一般]オブジェクト・ライブラリ モジュールに、設定の対象がDebugの場合、
- cppunitd.lib testrunnerd.lib
Releaseの場合、
- cppunit.lib testrunner.lib
と入力します。
ここで、メインアプリのプロジェクトをワークスペースに追加しときます。そして[プロジェクト]-[依存関係]で、テストプロジェクトがメインプロジェクトに依存するように設定します。
テストアプリのStdAfx.hに次のincludeを記載します。
- #include <cppunit/ui/mfc/TestRunner.h>
- #include <cppunit/ui/text/TestRunner.h>
- #include <cppunit/extensions/TestFactoryRegistry.h>
- #include <cppunit/extensions/HelperMacros.h>
- #include <cppunit/CompilerOutputter.h>
C++アプリケーションの効率的なテスト手法(CppUnit編)なんかには、StdAfx.hは削除するとの記載がありますが、ボクの環境では削除しなくても問題ないです。てか削除するとダイアログベースのアプリなんでビルドできませんので。コンソールアプリの場合は必要ないでしょうね。
テストアプリのアプリクラス(CWinAppを継承しているクラス)のInitInstance()を次のように書き換えます。
- BOOL CTestApp::InitInstance()
- {
- AfxEnableControlContainer();
- #ifdef _AFXDLL
- Enable3dControls(); // 共有 DLL 内で MFC を使う場合はここをコールしてください。
- #else
- Enable3dControlsStatic(); // MFC と静的にリンクする場合はここをコールしてください。
- #endif
- CPPUNIT_NS::MfcUi::TestRunner runner;
- runner.addTest( CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest() );
- runner.run();
- return FALSE;
- }
メインプロジェクトのテスト対象となるクラスと対になるテスト用クラスを作成するのが流儀のようです。次のようなクラスを作成します。
- class CMainClass;
- class CTestClass : public CPPUNIT_NS::TestFixture
- {
- CPPUNIT_TEST_SUITE( CTestClass );
- CPPUNIT_TEST( testFunc1 );
- CPPUNIT_TEST( testFunc2 );
- CPPUNIT_TEST_SUITE_END();
- public:
- CTestClass();
- virtual ~CTestClass();
- void setUp();
- void tearDown();
- void testFunc1();
- void testFunc2();
- private:
- CMainClass* m_pApp;
- };
CPPUNIT_TEST_SUITEマクロとCPPUNIT_TEST_SUITE_ENDマクロの間にCPPUNIT_TESTマクロで、テスト対象となるテスト用の関数を登録します。setUp()はテスト用関数が実行される直前に呼ばれ、tearDown()はテスト終わったあとに呼ばれます。たとえばsetUp()でCMainClass* m_pAppをnewして、tearDown()でdeleteするような使い方になります。
では実装の方は、次のような感じ。
- CPPUNIT_TEST_SUITE_REGISTRATION( CTestClass );
- void CTestClass::setUp()
- {
- m_pApp = new CMainClass();
- }
- void CTestClass::tearDown()
- {
- delete m_pApp;
- }
- void CTestClass::testFunc1()
- {
- CPPUNIT_ASSERT_EQUAL( TRUE, m_pApp->Func1( 0 ) );
- CPPUNIT_ASSERT_EQUAL( FALSE, m_pApp->Func1( -1 ) );
- }
- void CTestClass::testFunc2()
- {
- CPPUNIT_ASSERT( m_pApp->Func2( 0 ) );
- CPPUNIT_ASSERT( m_pApp->Func2( -1 ) );
- }
CPPUNIT_ASSERT_EQUALは、第一引数と第二引数が等しい場合にテスト成功。違ったらテスト失敗となります。CPPUNIT_ASSERTは、引数がTRUEだったらテスト成功。FALSEだったらテスト失敗となります。ほかにも、
- CPPUNIT_ASSERT
- CPPUNIT_ASSERT_MESSAGE
- CPPUNIT_FAIL
- CPPUNIT_ASSERT_EQUAL_MESSAGE
- CPPUNIT_ASSERT_DOUBLES_EQUAL
などあります。ここでは詳しくは省略。
さて、ここでビルドするとリンクエラーが発生します。メインプロジェクトのCMainClass::Func1()やCMainClass::Func2()にリンクできないと。ここでしばらく悩みましたが、どうやらメインプロジェクトのCMainClassのCPPファイルを、テストプロジェクトに追加しないといけないようです。なんかこれ気持ち悪いんですけど。しょうがないんですかね。
これでちゃんとビルドが通ります。
実行するとダイアログが起動され、Browseからテストケースが確認できます。通常はALL Testsを選んでおいて、Autorun at startupにチェックを入れておけば、起動と同時にすべてのテストを実行してくれるので楽です。
【関連エントリ】
ユニットテストの実践: CppUnitの導入(インストール編)
ユニットテストの実践: CppUnitの導入(インストール編)
金曜日, 4月 25th, 2008 Posted in C++, CppUnitの導入 | 3 Comments »恥ずかしながら今までユニットテストツールを使ったことがなかったんですが、soraさんおすすめの、アジャイルプラクティス 達人プログラマに学ぶ現場開発者の習慣を読んだら、いても立ってもいられなくなり、会社の環境にCppUnitを導入しました。
CppUnitとは、C++のユニットテストを自動化してくれるステキなツールです。
導入編
導入に関しては、それほど難しくないです。ボクが今回入れた環境は、Visual C++ 6.0です。手順としては以下の通り。
CppUnitをダウンロード。実は去年の夏くらいにダウンロードしてましたが、当時は導入をあきらめてました。今回はこのときにダウンロードしたCppUnitを使いました。(cppunit-1.12.0.tar.gz)
ダウンロードしたファイルを解凍します。解凍先を\CppUnit\とします。
次のプロジェクトをVC6で開いてビルドします。
- \CppUnit\examples\msvc6\CppUnitTestApp\CppUnitTestApp.dsp
\CppUnit\lib以下にいろいろなDLLやらLIBやらが作成されます。ちなみにCppUnitTestAppはCppUnit自体のユニットテストです。実行するとGUIが表示されるのでいろいろいじってみましょう。
VCのメニュー[ツール]-[オプション]からオプションダイアログを開き、[ディレクトリ]タブの表示するディレクトリ[インクルードファイル]に
- \CppUnit\include
を、表示するディレクトリ[ライブラリファイル]に、
- \CppUnit\lib
を追加します。ここに設定したディレクトリはすべてのプロジェクトに適応されます。プロジェクトごとに設定したい場合は[プロジェクトの設定]ダイアログでやってください。また、次のファイルを\windows\system32の中へコピーしてください。
- testrunnerd.dll
- testrunner.dll
次回は実践編です。
【関連エントリ】
ユニットテストの実践: CppUnitの導入(実装編)