Announce

PukiWiki contents have been moved into SONOTS Plugin (20070703)

GoogleMock

Google Mockの使い方

Table of Contents

Google Mockライブラリのダウンロード

http://googlemock.googlecode.com/files/gmock-1.6.0.zip

Cygwinの起動

Google Mockライブラリのビルド

   $ cd GMOCK_DIR/make
   $ make

GMOCK_DIRは、Google Mockをダウンロード後、配置したディレクトリ。

ビルド確認

サンプル・テストを実行。

   $ ./gmock_test
   Running main() from gmock_main.cc
   [==========] Running 13 tests from 3 test cases.
   [----------] Global test environment set-up.
   [----------] 6 tests from InitGoogleMockTest
   [ RUN      ] InitGoogleMockTest.ParsesInvalidCommandLine
   [       OK ] InitGoogleMockTest.ParsesInvalidCommandLine (0 ms)
   [ RUN      ] InitGoogleMockTest.ParsesEmptyCommandLine
   [       OK ] InitGoogleMockTest.ParsesEmptyCommandLine (0 ms)
   [ RUN      ] InitGoogleMockTest.ParsesSingleFlag
   [       OK ] InitGoogleMockTest.ParsesSingleFlag (0 ms)
   [ RUN      ] InitGoogleMockTest.ParsesUnrecognizedFlag
   [       OK ] InitGoogleMockTest.ParsesUnrecognizedFlag (0 ms)
   [ RUN      ] InitGoogleMockTest.ParsesGoogleMockFlagAndUnrecognizedFlag
   [       OK ] InitGoogleMockTest.ParsesGoogleMockFlagAndUnrecognizedFlag (0 ms)
   [ RUN      ] InitGoogleMockTest.CallsInitGoogleTest
   [       OK ] InitGoogleMockTest.CallsInitGoogleTest (1 ms)
   [----------] 6 tests from InitGoogleMockTest (1 ms total)
   
   [----------] 6 tests from WideInitGoogleMockTest
   [ RUN      ] WideInitGoogleMockTest.ParsesInvalidCommandLine
   [       OK ] WideInitGoogleMockTest.ParsesInvalidCommandLine (0 ms)
   [ RUN      ] WideInitGoogleMockTest.ParsesEmptyCommandLine
   [       OK ] WideInitGoogleMockTest.ParsesEmptyCommandLine (0 ms)
   [ RUN      ] WideInitGoogleMockTest.ParsesSingleFlag
   [       OK ] WideInitGoogleMockTest.ParsesSingleFlag (0 ms)
   [ RUN      ] WideInitGoogleMockTest.ParsesUnrecognizedFlag
   [       OK ] WideInitGoogleMockTest.ParsesUnrecognizedFlag (0 ms)
   [ RUN      ] WideInitGoogleMockTest.ParsesGoogleMockFlagAndUnrecognizedFlag
   [       OK ] WideInitGoogleMockTest.ParsesGoogleMockFlagAndUnrecognizedFlag (0 ms)
   [ RUN      ] WideInitGoogleMockTest.CallsInitGoogleTest
   [       OK ] WideInitGoogleMockTest.CallsInitGoogleTest (0 ms)
   [----------] 6 tests from WideInitGoogleMockTest (1 ms total)
   
   [----------] 1 test from FlagTest
   [ RUN      ] FlagTest.IsAccessibleInCode
   [       OK ] FlagTest.IsAccessibleInCode (0 ms)
   [----------] 1 test from FlagTest (0 ms total)
   
   [----------] Global test environment tear-down
   [==========] 13 tests from 3 test cases ran. (13 ms total)
   [  PASSED  ] 13 tests.

Mockテストの書き方(基礎編)

Google Mockドキュメントで利用されているサンプルから抜粋して編集したテスト。あるAPIを利用して、描画プログラムを開発しているケースでのテスト。以下の説明では、APIをラップしているインターフェイスをTurtle、開発/テストしたいプログラムがPainterクラス。まずは、Turtleインターフェイスの定義。

   #ifndef TURTLE_H
   #define TURTLE_H
   
   class Turtle
   {
    public:
     Turtle(){
     }
     virtual ~Turtle(){
     }
     virtual void PenUp() = 0;
     virtual void PenDown() = 0;
     virtual void Forward(int distance) = 0;
     virtual void Turn(int degrees) = 0;
     virtual void GoTo(int x, int y) = 0;
     virtual int GetX() const = 0;
     virtual int GetY() const = 0;
   };
   
   #endif

