はじめに
概要
書籍『テスト駆動開発による組み込みプログラミング』を読み始めたことをきっかけに、業務でよく触るRenesasのRL78マイコン向けのテスト環境構築を目指すことにしました。
とりあえずビルド時のテスト実施・結果表示ができたので、そこまでの手順を本記事にまとめます。
この記事でやること
"とりあえず"、ビルド時に命令レベルのシミュレータで自動テストが実施されるようにする
- テストフレームワーク Unityを、e2studioで作成するRL78マイコン向けソフトのプロジェクトに入れる
- ビルド & e2studioでのシミュレータ実行で、テスト結果が確認できるようにする
- e2studioのビルド時に自動テストが走るようにする
環境
使用する環境
- OS: Windows 11
- IDE: e2studio 2023-04 (23.4.0)
https://www.renesas.com/jp/ja/software-tool/e-studio - コンパイラ:CC-RL v1.12.00
- GDB:GNU gdb (GDB) 7.8.2-20211130-Build_1
(e2studioのインストール時についてきたものを使います) - テストフレームワーク: Unity
https://github.com/ThrowTheSwitch/Unity
準備
プロジェクト作成
使用するRL78のプロジェクトを作成します。
RL78のプロジェクトであればなんでもよいはずです。今回は、以下の評価ボードで使用されており、実機上のデバッグ時も使用できる、RL78/G14ファミリ R5F104MLマイコンでプロジェクトを作成します。
また今回は今回はコード生成ツールも使用します。
gdbの確認
テストの実行にあたり、デバッグツールGDBをrl78向けにカスタマイズした、rl78-elf-gdb
を使用します。
同ツールの場所を確認します。デフォルト設定でe2studioをインストールした僕の場合、C:\Users\[ユーザ名]\.eclipse\com.renesas.platform_1435879475\DebugComp\RL78
に配置されていました。
また、rl78-elf-gdb
の実行にあたり、e2studioと一緒にインストールされるPython 2.7.2が必要(らしい)です。
こちらも場所を確認します。僕の場合、C:\Renesas\e2_studio\eclipse\runtimes\python\2.7.12_x86
にありました。
上記のパスを使用して、rl78-elf-gdb
が正しく動作することを確認します。
>set PYTHONPATH=C:\Renesas\e2_studio\eclipse\runtimes\python\2.7.12_x86\Lib
>set Path=C:\Renesas\e2_studio\eclipse\runtimes\python\2.7.12_x86;%Path%
>C:\Users\[ユーザ名]\.eclipse\com.renesas.platform_1435879475\DebugComp\RL78\rl78-elf-gdb --version
GNU gdb (GDB) 7.8.2-20211130-Build_1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=i686-pc-mingw32 --target=rl78-elf".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
このようにバージョン情報が表示されればOKです
Unityの導入
ファイルのコピー
以下の記事を参考に、cloneもしくはダウンロードしたUnityの各ソースを、e2studioのプロジェクトにコピーして追加します。
RXマイコンで、Unityによる単体テスト環境を作ってみた(後編) - /Test_you
まず、以下のようなフォルダ構成になるよう、tests
およびunity
フォルダを作成します。
[プロジェクトルート]
- src
- tests
- unity
次に、以下に示す.c
および.h
ファイルをunity
フォルダにコピーします。
Unity-master
- src
- unity.c
- unity.h
- unity_internals.h
- extras
- fixture
- src
- unity_fixture.c
- unity_fixture.h
- unity_fixture_internals.h
- memory
- src
- unity_memory.c
- unity_memory.h
テスト用ファイルの作成
続いて、同じくRXマイコンで、Unityによる単体テスト環境を作ってみた(後編) - /Test_you を参考に、テストランナーとテストケースを作成します。
#include "../unity/unity_fixture.h"
#include "../r_cg_macrodriver.h"
#include "../r_cg_port.h"
TEST_GROUP(Test0);
// テストケース前処理
TEST_SETUP(Test0)
{
}
// テストケース後処理
TEST_TEAR_DOWN(Test0)
{
}
// 必ず失敗するテストケース
TEST(Test0, AlwaysFail)
{
TEST_FAIL_MESSAGE("This test always fails.");
}
// テストグループにテストケースをインストール
TEST_GROUP_RUNNER(Test0)
{
RUN_TEST_CASE(Test0, AlwaysFail);
}
#include "../unity/unity_fixture.h"
// 実行するテストケースを記述
void RunAllTests(void)
{
RUN_TEST_GROUP(Test0);
}
dprintf用の関数を作成
RXマイコンの場合、printf
によるエミュレータのコンソール出力が可能ですが、RL78マイコンの場合は不可能です。
そこで、コンパイル済みバイナリの実行はgdbのシミュレータを、テスト結果などの出力はgdbのdynamic printfを使用します。
dynamic printfのブレークを設置するための関数を以下のように用意します。
(ついでに、テスト終了時を検出するブレークを張るための関数も用意します)
#include "./myprintf.h"
// 文字列出力用バッファのサイズ
#define CHARBUF_SIZE 100
// 文字列出力用バッファの定義
// ヌル文字を考慮し、SIZE+1とする
static volatile char charBuf[CHARBUF_SIZE+1];
// バッファ用インデックスの定義
unsigned int idxCharBuf = 0;
// dynamic printf用 文字(列)出力関数
// dynamic printfの呼び出し回数を抑えるため、バッファフルもしくは改行コードで出力
void myPrintf(char c)
{
// charの格納とインデックスのインクリメント
charBuf[idxCharBuf] = c;
idxCharBuf ++;
// バッファフルもしくは改行コード入力の場合
if ( (idxCharBuf == CHARBUF_SIZE) || (c == '\n'))
{
// 末端にヌル文字を挿入
charBuf[idxCharBuf] = '\0';
// インデックスを0に戻す
idxCharBuf = 0; //※この処理にdprintfを配置
}
}
// テスト終了時に呼び出す関数(gdbのコンソールに操作を戻すため)
void onTestEnd(void)
{
idxCharBuf = 0;
}
#ifndef TESTS_MYPRINTF_H_
#define TESTS_MYPRINTF_H_
#endif /* TESTS_MYPRINTF_H_ */
void myPrintf(char c);
void onTestEnd(void);
unityによる出力がこのmyPrintf
を通るよう、プリプロセッサの定義を変更します。
...
/*-------------------------------------------------------
* Output Method: stdout (DEFAULT)
*-------------------------------------------------------*/
#ifndef UNITY_OUTPUT_CHAR
/* Default to using putchar, which is defined in stdio.h */
#include <stdio.h>
#include "../tests/myprintf.h" //追加
#define UNITY_OUTPUT_CHAR(a) (void)myPrintf(a) //変更
#else
...
最後に、テストが実行されるようmain
関数を変更します。
...
/* Start user code for include. Do not edit comment generated here */
#include "unity/unity_fixture.h"
#include "tests/myprintf.h"
/* End user code. Do not edit comment generated here */
...
void main(void)
{
R_MAIN_UserInit();
/* Start user code. Do not edit comment generated here */
int argc = 2;
const char *argv[] = {"program name", "-v"};
extern void RunAllTests(void);
// テスト実行
UnityMain(argc, argv, RunAllTests);
// テスト実行終了
onTestEnd();
while(1){}
/* End user code. Do not edit comment generated here */
}
ここまでできたら、一度正しくunityの導入ができているかを確認します。
プロジェクトをビルドし、シミュレータでデバッグ実行してください。
自動的にmain関数の入り口でブレークするはずなので、以下のようにdynamic printfを配置してください。
"%s",charBuf
ブレークポイント設置後に実行再開すると、Debugger Consoleに、以下のようにunityテスト結果が出力されます。
これでunityの導入はOKです。
ビルド時の自動テスト
最後に、e2studioでのビルド時に自動テストが走り、先ほどのようなテスト結果が出力されるようにします。
gdbのシミュレータを実行するためのバッチファイルおよびgdbのコマンドファイルを新たに作成し、適当な場所に配置します。
(今回はプロジェクトのルートに配置します。)
set PYTHONPATH=C:\Renesas\e2_studio\eclipse\runtimes\python\2.7.12_x86\Lib
set Path=C:\Renesas\e2_studio\eclipse\runtimes\python\2.7.12_x86;%Path%
rl78-elf-gdb.exe --silent %1\HardwareDebug\test_test.x < %1\autorun.gdbcmd > %1\autotest_log.txt
type %1\autotest_log.txt
findstr "OK" %1\autotest_log.txt
※注1: PYTHONPATH
およびPath
にセットするそれぞれのパスは、上部「gdbの確認」で調べたパスを使用してください。
※注2: プロジェクトの絶対パスはe2studioからのコマンド実行時に引数として渡します。
※注3: テスト失敗時にビルドエラーが表示されるよう、gdbでのテスト実施後にfindstr
でエラーレベルを設定しています。
target sim
load
dprintf C:/Users/[ユーザ名]/e2_studio/workspace/test_test/src/tests/myprintf.c:23, "%s" ,charBuf
b onTestEnd
shell cls
r
q
※注1: 先ほどdynamic printfを仕掛けた場所と同じところでdprintfするよう、フルパス+行数 で場所を指定しています。相対パスにしたい・・・
※注2: 先ほどと違い、onTestEnd
関数にブレークを張っています。これにより、テスト終了時にgdbコンソールに操作を戻すようにしています。
最後に、e2studioプロジェクトのビルドステップに、このバッチを実行するよう設定します。
プロジェクト > プロパティ > C/C++ ビルド > 設定 > ビルド・ステップ
「ビルド後のステップ」を以下にします。
${workspace_loc:/${ProjName}}\autotest.bat ${workspace_loc:/${ProjName}}
ここまでできたら、e2studioでプロジェクトをビルドします。
以下のように、テスト結果が表示され、テスト失敗を理由にビルドエラーになれば成功です。
FAIL_MESSAGE
を消して、テストOKであればビルドOKになることも確認しましょう。
おわりに
とりあえず動いたけど、ちゃんと使えるようにいろいろ改善したいですね・・・・