Mobil einternetaplチーム CppUnit を使用した VisualC++ プロジェクト作成方法 Version:1.0 Date:2004/08 /05
----- ---------------------- ---------------------- ------------------------------------------- 使用上の注意 以下は当文書を利用するにあたっての注意事項です 以下について了承されない方は 速やかに当文書を破棄して下さい 以上 当文書中のすべての情報について! その正確性 有効性は十分配慮していますが 不正確な内容がある可能性があります それら情報の使用の際に生じた損害等については一切の責任は負わないことをご了承下さい Copyr ight 2003-2004 Fujis ystems Inc.,AllRights Reserved. ----- ---------------------- ---------------------- -------------------------------------------
ChangeHistory Date New Category Section Changes Changedby Ver 2004/ 08/051.0 A - 新規作成上野 Category[A:Added,U:Updated,D:Deleted]
目次 1 はじめに... 1 1.1 参考文献... 1 1.2 略語一覧... 1 2 基本方針... 2 3 CppUnit の環境構築... 3 4 Visual C++ 6.0 の設定... 4 5 実プロジェクトの作成... 6 6 テストプロジェクトの作成... 9 7 テストクラスの作成... 13 8 テストプロジェクトに実プロジェクトを追加... 16 9 テストコードの記述... 17 10 実クラスの作成... 19 11 TIPS... 21 11.1 リソースの競合... 21 11.2 MFC のソケットクラスの使用... 23
1 はじめに 本ドキュメントは CppUnit を使用した テストファースト なプロジェクトを MicrosoftVisualC++6.0 (SP5) にて実現させる場合の導入指南書となることを目的としています 実プロジェクトの導入の参考になれば幸いです 1.1 参考文献 [1] 大月美佳著 CPPUNIT による実践テスト技法 秀和システム 2003/07/20 1.2 略語一覧 VC MFC XP URL SDI MDI RTTI 略語 説明 MicrosoftVisualC++6.0 MicrosoftFoundationClass extremeprogramming UniformResourceLocator SingleDocument Interface MultipleDocumentInterface Run-TimeTypeInformation 1
2 基本方針 実プロジェクトとテストプロジェクトを分離する テストコードは非常に有用なものですが 実際のプログラムの動作には必要ありません このため 実プロジェクトのみ納品できるようにプロジェクトを 2 つに分離します UI のテストは自動化しない UI( ユーザインターフェース ) のテストは CppUnit による自動化テストには不向きですので テスト対象外とします ( 例えば XP の場合なら ユーザによる受入テストで実施すべきものです ) つまり テストプロジェクトはコンソールアプリケーションで十分 ということになります MFC の使用について MFC の使用 不使用に関係なく CppUnit を導入することが可能です 以上を踏まえ 本ドキュメントでは以下のような開発環境を構築することとします C: CppUnit CppUnit インストールフォルダ Project VCプロジェクトルートフォルダ Real 実プロジェクトフォルダ (MFCAppWizard(exe) で作成 ) Test テストプロジェクトフォルダ (Win32ConsoleApplicationで作成) また 実クラスとして Dummy テストクラスとして testdummy クラスを作成します Dummy は引数で与えられた自然数を素数であるかどうか判断する isprimenumber 関数を持ちます なお 一度でも CppUnit を導入したことのある環境の場合 3 4 章は飛ばして下さい 2
3 CppUnit の環境構築 CppUnit を以下の URLからダウンロードします https://sourceforge.net/project/showfiles.php?group_id=1795 (2004 /08/05 現在 最新版はバージョン1.10.2 ファイル名は cppunit-1.10.2.tar.gz) ダウンロードしたファイルを解凍し 上記フォルダ (C: CppUnit) にコピーします examples フォルダにある VC 用のプロジェクトファイル (C: CppUnit examples examples.dsw) を開きます 図 3-1examples プロジェクト メニューの ビルド バッチビルド を選択し すべてのチェックが入っているのを確認してから リビルド を実行します 図 3-2 バッチビルド lib フォルダ (C: CppUnit lib) に各環境用の dll や lib exeファイルが作成されたことを確認します 3
4 Visual C++ 6.0 の設定 VC を起動し メニューの ツール オプション を選択します ディレクトリ タブから表示するディレクトリの インクルードファイル を選択し ディレクトリに C: CppUnit include を追加します 図 4-1 参照するインクルードディレクトリ 同じく 表示するディレクトリの ライブラリファイル を選択し ディレクトリに C: CppUnit lib を追加します 図 4-2 参照するライブラリディレクトリ 4
同じく 表示するディレクトリの ソースファイル を選択し ディレクトリに C: CppUnit src cppunit を追加します OK ボタンを押下します 図 4-3 参照するソースディレクトリ 5
5 実プロジェクトの作成 メニューの 新規作成 を選択します プロジェクト タブから MFCAppWizard(exe) を選択し プロジェクト名に Real 位置に C: Project Real を入力してから OK ボタンを押下します 図 5-1 実プロジェクト作成 必要な情報を Wizard の指示に従って入力し プロジェクトを作成します なお アプリケーションの種類 (SDI/MDI/ ダイアログベース ) や各種設定に CppUnit は全く依存しません 6
メニューの プロジェクト 設定 を選択します 設定の対象で すべての構成 を選択します C/C++ タブから C++ 言語 カテゴリを選択し ランタイムタイプ情報 (RTTI) を有効にする にチェックを入れます 図 5-2 ランタイムタイプ情報を有効にする 7
設定の対象で Win32Debug を選択します C/C++ タブから コード生成 カテゴリを選択し 使用するランタイムライブラリが マルチスレッド (DLL デバッグ ) になっていることを確認します 設定の対象で Win32Release を選択します 図 5-3 マルチスレッドであることを確認 C/C++ タブから コード生成 カテゴリを選択し 使用するランタイムライブラリが マルチスレッド (DLL) になっていることを確認します OK ボタンを押下し ここでビルドします 成功することを確認したら 一度プロジェクトファイルを閉じます 8
6 テストプロジェクトの作成 メニューの 新規作成 を選択します プロジェクト タブから Win32ConsoleApplication を選択し プロジェクト名に Test 位置に C: Project Test を入力してから OK ボタンを押下します 図 6-1 テストプロジェクト作成 アプリケーションの種類で MFC をサポートするアプリケーション を選択し 終了 ボタンを押下します 図 6-2MFC をサポート 9
メニューの プロジェクト 設定 を選択します 設定の対象で すべての構成 を選択します C/C++ タブから C++ 言語 カテゴリを選択し ランタイムタイプ情報 (RTTI) を有効にする にチェックを入れます C/C++ タブから プリプロセッサ カテゴリを選択し インクルードファイルへのパスに.. Real を入力します 図 6-3 インクルードパスの追加 10
ビルド後の処理 タブからビルド後の処理の説明に TestStart!! ビルド後の処理コマンドに $(TargetPath) を入力します 図 6-4 ビルド後にテストを自動的に実行 11
設定の対象で Win32Debug を選択します C/C++ タブから コード生成 カテゴリを選択し 使用するランタイムライブラリが マルチスレッド (DLL デバッグ ) になっていることを確認します リンク タブから 一般 カテゴリを選択し オブジェクト / ライブラリモジュールに cppunitd.lib を追加します ( d 付きはデバッグ環境用 ) 設定の対象で Win32Release を選択します 図 6-5CppUnit のスタティックライブラリを追加 C/C++ タブから コード生成 カテゴリを選択し 使用するランタイムライブラリが マルチスレッド (DLL) になっていることを確認します リンク タブから 一般 カテゴリを選択し オブジェクト / ライブラリモジュールに cppunit.lib を追加します ( d なしはリリース環境用 ) OK ボタンを押下します 12
7 テストクラスの作成 ワークスペースウィンドウの Test クラス を右クリックし サブメニューの クラスの新規作成 を選択します 図 7-1 クラスの新規作成 クラスの種類に Generic クラス クラス名に testdummy 基本クラスの派生元に CppUnit:TestFixture と入力し OK ボタンを押下します 図 7-2testDummy クラスの新規作成 13
テストクラスのヘッダファイル (testdummy.h) を以下のように編集します #include<cppunit/extensions/helpermacros.h> classtestdummy:publiccppunit:testfixture { CPPUNIT_TEST_SUITE(testDummy);// 自クラス名を引数に入力 CPPUNIT_TEST(test); // テスト関数名を引数に入力 ( 複数可 ) CPPUNIT_TEST_SUITE_END(); public: testdummy(); virtual~testdummy(); voidsetup(){ // 実クラスのインスタンス作成 voidteardown(){ // 実クラスのインスタンス削除 voidtest(); // テスト関数 ; テストクラスのソースファイル (testdummy.cpp) を以下のように編集します // テスト関数 voidtestdummy:test() { CPPUNIT_ASSERT(FALSE); // わざと失敗させる メイン (_tmain) 関数のあるソースファイル (Test.cpp) を以下のように編集します #include<cppunit/ui/text/testrunner.h> #include<cppunit/compileroutputter.h> #include"testdummy.h" // テストクラス int_tmain(intargc,tchar*argv[],tchar*envp[]) { intnretcode=0; //MFC の初期化および初期化失敗時のエラーの出力 if(!afxwininit(:getmodulehandle(null),null,:getcommandline(),0)) { //TODO: 必要に応じてエラーコードを変更してください cer<<_t("fataleror:mfcinitializationfailed")<endl; nretcode=1; else { 14
// ユニットテストを実行する CppUnit:TextUi:: TestRunnerrunner; runer.addtest(testdummy:suite()); // テストクラス ( 複数可 ) CppUnit:Outputer*outputer = CppUnit:: CompilerOutputter:: defaultoutputter(&runer.result(),std:: cout); runer.setoutputer(outputer); nretcode=!(runner.run()); returnnretcode; ここでビルドします ビルドをするとユニットテストを自動的に実行します アウトプットウィンドウに以下のように出力されていれば つまりユニットテストが実行され かつテストに失敗することが確認できれば ここまでは成功です コードを生成中... リンク中... TestStart!!.F C: Project Test testdummy.cpp(32):assertion Testname:testDummy:: test assertionfail ed -Expression:FALSE Fail ures!!! Run:1 Failuretotal:1 Fail ures:1 Errors: 0 c: winnt system32 cmd.exe の実行エラー Test.exe - エラー 1 警告 0 15
8 テストプロジェクトに実プロジェクトを追加 メニューの プロジェクト プロジェクトをワークスペースへ挿入 を選択します 実プロジェクト (C: Project Real Real.dsp) を選択し 依存関係 にチェックを入れてから OK ボタンを押下します 図 8-1 テストプロジェクトに実プロジェクトを追加 16
9 テストコードの記述 アクティブプロジェクトを Test に変更します テストクラスのヘッダファイル (testdummy.h) を以下のように編集します #include"dummy.h" classtestdummy:publiccppunit:testfixture { CPPUNIT_TEST_SUITE(testDummy);// 自クラス名を引数に入力 CPPUNIT_TEST(test); // テスト関数名を引数に入力 ( 複数可 ) CPPUNIT_TEST(testisPrimeNumber); CPPUNIT_TEST_SUITE_END(); public: testdummy(); virtual~testdummy(); voidsetup(){ target=newdummy; // 実クラスのインスタンス作成 voidteardown(){ // 実クラスのインスタンス削除 deletetarget; voidtest(); // テスト関数 voidtestisprimenumber(); // 素数判定テスト関数 private: Dummy*target; ; // 実クラスへのポインタ テストクラスのソースファイル (testdummy.cp) を以下のように編集します // テスト関数 voidtestdummy:test() { CPPUNIT_ASSERT(TRUE); // 必ず成功させる // 素数判定テスト関数 voidtestdummy:testisprimenumber() { BOOLbRet; bret=target->isprimenumber (0);//0 は素数ではない CPPUNIT_ASSERT(!bRet); 17
bret=target->isprimenumber (1);//1 は素数ではない CPPUNIT_ASSERT(!bRet); bret=target->isprimenumber (2);//2 は素数 CPPUNIT_ASSERT(bRet); bret=target->isprimenumber (4);//4 は素数ではない CPPUNIT_ASSERT(!bRet); ここでビルドし リンクエラーになることを確認します 18
10 実クラスの作成 ワークスペースウィンドウの Real クラス を右クリックし サブメニューの クラスの新規作成 を選択します クラスの種類に Generic クラス クラス名に Dummy と入力し OK ボタンを押下します 実クラスのヘッダファイル (Dummy.h) を以下のように編集します classdummy { public: Dummy(); virtual~dummy(); BOOLisPrimeNumber(intnNumber); ; 実クラスのソースファイル (Dummy.cpp) を以下のように編集します // 素数判定 BOOLDummy::isPrimeNumber(intnNumber) { if(nnumber<=0) { returnfalse; //0 は素数でない if(nnumber==1) { returnfalse; //1 は素数でない intnloop=nnumber/2; for(inti=2;i<=nloop;i++) { if(nnumber%i==0) { returnfalse; // 割り切れれば素数ではない returntrue; // 割り切れなければ素数 19
ここで最大の注意点ですが Test プロジェクトの方にも実クラスのソースファイル (Dummy.cpp) を追加する必要があります 一番簡単な方法はソースファイルの編集ウィンドウで右クリックをし サブメニューの プロジェクトへファイルの挿入 Test を選択することです それではビルドします 図 10-1 実クラスのソースファイルをテストプロジェクトに追加 アウトプットウィンドウに以下のように出力されていれば すべて成功です コードを生成中... リンク中... TestStart!!. OK (2) Test.exe - エラー 0 警告 0 20
11 TIPS ここでは 実際のプロジェクトで起こったトラブルと その回避方法を紹介します 11.1リソースの競合ユニットテストではテストプロジェクトから実プロジェクト内のクラスを呼び出すことになりますが 例えば実プロジェクトで CString:: LoadString() などのリソースを参照しているコードがあった場合 テストプロジェクト側のリソースを参照しに行ってしまい エラーが発生する可能性があります この問題を回避するために リソースファイルおよびResource.h をプロジェクト間で共有する方法を示します アクティブプロジェクトをテストプロジェクトに変更します ワークスペースウィンドウの FileView から テストプロジェクトのリソースファイル (Test.rc) および Resource.h を削除します ResourceView でリソースが削除されているのを確認します 図 11-1Test リソースが削除されている 21
メニューの プロジェクト プロジェクトへ追加 ファイル を選択し 実プロジェクトのリソースファイル (Real.rc) を追加します Fil eviewで確認します 図 11-2 実プロジェクトのリソースをテストプロジェクトに追加 図 11-3 実プロジェクトのリソースがテストプロジェクトに追加されている ただし こうするとテストプロジェクト用のリソースが扱えなくなります テストプロジェクトを MFCAppWizard など UI 付きで作成する場合は 面倒でも対象リソースを二重化する必要があります 22
11.2MFC のソケットクラスの使用 CAsyncSocket など MFC のソケットクラスを実プロジェクトで使用している場合 ユニットテストでエラーが発生する可能性があります これはソケットの初期化関数をテストプロジェクトで呼び出していない場合に発生します この問題はメイン関数にてユニットテストを実行する前に 以下のようなコードを追加することで解決します #include<afxsock.h> int_tmain(intargc,tchar*argv[],tchar*envp[]) { intnretcode=0; //MFC の初期化および初期化失敗時のエラーの出力 if(!afxwininit(:getmodulehandle(null),null,:getcommandline(),0)) { //TODO: 必要に応じてエラーコードを変更してください cer<<_t("fataleror:mfcinitializationfailed")<<endl; nretcode=1; else { //MFC のソケットを初期化する if(!afxsocketinit() { cer<<_t("fataleror:afxsocketinit") <<endl; return1; // ユニットテストを実行する CppUnit:TextUi:: TestRunnerrunner; runer.addtest(testdummy:suite()); // テストクラス ( 複数可 ) CppUnit:Outputer*outputer = CppUnit:: CompilerOutputter:: defaultoutputter(&runer.result(),std:: cout); runer.setoutputer(outputer); nretcode=!(runner.run()); returnnretcode; 23