2013年1月2日水曜日

Windows で eclipse ~CUTE入門編 Part.2~

2013年1月1日。
新年あけましておめでとうございます。

というか、この連載終わらないと新年を迎えた気がしない……。(-_-;;;)


Windows で eclipse ~CUTEインストール編~
Windows で eclipse ~CUTE入門編~




「CUTEを使ったユニットテストの実践編」を書こうと思ったが、マクロについて書いてなかったので、ここで改めて書いておく。

ユニットテストを実践する際、必須の知識となるので、事前に知っておいた方が良いので。



■CUTEの資料

Google先生に色々聞いていると、こんな資料を発見した。この資料に、CUTEの詳しい説明が記載されている。英語だが、翻訳サイトで翻訳しながら、なんとか読破いただきたい。


■C++ Refactoring and TDD with Eclipse CDT and CUTE



<マメ知識>




■テスティング・フレームワークの正体

▼対象読者

「初心者向け」に、テスティング・フレームワークについて記載しておく。
中級者以上は読み飛ばしてOK。




▼初めに

「テスティング・フレームワーク」とは、ユニット(=関数)の単体テストを自動実行するための環境である。

「テスティング・フレームワーク」を使用しない場合のユニットテストは、概ね下記に分類されるだろう。

  1. 関数レベルでは実施せず、結合試験レベルで代用。
  2. 関数内をステップ実行。途中で変数にメモリパッチして動作確認。
  3. テスト時のみ関数を修正して期待するテストを実施。テスト完了後プログラムを戻す。
  4. わざわざテスト専用ツールを作成し、テストする。
1の方。単純なバグでいつもお悩みのことでしょう。

2の方。単体試験完了後、バグが見つかってプログラムを修正しても、修正箇所しかテストしてないのでは?

3の方。結局製品コードをテストした事にならないのでは?かつ修正ミスでデグレした経験ありませんか?

4の方。度重なる仕様変更と、別のプログラムの開発で、折角作ったテストツールが使えなくなった経験、ありませんか?

これらの問題を、ある程度解消してくれるのが、「テスティング・フレームワーク」である。




▼できること、できないこと


「テスティング・フレームワーク」は万能ツールではない。できること、できないことがある。

  • できること
    • テスト対象関数を、任意のタイミングで呼び出す
    • テスト対象関数に、好きなパラメタを渡す
    • テスト対象関数のアウトプットが正しいかチェック
    • 製品となるプログラムに手を加えずテストすることが可能。
    • スタブによる任意の値を返すことが可能
    • 同じテストを繰り返し実行可能
  • できないこと
    • アルゴリズムの妥当性検証
    • スタック破壊、メモリ破壊の検証
    • 実行途中のメモリパッチ
    • 静的解析
    • システムライブラリの戻り値を書き換えること

要約すると、「任意の値をインプットした関数からのアウトプットが正しいか、自動検証することができる」のである。

(例)

bool isSame( short data1, short data2 )
{
    return (data1 == data2);
}


例えば、上記関数に対するテストパターンを考えると、下記12パターンが挙げられる。
あなたは上記関数に対して何パターンのテストを実施しますか?

  1. data1=0,        data2=0,          結果=true
  2. data1=1,        data2=1,          結果=true
  3. data1=32767  data2=32767,    結果=true
  4. data1=-32768 data2=-32768,  結果=true
  5. data1=0,        data2=1,          結果=false
  6. data1=0,        data2=32767,    結果=false
  7. data1=0,        data2=-1,         結果=false
  8. data1=0,        data2=-32768,   結果=false
  9. data1=1,        data2=0,           結果=false
  10. data1=32767,  data2=0,           結果=false
  11. data1=-1,       data2=0,           結果=false
  12. data1=-32768, data2=0,          結果=false

で、こんなテストをササッと作成できてしまうのが「テスティング・フレームワーク」の強みである。

(例)テスト関数

