CppUTestを使ってみる
テストフレームワークの一つであるCppUTestを実機で動作させてみる。
ダウンロード
この辺りからダウンロードしてくる。執筆時点のバージョンは3.8だった。
ワークスペースの準備
ターゲットはTI社製Cortex-A8を搭載したBeagleBone(ブラックではない)で、開発環境はTI社謹製のCode Composer Studio v6.0.1(以下、CCSv6)でやってみる。(古くて申し訳ないが筆者が一番使っている環境なのでご了承頂きたい)
CCSを起動し、Workspaceに適当な名前(ここではBeagleBone_CppUTestとしたが、設定時にスペルミスしたので適切に読み替えて下さい)を入れてOKを押下。
ライブラリの生成
プロジェクトの作成
まず、CppUTestライブラリを生成するプロジェクトを作成する。
File => New => CCS Projectで新規プロジェクトを作成する。
Description | Comment |
---|---|
Target | BeagleBoneを選択 |
Project name | 何でもいいと思うがここではCppUTestとした |
Compiler version | 筆者が使っているTI製を選択(TI v5.1.6) |
Output type | Advanced settingsからStatic Libraryを選択 |
Project templates | Empty Projectを選択 |
Advanced settingは通常現れないので▼を押して表示する。
入力が完了したらFinishを押下。
UppUTestのインポート
プロジェクトを右クリック(もしくはプロジェクトを選んでFileメニュー)からImportでImportダイアログを開く。General⇒File Systemを選んでNextをクリック。Browseを押下してCppUTestディレクトリを指定してOKを押下。
次のようにインポートするインクルードファイルとソースファイルを指定する。PlatformsはインクルードではGcc、ソースファイルではIarを選ぶ。なお、ソースファイルに含まれる拡張子dspのような不要なファイルは組み込まない。Finishをクリックしてインポートを実行する。
インポート後のプロジェクトは次のようになる。
プロジェクトの設定
まずインクルードディレクトリを指定する。プロジェクトを右クリック(もしくはプロジェクトを選択してFileメニュー)からPropertiesを選択し、プロパティダイアログを表示する。左のツリービューからBuild⇒ARM Compiler⇒Include Optionsを選択し、右下のディレクトリサーチ追加ペインにあるAddボタンをクリックし、Workspaceボタンから参照して次のようにプロジェクト内のインクルードパスを指定する。
OKを押下すると次のようなディレクトリ指定となるので更にOKを押下する。
ディレクトリパスに追加されていることを確認する。
続けてシンボル定義をしておく。同じプロパティダイアログのツリービューからBuild⇒ARM Compiler⇒Advanced Options⇒Predefined Symbolsを選択し、右上のPre-define NAMEペインのAddボタンをクリックし、次のようにシンボル「_LIB」を定義する。
追加されていることを確認する。
最後に言語オプションで例外ハンドリングを有効にする。同じプロパティダイアログのツリービューからBuild⇒ARM Compiler⇒Advanced Options⇒Language Optionsを選択し、Enable C++ exception handling (--exceptions)
とEnable support for GCC extensions (--gcc)
にチェックを入れ、OKボタンをクリックする。
メモリーリーク検出を抑制
時間の関係でうまく動作させる方法が分からなかったので一旦メモリリークの検出を抑制する。/CppUTest/include/CppUTest/CppUTestConfig.hファイルを編集し、#define CPPUTEST_MEM_LEAK_DETECTION_DISABLED
を追記する。
/* Is memory leak detection enabled?
* Controls the override of the global operator new/deleted and malloc/free.
* Without this, there will be no memory leak detection in C/C++.
*/
#define CPPUTEST_MEM_LEAK_DETECTION_DISABLED
#ifndef CPPUTEST_USE_MEM_LEAK_DETECTION
#ifdef CPPUTEST_MEM_LEAK_DETECTION_DISABLED
#define CPPUTEST_USE_MEM_LEAK_DETECTION 0
#else
#define CPPUTEST_USE_MEM_LEAK_DETECTION 1
#endif
#endif
ビルド
ビルドを実行(別段の理由が無ければCtrl+Bでよい)し、ライブラリCppUTest.libが生成する。ライブラリファイルはDebug(設定によりRelease)以下に生成される。
テストケースの実装
プロジェクトの作成
続いてテストケースを実装してみる。今回は簡単のため同じワークスペース上でテストケースを実装する。File => New => CCS Projectで新規プロジェクトを作成する。
Description | Comment |
---|---|
Target | BeagleBoneを選択 |
Connection | Texas Instruments XDS100v2 USB Debug Probeを選択 |
Project name | 何でもいいと思うがここではRunnerとした |
Compiler version | 筆者が使っているTI製を選択(TI v5.1.6) |
Output type | Advanced settingsからExecutableを選択 |
Project templates | 標準出力の見本のあるHello Worldを選択 |
入力が完了したらFinishを押下。
CppUTestなので自動生成されたhello.cをhello.cppにリネームしておく。
インクルードパスの指定
インクルードディレクトリの指定をライブラリの時とおなじ要領で設定する。同じワークスペース上にあるときはWorkspaceボタンを押下して次のように設定すれば良い。なお、ワークスペース内に無いときはFile Systemで指定する。
##ライブラリの指定
Build⇒ARM Linker⇒File Search Pathを選び右上のInclude library fileペインでAddボタンを押下し、CppUTest.libを指定する。なお、次画面は指定後の画面。
Addボタンを押下するとAdd file pathダイアログが開くのでWorkspaceボタンを押下し、次のようにワークスペース内にある事前に作成したライブラリを指定する。
言語オプションで例外ハンドリングを有効にする。同じプロパティダイアログのツリービューからBuild⇒ARM Compiler⇒Advanced Options⇒Language Optionsを選択し、Enable C++ exception handling (--exceptions)
とEnable support for GCC extensions (--gcc)
にチェックを入れ、OKボタンをクリックする。
CppUTestのテストを実行するには一定以上のスタックサイズとヒープサイズが必要になる。正確に見積もりしていないが、メモリーも沢山ある事だし両方とも0x100000を指定する。Build⇒ARM Linker⇒Basic Optionsを選び、Set C system stack size
に0x10000、Heap Size for C/C++ dynamic memory allocation
に0x10000を指定する。
確認してOKボタンを押下する。
セクションの設定
サンプルプログラムはSRAM上に配置するように設定されているが、CppUTestがまあまあ大きいので納まらないため、DDR上に配置するよう、AM335x.cmdを次のように編集しておく。つまり、L3OCMC0
をDDR0
に全て置換し、.ARM.exidx
と.ARM.extab
を追加する。
#ifdef A8_CORE /* A8 memory map */
MEMORY
{
SRAM: o = 0x402F0400 l = 0x0000FC00 /* 64kB internal SRAM */
L3OCMC0: o = 0x40300000 l = 0x00010000 /* 64kB L3 OCMC SRAM */
M3SHUMEM: o = 0x44D00000 l = 0x00004000 /* 16kB M3 Shared Unified Code Space */
M3SHDMEM: o = 0x44D80000 l = 0x00002000 /* 8kB M3 Shared Data Memory */
DDR0: o = 0x80000000 l = 0x40000000 /* 1GB external DDR Bank 0 */
}
SECTIONS
{
.ARM.exidx > DDR0
.ARM.extab > DDR0
.text > DDR0
.stack > DDR0
.bss > DDR0
.cio > DDR0
.const > DDR0
.data > DDR0
.switch > DDR0
.sysmem > DDR0
.far > DDR0
.args > DDR0
.ppinfo > DDR0
.ppdata > DDR0
/* TI-ABI or COFF sections */
.pinit > DDR0
.cinit > DDR0
/* EABI sections */
.binit > DDR0
.init_array > DDR0
.neardata > DDR0
.fardata > DDR0
.rodata > DDR0
}
#endif /* A8 memory map */
テストケースの実装
今回の例ではメイン関数にテストケースを直接コーディングして動作を確認する。
/*
* hello.cpp
*/
#include <stdio.h>
#include <CppUTest/CommandLineTestRunner.h>
#include <CppUTest/TestHarness.h>
int main(void)
{
printf("Hello World!\n");
static char *argv[] = { "main" };
CommandLineTestRunner::RunAllTests(sizeof(argv)/sizeof(*argv), argv);
}
int hoge(void)
{
return 3;
}
int hoge(int a)
{
return a + 1;
}
TEST_GROUP(TestSuiteHoge)
{};
TEST(TestSuiteHoge, TestCaseHoge)
{
LONGS_EQUAL(3, hoge());
}
TEST(TestSuiteHoge, TestCaseHoge2)
{
LONGS_EQUAL(3, hoge(2));
}
実行と結果
BeagleBoneはマルチコアなのでA8側に接続、ロードして実行する。
実行結果
ロード後Resumeを選択して実行する。結果はCIOコンソールに出力される。