2012年2月25日土曜日

Google Test を使ってみる - その4(オプション)

Google Test では様々なオプションを環境変数または起動時引数に指定できます。
今回はそちらの紹介をしたいと思います。

オプション内容
--gtest_list_testsテストの一覧を出力します。
--gtest_filter=<条件>実行するテストを限定します。
--gtest_also_run_disabled_testsDISABLE なテストも実行します。
--gtest_repeat=<COUNT>テストの繰り返し回数を指定します。
負数にすると無限に繰り返します。
--gtest_shuffleテストの実行順序をシャッフルします。
--gtest_random_seed=<NUMBER>シャッフルする際の乱数シードを指定します。
0 を指定すると時間からシードを決定します。
--gtest_color=<yes|no|auto>出力を色付で表示するか選択します。
--gtest_print_time=0テストの実行時間を出力しないようにします。
--gtest_output=xml[:DIRECTORY|:FILE]指定のディレクトリまたはファイルにテスト結果の xml を出力します。デフォルトのファイル名は test_details.xml です。
--gtest_break_on_failureテストが失敗したときに break します。
--gtest_throw_on_failureテストが失敗したときに例外をスローします。
--gtest_catch_exceptionsテストが例外をキャッチするようにします。
--helpヘルプを表示します。

環境変数の場合は、最初の -- をのぞいた変数名を使います。(GTEST_FILTER, GTEST_COLOR, etc...)

よく使うオプション
それぞれのオプションの機能については、マニュアルを見ればわかるのでそちらを見ていただいて、ここでは個人的に使用頻度の高い機能と思うオプションを紹介します。

--gtest_filter=<条件>
実行するテストを指定します。
条件には、 * が使用できます。 * は任意の文字列にマッチします。
--gtest_filter=* ですべてのテスト名にマッチします。
--gtest_filter=FooTest.* でテストケース FooTest 内のすべてを実行します。

:(コロン) で OR 条件を記述できます。
--gtest_filter=*Constructor*:*Copy* で、Constructor または Copy を含むテストを実行します。

-(マイナス) で除外も可能です。
--gtest_filter=FooTest.*-FooTest.Bar で、FooTest.Bar テストを除く、テストケース FooTest 内のテストを実行します。

--gtest_filter の詳しい使用方法は、上級ガイドのテストを選択するを参照してください。

--gtest_shuffle
このオプションを指定するとテストケース・テストそれぞれランダムな順番で実行されます。
テストが他のテストの結果に依存していないか確認するのに最適です。
乱数のシードは、--gtest_random_seed=<NUMBER> で指定可能です。

--gtest_repeat=<COUNT>
テストを繰り返し実行します。
繰り返し実行させることで、再現性の低いテスト失敗が出るまで繰り返すことができます。
テストで乱数を使っている場合などに有効でしょう。
--gtest_repeat=-1 とすると無限に繰り返すので、
退社するまえにテストを走らせておいて一晩テストをさせることもできます。
また、--gtest_shuffle を指定すると毎回異なるシードでテストを行うので活用してみてください。

※ Google Test 関係の記事一覧はこちら

2012年2月18日土曜日

Google Test で Boost.Test の WARN flavor を実現する

Boost.Test には flavors というものがあり、アサーションのレベルがそれぞれ違います。
もちろん、Google Test にも同等のものが存在します。

エラー:ならない
テストの実行:継続
エラー:なる
テストの実行:継続
エラー:なる
テストの実行:中断
Google Test---EXPECTASSERT
Boost.TestWARNCHECKREQUIRE

ご覧のように Google Test には、"エラーにならないアサーション" がありません。
そこで、必要かどうかはさておき Google Test にもエラーにならないアサーションを提供したいと思います。

ベースとなるマクロ
まずは、アサーションで失敗が発生したときに失敗したことにならないようにします。
EXPECT をベースに作っていきましょう。
// GTEST_EXPECT_FAILURE_ をベースに作成
#define GTEST_INFORM_FAILURE_(message) \
 GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess)
                                // kSuccess とし成功を指定する

アサーションは最終的に GTEST_<level>_FAILURE_ を呼ぶので、エラーにならないアサーション用に GTEST_INFORM_FAILURE_ を定義します。(エラーにならないアサーションを INFORM としています。)

