以前、こんな記事を書きました。
CMockは素晴らしいツールで、正直これがないとこの3ヶ月で心がへし折られていたと思う。しかし今日は、CMockに対向できるような素晴らしいツールを発見したので紹介。その名も、
FFF
ファイナルファンタジーではないが、魔法のようなツールだ。
FFFってなに
Fake Function Framework。ダミー関数を自動生成してくれる、『C言語』のためのツール。フェイク関数のフレームワークといいつつも、実際はスタブ関数やスパイ関数などなど、いろいろ生成するツールだ。
githubからダウンロードできる。
基本編
一番くわしいリファレンスは、githubのReadme.mdを以下はそれを参考に、いろいろと実験。
git clone git@github.com:meekrosoft/fff.git
xUnitフレームワークは、Unityを利用します。
はじめの一歩
定形の宣言。fff.hのなかに、すべてが集約されている。テストコードに以下を追記。
// Test_uhauha.c
#include "fff.h"
#include
DEFINE_FFF_GLOBALS;
fff.hのなかで、memsetを利用しているようなので、string.hかが必要。
FFFでDummyする
まずは、ダミー関数を。hogehogeの実体をコンパイルすることなく、uhauha関数からhogehogeを呼び出す。
// uhauha.c
#include "uhauha.h"
#include "hogehoge.h"
void uhauha(void)
{
hogehoge();
}
// hogehoge.h
int hogehoge(void)
void hogehoge(void)型を置き換えるには、テストコードに以下を追加する。
// Testuhauha.c
FAKE_VOID_FUNC(hogehoge);
これで、ダミー関数が宣言されて、コンパイルが通る。
これだけなのです!!魔法みたい!ウッハウハですね。
FFFでスタプする
hogehoge()をスタブ関数にします。必ず1を返すようにする。。
// uhauha.c
int uhauha2(void)
{
return hogehoge2();
}
// hogehoge.h
int hogehoge2(void)
テストコードに以下を宣言。
// Testuhauha.c
FAKE_VALUE_FUNC(int, hogehoge2);
そして、実際のテストでは、1を返すようにhogehoge2_fake.return_valに値を入れる。
void test_uhauha2(void)
{
hogehoge2_fake.return_val = 1;
TEST_ASSERT_EQUAL(1, uhauha2() );
}
これで、hogehoge2は必ず1を返すフェイク関数ができる。
これだけなのです!!魔法みたい!ウッハウハですね。
FFFでスパイする
Spy関数も生成できるようです。
hogehoge3()に渡された値をスパイして、あとで結果をAssertします。
// uhauha.c
void uhauha3(int x)
{
x++;
hogehoge3(x);
}
// hogehoge.h
void hogehoge3(int);
テストコードはこちら。hogehoge3_fake.call_countで呼ばれた回数を、hogehoge3_fake.arg0_valで呼ばれた値を検証している。
// Testuhaha.c
FAKE_VOID_FUNC(hogehoge3,int);
void test_uhauha3(void)
{
uhauha3(1);
// check how many times hogehoge3 called.
TEST_ASSERT_EQUAL(hogehoge3_fake.call_count, 1);
// chech what value was given
TEST_ASSERT_EQUAL(hogehoge3_fake.arg0_val, 2);
}
これで、hogehoge3をスパイできる。
これだけなのです!!魔法みたい!ウッハウハですね。
応用編
スタブとスパイの合わせ技
スタブしつつ、スパイの検証もできる。以下のように宣言。たとえば、
int hogehoge4(int);
をスパイしつつフェイクするには、以下を書く。
FAKE_VALUE_FUNC(int, hogehoge4,int);
シーケンス制御の検証
ほかにも、シーケンスの検証も可能。シーケンスのチェックこそがモッキングフレームワークなのだよ!詳細は省略。
カスタム関数を利用してフェイク、スパイする
登録した関数がコールされた時に、自分で作成した関数に飛ばすことができる。
hogehoge5_fake.custom_fake = hogehoge_custom_fake;
のように宣言して
void hogehoge_custom_fake(){}
みたいに、自分が関数を用意する。プリプロセッサ接合部で置換するので、関数ポインタやリンク時の整合部を意識することなく、さくっと自前関数に飛ばせる。便利(・∀・)。
個人的最大の課題 データを渡す関数のモック
自分の扱っているコードは、メモリ獲得した構造体データを引数にして関数に渡すことがほとんど。こんな感じ。
//hogehoge.h
typedef struct hogehoge {
int time;
int status;
int factor;
}HOGEHOGE;
void hogehoge5(HOGEHOGE *hogehoge);
//uhauha.c
void uhauha5(void)
{
HOGEHOGE *hogehoge = (HOGEHOGE *)calloc(1,sizeof(HOGEHOGE));
hogehoge->time = 1;
hogehoge->status = 2;
hogehoge->factor = 3;
hogehoge5(hogehoge);
}
こういうhogehoge5をチェックするには、自前のスパイ関数を作成して検証していた。fff.hを利用すれば検証がサクットできる。
HOGEHOGE last_hogehoge;
void hogehoge5_spy(HOGEHOGE *hogehoge)
{
memcpy(&last_hogehoge,hogehoge,sizeof(HOGEHOGE));
free(hogehoge);
}
void test_uhauha5(void)
{
hogehoge5_fake.custom_fake = hogehoge5_spy;
uhauha5();
TEST_ASSERT_EQUAL( 1, last_hogehoge.time);
TEST_ASSERT_EQUAL( 2, last_hogehoge.status);
TEST_ASSERT_EQUAL( 3, last_hogehoge.factor);
}
感想
以前の記事で、『プリプロセッサ接合部』について書きました。
このfffは、『プリプロセッサスゲーΣ(゚Д゚ノ)』と思わせるツールでした。C言語のプリプロセッサの底力を垣間見たフレームワーク。レガシーC言語バンザイヽ(´ー`)ノ
CMockは便利だが、xUnitがUnityに限定されてしまう。それに対してこのfff.hは、移植性がとても高そうだ。評価してないけど、いろんなフレームワークでいっしょに利用できそう。C言語のフレームワークだが、extern “C"のテクニックをりようすることで、C++系のxUnitフレームワークでも利用可能。
CMockはRubyスクリプトでダミー関数を一気に生成することができる。
fffは必要なダミー関数を必要なだけ作成する点が異なる。自分の扱っているコードはテストがあるなんという金持ち環境ではなく、技術的負債で潰れかけているので、ねじ込むようにテストを書くにはCMockが必須う。
CMockだと、引数に構造体ポインタを渡す関数をうまくモックできなかった(やりかたがわからないだけかも)。そういう場合は、結局自分でモック関数を作成していた。しかし、fffを利用すればちょっと楽がデキそうた。