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 で公開しました。ご自由に使用してください。
また、これはほんの一例に過ぎませんので、気に食わないところがあったらカスタマイズしてみてください。

0 件のコメント:

コメントを投稿