void testisSame()
{
    ASSERT_EQUAL( isSame( 0, 0 ), true );
    ASSERT_EQUAL( isSame( 1, 1 ), true );
    ASSERT_EQUAL( isSame( 32767, 32767 ), true );
    ASSERT_EQUAL( isSame( -32768, -32768 ), true );
    ASSERT_EQUAL( isSame( 0, 1 ), false );
    ASSERT_EQUAL( isSame( 0, 32767 ), false );
    ASSERT_EQUAL( isSame( 0, -1 ), false );
    ASSERT_EQUAL( isSame( 0, -32768 ), false );
    ASSERT_EQUAL( isSame( 1, 0 ), false );
    ASSERT_EQUAL( isSame( 32767, 0 ), false );
    ASSERT_EQUAL( isSame( -1, 0 ), false );
    ASSERT_EQUAL( isSame( -32768, 0 ), false );
}


[ASSERT_EQUAL( )]は、アサートマクロと呼ばれるもので、テスト対象プログラムのアウトプットを評価するマクロである。

ターゲットとなる関数(isSame)に対応するテスト関数(testisSame)を作成し、テストを実施する。一度作ってしまうと、未来永劫テストし続けることができ、デグレを防止することができる。

さらに、こんなこともできてしまう!!


(例)テスト関数 その2


void testisSame() {
  ASSERT_EQUAL( isSame(0,0), true  );
  for( int data=-32768; data<=-1; data++ ) {
ASSERT_EQUAL( isSame(data,data), true  );
ASSERT_EQUAL( isSame(0,   data), false );
ASSERT_EQUAL( isSame(data,0),    false );
  }
  for( int data=1; data<=32767; data++ ) {
ASSERT_EQUAL( isSame(data,data), true  );
ASSERT_EQUAL( isSame(0,   data), false );
ASSERT_EQUAL( isSame(data,0),    false );
  }
}


上記12パターンどころか、-32768~32767まで、全パターンのテストが、たった13ステップのプログラムで実現してしまう!

しかも、ビルドして実行するので、実行時間は数秒~十数秒しか掛からない。

これを人間がステップ実行することを考えると、テスト時間の短縮率は圧倒的だということがお分かり頂けるだろう。




■アサートマクロ

という訳で、ようやく本題のテストマクロのお話。

▼アサートマクロ一覧

  • ASSERT系 : condがfalseの場合、エラーとみなす。
    • ASSERTM( msg, cond )
    • ASSERT( cond )
  • FAIL系 : 実行するとエラーとなる。
    • FAILM(msg)
    • FAIL()
  • ASSERT_EQUAL系 : expected と actual が不一致の場合エラーとなる。
    • ASSERT_EQUALM(msg, expected, actual)
    • ASSERT_EQUAL(expected, actual)
  • ASSERT_EQUAL_DELTA系 : expected と actual の差が delta を超えた場合エラー。
    • ASSERT_EQUAL_DELTAM(msg, expected, actual, delta)
    • ASSERT_EQUAL_DELTA(expected, actual, delta)
  • ASSERT_THROW系 : 実行すると exc(例外) をスローする。
    • ASSERT_THROWSM(msg, code, exc)
    • ASSERT_THROWS(code, exc)




■テスト関数登録マクロ

更に、「テスティング・フレームワーク」に登録する際、下記マクロが使用できる。

  • CUTE( test1 )
    • テスト関数(test1)を「テスティング・フレームワーク」に登録する。
  • CUTE_SMEMFUN( TestClass, test1 )
    • テストクラス(TestClass)内のテスト関数(test1)を「テスティング・フレームワーク」に登録する。オブジェクトは、「テスティング・フレームワーク」で生成される。
  • CUTE_MEMFUN( testobject, TestClass, test1 )
    • テストオブジェクト(testobject)内のテスト関数(test1)を「テスティング・フレームワーク」に登録する。オブジェクトは[testobject]をそのまま使用。
  • CUTE_CONTEXT_MEMFUN( testobject, TestClass, test1 )
    • テストオブジェクト(testobject)内のテスト関数(test1)を「テスティング・フレームワーク」に登録する。オブジェクトは[testobject]をコピーしたものを使用。

という訳で、次回はユニットテストの実技に移る。

0 件のコメント:

コメントを投稿