述語アサーション
次に、ほとんどのアサーションが述語アサーションを利用しているので、そちらを用意します。
#define INFORM_PRED_FORMAT1(pred_format, v1) \
  GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_INFORM_FAILURE_)
#define INFORM_PRED1(pred, v1) \
  GTEST_PRED1_(pred, v1, GTEST_INFORM_FAILURE_)

#define INFORM_PRED_FORMAT2(pred_format, v1, v2) \
  GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_INFORM_FAILURE_)
#define INFORM_PRED2(pred, v1, v2) \
  GTEST_PRED2_(pred, v1, v2, GTEST_INFORM_FAILURE_)
GTEST_INFORM_FAILURE_ を使うように書き換えただけです。
(述語アサーションは "5" まであるので、すべて用意します。)

各アサーションの定義
最後に、INFORM_TRUE とか INFORM_EQ マクロを定義します。
先に定義した述語アサーションを使うようにするだけです。
#define INFORM_TRUE(condition) GTEST_TEST_BOOLEAN_(condition, #condition \
    , false, true, GTEST_INFORM_FAILURE_)

#define INFORM_EQ(expected, actual) \
  INFORM_PRED_FORMAT2(::testing::internal:: \
   EqHelper<GTEST_IS_NULL_LITERAL_(expected)>::Compare, \
   expected, actual)
#define INFORM_NE(expected, actual) \
  INFORM_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual)
#define INFORM_LE(val1, val2) \
  INFORM_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2)
#define INFORM_LT(val1, val2) \
  INFORM_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2)
// 他にもありますが、ここでは省略します。

使い方
他のアサーションと同様に使います。
TEST(InfromTest, Sample)
{
    INFORM_TRUE(rand() != 0);
    INFORM_EQ(5, rand());
}

出力イベントリスナー
さて、ここまで順調にきましたが 問題 が発生します。
Google Test デフォルトの出力イベントリスナーだと何も出力されません。
TestPartResult::kSuccess のときは、何もせず return するようにコーディングされているからです。

そこで、ユーザー定義のイベントリスナーを追加してやります。

class InformPrinter : public ::testing::EmptyTestEventListener
{
private:
 virtual void OnTestPartResult(const TestPartResult& test_part_result)
 {
  // 成功のときに出力
  if( test_part_result.type() == TestPartResult::kSuccess )
  {
   // 出力してもらえるようにダミーのタイプを設定する
   TestPartResult tmp(TestPartResult::kNonFatalFailure
    , test_part_result.file_name()
    , test_part_result.line_number()
    , test_part_result.message());
   ::testing::UnitTest::GetInstance()->
    listeners().default_result_printer()->OnTestPartResult(tmp);
  }
 }
};

int main(int argc, char **argv) {
 testing::InitGoogleTest(&argc, argv);
 // InformPrinter をイベントリスナーに追加
 ::testing::UnitTest::GetInstance()->
  listeners().Append( new InformPrinter() );
 return RUN_ALL_TESTS();
}

iutest でできるようにしました
ここまで紹介してきた INFORM マクロを iutest で使えるようにしました。(v0.18.1.0 以降)
iutest は自作の C++ テストフレームワーク です。
Boost.Test には、include するだけ使える方法もあるようですが、
iutest を使えば、include するだけで Google Test の記法を使うことができます。
詳しくは、 SourceForge.Jp の プロジェクトページ を見てください。

2012年2月14日火曜日

「Boost.勉強会 #8 大阪」に参加してきました

というわけで、Jenkins 勉強会に引き続き、大阪に行って参りました。

どれも非常に興味深い(そして難しい)お話が聞けて、とても良かったです。

色々なお話がありましたが、個人的に一番興味のあったテスト関係の感想を。
まぁ、テストとかテストとかテストとかやってる身なので…
UST の URL はこちら。
C++でテスト駆動開発 (UST が見当たらなかったので SlideShare)
Boost.Testの紹介

