2012年6月29日金曜日

CCCC + Jenkins

CCCC とは
CCCC は、「C and C++ Code Counter」の略称で、C や C++ のコードメトリクスツールです。
こちらからダウンロードできます。

今回は、CCCC と Jenkins の連携について書きたいと思うので、
コードメトリクスや CCCC の使い方に関しては省かせて頂きます。

Jenkins との連携 - CCCC Plugin
CCCC Plugin というプラグインが既にあるので、それを使います。

設定としては、「Publish CCCC report」にチェックを入れて cccc が吐き出した xml のパスを入力するだけです。

試しに収集した結果がこちらです。



プロジェクト全体のコード行数や複雑度を見ることができます。

ただ、残念なことにプロジェクト全体やクラス単位でのメトリクス値を見ることはできているのですが、関数単位など細かい情報を見ることができません。
(※知らないだけで方法があるのかもしれませんが。)

CCCC の出力XMLをテスト
一番確認したい関数ごとの行数や複雑度を閲覧する方法が見つからなかったので、
CCCC の出力XMLを調べて Jenkins の「JUnitテスト結果の集計」で利用できる XML を出力するツールを作りました。

c4ju

試しに出力してみた結果がこちらです。






複雑な関数や長い関数を見つけやすくなりました。これで CCCC の恩恵が受けられます。

2012年6月17日日曜日

iutest v1.0 RC リリース

本日 iutest v1.0 RC をリリースしました。
ダウンロードはこちらから
iutest とは
iutest は include するだけで使えることを目的とした C++ のテスティングフレームワークです。
Google Test と同等の記述方式を取っているので、Google Test 使ってみようかなぁと思っている方にはオススメです。

逆に Google Test をガッツリ使ってるよ!という方にはオススメできないです。
なぜなら、iutest にはできないことがいくつかあるからです。

iutest にできないこと
  • マルチスレッド非対応
  • Death テスト
大きな項目としては少なく感じますが、
細かい部分で Google Test と異なる部分があるのでご注意ください。

iutest にしかできないこと
  • 記法の異なるパラメタライズテスト(IUTEST_PMZ)
  • INFORM アサーション(警告)
  • 追加アサーション(IUTEST_*_NULL, IUTEST_*_NOTNULL etc...)
  • イベントリスナーで RecordProperty 時に呼ばれる OnTestRecordProperty が利用可能
  • Variadic Templates などの C++11 対応
  • private メンバーへのアクセス機能(IUTEST_PEEP)
  • return ではなく例外を使った ASSERT マクロ(-DIUTEST_THROW_ON_ASSERT_FAILURE=1)
などなど。細かくなりすぎるのでこれぐらいにしておきます。
iutest には Google Test の実装を利用する機能もあります。(-DIUTEST_USE_GTEST)
また、逆に iutest の機能を Google Test でも使えるようにするヘッダーも用意しています。
(ただし、一部互換性なし)

バグ報告お待ちしてます
実際に使用して頂ける方、大募集中です。
気になった方はダウンロードして試していただけると大変ありがたいです。
そして、不具合等があれば twitter などで気軽に連絡して頂けると嬉しいです。

2012年6月14日木曜日

iutest にパラメタライズテストの記法を追加

iutest に Google Test とは異なる記法のパラメタライズテストを追加しました。

サンプルコード
void TestFunction(int x, int y)
{
    IUTEST_ASSERT_EQ(x, y);
}
IUTEST_PMZ(ParamMethodTest, EQ, TestFunction, 0, 0);
IUTEST_PMZ(ParamMethodTest, EQ, TestFunction, 1, 2);
IUTEST_PMZ(ParamMethodTest, EQ, TestFunction, 2, 2);

typedef TestFixed ParamMethodTestFixed;

IUTEST_PMZ_F(ParamMethodTestFixed, EQ, TestFunction, 0, 0);
IUTEST_PMZ_F(ParamMethodTestFixed, EQ, TestFunction, 1, 2);
IUTEST_PMZ_F(ParamMethodTestFixed, EQ, TestFunction, 2, 2);

実行結果


"GetParam() = " と出力されますが、既存の仕組みを再利用しているのでそうなってます。
あと、良い名前が思い浮かばなかったのでイイ名前を募集中です。

2012年6月3日日曜日

