Thanks Driven Life

日々是感謝

GoogleTest で標準出力、標準エラー出力をテストする

テストないと死んじゃう

Kinect ありきでの動作テストは、デバイスを持ち歩かないといけないということに加え、
いちいち「コンパイル → 立つ → パンチ → 座る → リファクタ」というかなりの重労働な
開発フローを辿らなければいけません。痩せるにはちょうどいいかも知れませんが。

そんなわけで、Tython は Google Test という Testing Framework を採用しています。
GogleTetst はその名のとおり、GoogleC++ Test Framework です。
CPPUnit など、C++ 用はいくつかあったのですが、採用理由をあげるとすれば

こんなところでしょうか。

基本的な使い方はドキュメントを見ていただければわかると思うので、
今回は、何故かドキュメントに載ってない、GoogleTest を使っててすごい助かったものを紹介します。

標準出力のテスト

Compiler 及び VM結合テストを兼ねて、「2 + 7 = 9」という計算プログラムをTython で動かすとします。
この計算を Tython ソースコードに落とすと以下の表になります。

source instruction
aaaaaag push 2
aaa@a@g push 7
@aaa add
@ a@ num_out

上表より、テストの流れは以下のようになります。

  1. "aaaaaagaaa@a@g@aaa@ a@" というソースコードを compile
  2. compile して生成された命令列を VM に渡し、実行
  3. 「9」が 標準出力 されれば SUCCESS

当初、最後の標準出力のテストをどうしようか、と悩んでいました。
自動テストなのに「数字が出力されるか目で見る」なんてやってられません。
しかも、数が増えれば増えるほど非現実的なテスト手法となります。

そんな時に GoogleTest!標準出力を検知してくれる API がありました。

#include <gtest/gtest.h>
#include <gtest/internal/gtest-port.h>

// 省略...

TEST_F(VMTest, TestRun) {
    Compiler *compiler = Compiler::instance();
    vector<Instruction*> insns;

    // 2 + 7 = 9 を stdout
    insns = compiler->compile("aaaaaagaaa@a@g@aaa@ a@");
    testing::internal::CaptureStdout(); // 標準出力キャプチャ開始
    object->run(insns); // 本来であれば標準出力される(キャプチャ中は出力されない)
    ASSERT_STREQ("9", testing::internal::GetCapturedStdout().c_str()); // キャプチャ終了
}

ね、簡単でしょ?

「testing::internal::CaptureStdout() 〜 testing::internal::GetCapturedStdout()」の間は、
標準出力されるはずだった文字列は保存され、最後の GetCaputuredStdout() で、溜まった文字列を取得できます。
あとは、期待される文字「9」と比較すればOK。これでテスト完了です。

標準エラー出力も同じで、
「testing::internal::CaptureStderr() 〜 testing::internal::GetCapturedStderr()」でOKです。

ちなみに、「Hello, World」をテストするとこうなります

    insns = compiler->compile("aaaa@@@@agaaaaa@@a@@gaaaaa@aa@@gaaaaaa@@a@gaaaaa@aaaagaaaa@a@aaagaaaa@@@@@gaaaa@aa@@gaaaaa@aaaagaaaaa@aa@@gaaaaa@aa@@gaaaaa@@a@agaaaa@@a@@@g@ aa@ aa@ aa@ aa@ aa@ aa@ aa@ aa@ aa@ aa@ aa@ aa@ aa");
    testing::internal::CaptureStdout();
    object->run(insns);
    ASSERT_STREQ("Hello, World!", testing::internal::GetCapturedStdout().c_str());

長いね〜

まとめ

TDD 最高!

実は冒頭で述べたデバイスありきで云々〜は、GoogleTest よりも GoogleMock が
力発揮しているのですが、それはまた後日書く予定です。