C++でテスト駆動開発
TDD の話は、Aimingさんの社内勉強会 UST を事前に見てたので、フムフムと再確認。
Google Mock は、使ったことないので調べてみようと思いました。
(とりあえず、自分用に日本語ドキュメントの URL を貼っときます。Google Mock ドキュメント日本語訳

Boost.Testの紹介
Boost.Test の存在は前々から知っていましたが、
Google Test で運用を始めていたのと、それで不満なく使えていたのでスルーしてました。
あとは、パッと見使い方がわからなかった。。。

正直、Google Test でいいと思うが、Boost.Test を知らずして
Google Test 最高!とも言えないので、ちゃんと使ってみよう!

って、意気込んだものの忙しくて何もできてません・・・
そのへんはいずれ記事にできたらと思います。

2012年2月11日土曜日

「第2回大阪Jenkins勉強会」に参加してきました

2/10(金) に行われました 第2回大阪Jenkins勉強会 に参加してきました。
勉強会自体参加するのが初めてなので、緊張しました。

Jenkins は会社で使っていて、今は私が管理しています。
業務で使用する分には普通に稼働していますが、もっと便利な使い方とかあれば、
勉強していきたいなぁと思っています。

当日
勉強会が終わって、今これを書いています。

とりあえず、「難しかった」。
というのが最初の感想。

タイムテーブルは ATND のページをご覧ください。

ソースコードレビューシステムGerritとの連携
Gerrit 自体は、ちょっと使ってみたいなぁと思ったのですが、
git を使えないし、会社で使う予定もないので使う機会はなさげ。
あとは、コミット毎にレビューと検証をするのは面倒な気もしました。
そのへんは、やり方がなんかあるのかもしれませんが・・・

中規模プロジェクトでのJenkinsの運用を支える技術
例題が自分の分野とは違って、ピンと来なかったが、
プロジェクトの管理する方も自動化できるとこはして楽をしようという話。(きっとそう)
スクリプトコンソールや Configuration Slicing Plugin は会社でも使ってみようと思いました。

Amazon EC2でJenkinsを使ってみる
Amazon EC2 は、Amazon Elastic Compute Cloud のこと。
EC2 をスレーブマシンと使える。それは非常に魅力的だが、
従量課金の点やセキュリティの面を考えると会社で使うのは難しいかも。
(EC2 についてちゃんと調べてみようとは思う。使うかどうかはそれからかなぁ)

ちなみに、蛙本は会社で購入してもらう予定。


Building Jenkins plugin with Ruby
ruby わからないので何やってるのかサッパリだったが、
すごく簡単そうにプラグインができてた。
Jenkins のプラグインは作ったことがないが、やってみようかなぁ…

Arduino でつくる XFD のつくり方とその効果
Arduino を使った XFD (eXtreme Feedback Device) の実物をデモで見せていただけた。

Arduino はこんなの。


これに、赤色のランプが繋がったもので、
Jenkins でビルドが失敗するとランプが点滅する仕組み。

これを開発部屋においておけば、嫌でも Jenkins の失敗を無視できなくなるという寸法。
自分でもできそうだったので、今度やってみようと思いました。


総評
予めタイムテーブルを見て、自分の使用範囲とは少し違うなとは思っていたが、
やっぱり少し違った。
でも、直接会場に出向いて生の声を聞いてモチベーションが上がったし、持ち帰れる内容もいっぱいあった。

勉強会では、ブラウザを眺めているだけでは得られないモノが手に入りますね。
今後も、機会があれば勉強会に参加していきたいと思います。

2012年2月2日木曜日

iutest の公開

以前、ブログで書いた自作の C++テストフレームワーク を SourceForge にて公開しました。

iutest といいます。
iutest は、Google Test のインターフェイスを踏襲した、C++ テストフレームワークです。
今回、リリースバージョンではありませんが、ベータ版として公開することにました。

iutest にできて、gtest にできないものはなく。
gtest にできて、iutest にできないものはある。まだまだ貧弱なフレームワークですが、
include するだけで使えることを目的として作成しています。

あとは、一応ゲーム会社に勤務しているので、その辺の環境でも使えるように意識はしてます…

テストは自分の周りにある環境でしかできていないので、
ビルドできなかったり、正常動作しなかったりする環境があるかもしれません。


ご意見・ご感想などいただけると嬉しいです。