Google Test で成功時のメッセージを非表示にする方法

TDDBC 大阪。参加すればよかったなぁと、ツイッターを眺めていたら興味深いつぶやきがありました。
「GoogleTestはOKなテストも全部表示されてしまう」設定で切り替える方法はあるだろうか?

私の知る限りでは、できないです。
「設定」というのがマクロ定義やコマンドラインオプションであるなら、そのような機能はなかったと思います。

ただし、
「イベントリスナー」を使えばできちゃいます。

イベントリスナーって?
Google Test にはイベントリスナーというものがあります。
これについては、マニュアルにも記載されてますので参考にしてください。

イベントリスナーは、テストケースやテストが開始・終了したとき、テストが失敗したときなど、
Google Test で発生したイベントを処理することができます。
デフォルトのコンソール出力や XML 出力もこのイベントリスナーで実装されています。

というわけで、このデフォルトイベントリスナーを置き換えることで目的が達成できます。

実装
class QuietResultPrinter : public ::testing::TestEventListener
{
public:
    QuietResultPrinter(::testing::TestEventListener* default_printer)
        : m_default_printer(default_printer)
    {}

    virtual void OnTestEnd(const ::testing::TestInfo& test_info)
    {
        if( test_info.result()->Failed() )
        {
            // 失敗したときのみ出力する
            m_default_printer->OnTestEnd(test_info);
        }
    }
    // その他のイベントは、デフォルトをそのまま呼ぶ
    // ...
private:
    ::testing::TestEventListener* m_default_printer;
};

まずは、::testing::TestEventLisener を継承してカスタムイベントリスナーを作成します。
本当は、デフォルトコンソール出力イベントリスナーを継承したいのですが、
こちらはヘッダーに公開されていないので、ポインターを受け取ってデフォルトを呼ぶようにしています。
デフォルトのイベントリスナーは、UnitTest::GetInstance()->listeners().default_result_printer() で取得できます。

OnTestEnd 関数は、テストが終了したときに呼ばれるイベントです。
ここでテストが失敗したかどうか判定し、失敗した場合のみデフォルトの出力をするようにしています。

省略されていますが、他のイベントに対してはデフォルトを呼ぶようにします。

次にこのイベントリスナーを Google Test に登録します。

::testing::TestEventListeners& listeners =
    ::testing::UnitTest::GetInstance()->listeners();
::testing::TestEventListener* def =
    listeners.Release(listeners.default_result_printer());
listeners.Append(new QuietResultPrinter(def));
return RUN_ALL_TESTS(); // run all

listners.Release でデフォルトの登録を解除し、Append でカスタムイベントリスナーを登録します。
実行結果がこちら。
※画像が小さいですが、クリックすると大きく表示されます。

左がデフォルトイベントリスナーで、右がカスタマイズしたイベントリスナーの出力です。
少しコンパクトになりましたね。

もう少し変更
テスト開始時の出力も非表示にしてしまおうと思います。

virtual void OnTestStart(const ::testing::TestInfo& test_info) {}

    virtual void OnTestPartResult(const ::testing::TestPartResult& test_part_result)
    {
        if( ::testing::UnitTest::GetInstance()->current_test_info() != NULL )
        {
            const ::testing::TestInfo& test_info = *::testing::UnitTest::GetInstance()->current_test_info();
            if( test_info.result()->Failed()
                && test_info.result()->total_part_count() == 1 )
            {
                m_default_printer->OnTestStart(test_info);
            }
        }
        m_default_printer->OnTestPartResult(test_part_result);
    }

先ほどの、QuietResultPrinter を変更します。
OnTestStart ではテストが失敗したかまだわからないので、なにも出力しません。
OnTestPartResult 関数でテスト結果が来た時に、最初の失敗の時だけデフォルトの開始メッセージを出力するようにしてみました。

これを実行するとこのようになります。


ただし、これには問題があります。
テスト開始から最初の失敗までに出力があった場合に、それが開始メッセージよりも前に表示されてしまいます。
その点に注意してください。

OnTestCaseStart/End も同様に変更すれば、さらに簡潔になると思います。

最後に
今回紹介したコードを github で公開しました。ご自由に使用してください。
また、これはほんの一例に過ぎませんので、気に食わないところがあったらカスタマイズしてみてください。