続いて、Painterクラスの定義。

   #ifndef PAINTER_H
   #define PAINTER_H
   
   #include "Turtle.h"
   
   class Painter {
    public:
     Painter(Turtle* turtle){
       this->turtle = turtle;
     }
     virtual ~Painter(){
     }
   
     bool DrawCircle(int x, int y, int radius){
       // このメソッドを実装したい。
       return true;
     }
   
    private:
     Turtle* turtle;
   };
   
   #endif

Painter::paintメソッドを実装するためのテスト・コードをMockクラスを利用して作成する。第1ステップは、Mockクラスの作成。Turtleインターフェイスは、まだ実装を持っていないためTurtleインターフェイスの実装となるMockTurtleクラスを作成する。第2ステップは、Mockクラスを利用したテスト・コードの作成。

Mockクラスの作成

Mock作成用のヘッダ(gmock.h)をインクルードし、マクロを利用してTurtleインターフェイスで定義されているメソッドを実装する。メソッドの引数の数により、使うマクロの名前が変わることに注意。例えば、引数なしメソッドは、MOCK_METHOD0マクロ、引数1個のメソッドはMOCK_METHOD1マクロを利用する。Google Mockでは引数10個までのマクロを定義している模様。(Mockメソッドを定義するためのマクロはgmock-generated-function-mockers.h内で定義)

   #ifndef MOCKTURTLE_H
   #define MOCKTURTLE_H
   
   #include "gmock/gmock.h"
   #include "Turtle.h"
   
   class MockTurtle : public Turtle {
    public:
     MOCK_METHOD0(PenUp, void());
     MOCK_METHOD0(PenDown, void());
     MOCK_METHOD1(Forward, void(int distance));
     MOCK_METHOD1(Turn, void(int degrees));
     MOCK_METHOD2(GoTo, void(int x, int y));
     MOCK_CONST_METHOD0(GetX, int());
     MOCK_CONST_METHOD0(GetY, int());
   };
   #endif

テスト・コードの作成

作成したMockクラスを利用して、テスト・コードを作成する。Mockオブジェクトを利用したテストでは、テスト対象のオブジェクトが、仕様通りに他のオブジェクトと協調しているかテストすることができる。例えば、上記のPainter::DrawCircleメソッドでは、円を描くために、Turtle::PenDownメソッド(キャンバスに線を書くために呼び出すメソッド)を最低でも1度呼び出さなければいけないので、以下のようなテスト(test.cpp)を書く。

   #include "gmock/gmock.h"
   #include "gtest/gtest.h"
   
   #include "MockTurtle.h"
   #include "Painter.h"
   
   using ::testing::AtLeast;
   
   TEST(PainterTest, CanDrawSomething){
     MockTurtle turtle;
   
     EXPECT_CALL(turtle, PenDown())
         .Times(AtLeast(1));// PenDownメソッドが最低でも1度呼ばれることをチェックするためのExpectationを指定。
   
     Painter painter(&turtle);
   
     EXPECT_TRUE(painter.DrawCircle(0,0,10));
   }
   
   int main(int argc, char** argv) {
     ::testing::InitGoogleMock(&argc,argv);
     return RUN_ALL_TESTS();
   }

テストの実行

作成したテストをビルドして、実行する。DrawCirleメソッドが実装されていないため、テストは失敗し、失敗したテストの情報が表示される。あとは、このテストが通るようにDrawCircleメソッドを実装していく。

Linux(Ubuntu)上では、ビルド・コマンドに"-lpthread"オプションを追加する必要あり。

   $ g++ -I GMOCK_DIR -I GMOCK_DIR/include -I GMOCK_DIR/gtest/include test.cpp GMOCK_DIR/make/gmock_main.a -o my_sample_test
   $ my_sample_test.exe 
   [==========] Running 1 test from 1 test case.
   [----------] Global test environment set-up.
   [----------] 1 test from PainterTest
   [ RUN      ] PainterTest.CanDrawSomething
   test.cpp:12: Failure
   Actual function call count doesn't match EXPECT_CALL(turtle, PenDown())...
            Expected: to be called at least once
              Actual: never called - unsatisfied and active
   [  FAILED  ] PainterTest.CanDrawSomething (0 ms)
   [----------] 1 test from PainterTest (0 ms total)
   
   [----------] Global test environment tear-down
   [==========] 1 test from 1 test case ran. (1 ms total)
   [  PASSED  ] 0 tests.
   [  FAILED  ] 1 test, listed below:
   [  FAILED  ] PainterTest.CanDrawSomething
   
    1 FAILED TEST

参考URL

Google Mockのプロジェクト・ホームページ。

http://code.google.com/p/googlemock/

Mockオブジェクトを利用したテストに関するエッセイ。MockオブジェクトとStubの違いなど、Mockオブジェクトは、どのようなテストに利用するべきか知りたい人には勉強になると思います。

http://martinfowler.com/articles/mocksArentStubs.html