/Test_you

電子工作やプログラミングなど、やってみたことのメモ

e2studio(GCC for RX)で、Unityによる単体テストを試してみた

先日、Renesasのアプリケーションノートに従い「e2studio(GCC for RX)で、CUnitによる単体テストを試してみた」をやりましたが、今回はテストフレームワーク Unity で同じことを試しました。結果、CUnitと同様にテストできました


1. 環境

  • Windows 10 Pro: バージョン 21H2、ビルド 19044.2130
  • e2studio: 2022-07 (64bit版)
  • コンパイラ: GCC for Renesas RX 8.3.0.202202
  • Unity: 2.5.2
  • テスト環境:RX Simulator

2. テスト対象プロジェクトを作成する

  • ファイル > 新規 > Renesas C/C++ Project > Renesas RX より、プロジェクトを新規作成
    • テンプレートはGCC for Renesas RX C/C++ Executable Projectを選択
    • この記事では、プロジェクト名をSampleUnityとしています
  • Select toolchain, device & debug settingsのダイアログで下記に設定し「次へ」を押下
    • ツールチェーン: GCC for Renesas RX
    • ツールチェーン・バージョン: 8.3.0.202202
    • ターゲット・デバイス: 任意(ここでは:RX600 > RX610 > RX610 - 144pin > R5F56107VxFP)
    • Hardware Debug構成を生成: チェックを外す
    • Debug構成を生成: チェックを入れる(「RX Simulator」を選択)
  • Select Coding Assistant Settingsのダイアログで「終了」をクリック

3. Unityの導入 と 準備

  • GitHub - ThrowTheSwitch/Unity: Simple Unit Testing for Cから、ソースをダウンロード
  • Unityの/srcフォルダにある unity_internals.hunity.cunity.h を、作成したプロジェクトの/srcフォルダにコピー

  • /generateフォルダに下記ファイルを sbrk.c として作成
    詳細理解していませんが、putchar や printf を使う場合、この関数が必須のようでした

// 本コードは、Renesasのアプリケーションノートから変更なし
// - putchar や printf を使うには、この sbrk 関数が必要なようだ。関数がない場合、次のエラーが出た
//   collision in (null): pc ffe83663 heap 00001018 stack 0000015c
// - Unityはテスト結果の出力に putchar を使うので、この関数定義は必須
void* sbrk(int incr)
{
    extern char end; /* Set by linker. */
    static char * heap_end;
    char * prev_heap_end;

    if (heap_end == 0) heap_end = &end;

    prev_heap_end = heap_end;
    heap_end += incr;

    return (void *)prev_heap_end;
}

3. テスト対象コードの追加

  • /srcフォルダにテスト対象ソース source.hsource.c を追加
// 本コードは、Renesasのアプリケーションノートから変更なし
#ifndef SOURCE_H_
#define SOURCE_H_

int add(int a, int b);
int subtract(int a, int b);

#endif
/* SOURCE_H_ */
// 本コードは、Renesasのアプリケーションノートから変更なし
#include "source.h"

int add(int a, int b) {
    return a + b;
}

int subtract(int a, int b) {
    return a - b;
}

4. テストコードの作成

メインのソースコードを下記のように修正

#include <stdlib.h>       // _Exit()
#include "unity.h"
#include "source.h"

// RUN_TEST毎の前後で呼ばれる関数(関数定義は必須、中身は空でも良い)
void setUp(void) {
}

void tearDown(void) {
}

// 下記テストは、Renesasのアプリケーションノートの内容を、Unity用に書き換えたもの
static void test_Add_01(void) {
    TEST_ASSERT_EQUAL_INT(1, add(1,0));
}

static void test_Add_02(void) {
    TEST_ASSERT_EQUAL_INT(10, add(1,9));
}

static void test_Subtract(void) {
    TEST_ASSERT_EQUAL_INT(0, subtract(1,1));
}

void main(void) {
    // テストケースが失敗した数
    int num_of_failures;

    // テスト開始
    UNITY_BEGIN();

    // 各テストを実施
    RUN_TEST(test_Add_01);
    RUN_TEST(test_Add_02);
    RUN_TEST(test_Subtract);

    // テスト終了
    num_of_failures = UNITY_END();

    // プログラムを強制終了し、シミュレータを抜ける
    // - このやり方が正しいか分からないが、Renesasのアプリケーションノートの方法(generate/start.Sにbrkを追加)だと、
    //   プログラム終了してからコマンドプロンプトに戻るまでに時間が掛かるので、このようにしている
    _Exit( (num_of_failures == 0) ? EXIT_SUCCESS : EXIT_FAILURE );
}
  • ポイント
    • テストコード test_Add_01()などを記述
      ※アプリケーションノートだとテストは別ファイルtestsource.cでしたが、ここでは簡単のためテストを同一ファイルに記述してます
    • テスト実行コードを main() 内に記述
    • テスト完了後、_Exit() でプログラムを強制終了し、シミュレータを抜ける
      ※このやり方が正しいか分からないですが、アプリケーションノートの方法(generate/start.Sにbrkを追加)だと、コマンドプロンプトに戻るまでに時間が掛かるので、このようにしてます

5. テスト用のバッチファイル作成

  • /Debugフォルダに下記ファイルをrun_test.batとして作成、ビルド後のフェーズでテストを実行する
@echo off
REM シミュレータでテストを実行する
REM ★GCC for RX のバージョン・インストール先に合わせて rx-elf-run.exe のパスを変更
REM ★プロジェクトの設定に合わせて *.elf のファイル名を変更
echo ******************** test phase ********************
"C:\ProgramData\GCC for Renesas RX 8.3.0.202202-GNURX-ELF\rx-elf\rx-elf\bin\rx-elf-run.exe" SampleUnity.elf
echo ****************************************************

6. 確認

この手順まで進めると、下記のフォルダ構成になります(水色が追加・修正したファイル)

7. プロジェクトのプロパティ設定

プロジェクトのプロパティを開いて、下記を設定

  • C/C++ビルド>設定>ツール設定>Linker>Otherに、オプション-msimを追加
  • C/C++ビルド>設定>ビルド・ステップにて、ビルド後のステップにrun_test.batを入力

8. Unityを使用した単体テストを実行する

プロジェクトをビルドすると、ビルドに続いて、テストが実行される
先日の記事と同様、設定すればVS Code上でも実行可能です


参考にした情報