can't go to sleep

組み込み開発の多くをRubyで自動化することに興味があります

unity開始の第一歩(超入門)

思い返せば、unityを初めて1年近く経過しました。
結局こういうツールは使い始めるまでのハードルが最も高いように思います。
ということで、unityの簡単な始め方を、改めて書き出したいと思います。

目標

unityを開始する際には色々と気を付けることがありますが、ここではTDDにこだわらず、無料でC言語単体テストをすることを目標にしたいと思います。そのため、既存の開発プロジェクトのフォルダの近くにunityのプロジェクトを作成し、製品コードには手を加えずに単体テストを実施できる環境を作ることを目標とします。
また、色々なところで触れられていますが、CMockはfff(fake function framework)と比べると使い勝手、動作速度などで劣っているため、今回は導入しません(CMockの使い方は以前1度記事にしましたが、rakefileの設定などが変わるため色々と面倒です)。更に、ceedlingはCIを行う際には強い味方となりますが、いまいち使い勝手が悪いので、そちらも無視です。

事前準備

rubyおよびrakeをPCにインストールします。
rubyは、「ruby installer」で検索すると、インストーラーが見つかるので、適当にインストールしてください。rakeはrubyをインストールすると同時にインストールされると思います。
http://rubyinstaller.org/
次に、unityの本体を入手します。GitHubからcloneしても手に入りますが、作者達のサイト「Throw The Switch」からでもzip形式で入手できます。今回は、現在の作者サイトから手に入る、unity-master.zipを使うことを前提としています。
http://throwtheswitch.org/

unityをとりあえず動かす

まず、サンプルテストを動作させるところまでを行いまs。

フォルダ構成について

ダウンロードしたunity-master.zipを、製品コードの傍に展開します。展開すると、unity-masterフォルダができます。フォルダ構成ですが、今回は、以下のようなフォルダ構成を仮定します(A.c, A.hは製品コードの例)。

-/project
    |-/src
        |-A.c
        |-A.h
-/unity-master

こういったフォルダ構成にすることで、プロジェクトフォルダの外でテストファイルを作成することができますので、製品コードとテストコードを完全に分離することができます。ただし、テストファイルはソースファイルやプロジェクトと一緒にバージョン管理することを強くお勧めします。

デフォルトのテストを動作させる

コマンドプロンプトを立ち上げて、unity-masterフォルダへ移動します(rakefile.rbのある場所)。そこで、「rake」とコマンドを入力して実行してみてください。すると、

rake aborted!
cannot load such file -- C:/utest/Unity-master/auto/unity_test_summary

と表示され、うまくいきません。そこでrakefile.rbをエディタで開き、2行目を

#UNITY_ROOT = File.expand_path(File.dirname(__FILE__)) + '/../..'
UNITY_ROOT = File.expand_path(File.dirname(__FILE__))

と修正します。再びrakeをすると、次は

rake aborted!
No such file or directory - target_gcc_32.yml

と表示されるので、次はtargetフォルダ内にある「gcc_32.yml」を「target_gcc_32.yml」とリネームしたうえで、rakefile.rbと同じフォルダにコピーします(真面目に修正するならば、rakefile_helper.rb内のconfigure_toolchainなどを変更する必要があるのですが、面倒なので・・・)。再びrakeをすると、何やら変なエラーが出ます。これは、testフォルダ内にある「testparameterized.c」というファイルのテストがgccで動作しないためです(環境によっては動くかもしれませんが、私の環境ではエラーとなりました)。ここは素直にあきらめて、「testparameterized.c」を削除してしまいます。改めてrakeをすると、ようやくテストが実行できます。
unityでは、testフォルダ中にある、「test」で始まる.cファイルは全てテストファイルとみなします。そのため今後テストを追加する際には、testフォルダ内に追加していくことになります。

製品コードへのパスを追加する

次に、製品コードのソースへのパスを設定に追加します。target_gcc_32.ymlを開き、compiler:のincludes:のitems:に、相対パスを追加します。
具体的には

  includes:
    prefix: '-I'
    items:
      - 'src/'
      - '../project/src/'
      - *unit_tests_path

という具合に、デフォルトで存在する'../src'を変更すれば良いと思います。

製品コードをテストする

これでようやく製品コードをテストできます。今回は、製品コードの例として

// A.c
int funcA(int a, int b)
{
	return a + b;
}
// A.h
int funcA(int a, int b);

という形でコードが記述されており、上記のproject/src/フォルダに保存されているとします。
例として、testA.cという名前で、testフォルダに以下のようなテストコードを作成します。

// testA.c
#include "unity.h"
#include "A.h"

void setUp(void)
{
}

void tearDown(void)
{
}

void testA(void)
{
	
	TEST_ASSERT_EQUAL(3, funcA(1,2));
}

これでrakeを実施すると、

test/testA.c:12:testA:PASS
------------------------
1 Tests 0 Failures 0 Ignored
OK

と表示されます。テストが正常に実行され、パスしていることがわかります。
ここで、testunity.cは邪魔なので、_testunity.cなどとリネームしてやると、テスト対象から外れます。

終わりに

とりあえずこれでunityが使えるようになります。
ここからでも、色々とつまづくことがあるかと思います。具体的には、

  1. 同名のヘッダファイルがないCファイルのテスト
  2. 依存ファイルが多すぎるファイルのテスト方法
  3. モック関数の作り方
  4. 大量にできたテストファイルをいちいち毎回テストするのが面倒
  5. フォルダ分けしたソースファイルをテストしたい場合、またテストファイルをフォルダ分けしたい場合

これらは以前このブログで書いたように思いますので、ぜひ参考にしてみてください。