読者です 読者をやめる 読者になる 読者になる

Natural Software

KinectなどのDepthセンサーを中心に活動しています

Visual Studio で GoogleMock を使う

C++ TDD

先日書いた GoogleTest の兄弟分である GoogleMock を Visual Studio で使ってみた。名前の通りのモックライブラリ。
ビルドでも意外と躓いたのでメモ。
#前提として GoogleTest の設定ができてることとする


はじめて使ったけど、結構いいかも

環境

ビルド

  1. http://code.google.com/p/googlemock/downloads/list からダウンロード
    • 試したのは gmock-1.5.0.zip
  2. 解凍して読み込み専用を外し、msvc/gmock.sln を実行
    • 変換ウィザードが動くので、「完了」を押す
  3. gmock プロジェクトの gmock-all.cc が無いとか言ってくるので、一度クリアして gmock/src にあるやつを追加
  4. gmock-all.cc の中でインクルードできないとか言ってくるので、#include を #include に変える
  5. gtest の関数の実体が無いとか言ってくるので、gmock の下にある gtest を消す
  6. ビルドはできるので、gmock_test を走らせる。なんか、2件の Fail が出た
  7. パスの設定
    • Visual Studio のメニュー[ツール|オプション]を選択
    • 「プロジェクトおよびソリューション|VC++ディレクトリ」(一番上に隠れてる)を選択
    • 「ディレクトリを表示するプロジェクト」から「インクルードファイル」を選択し、Google Mock のインクルードパス(ここでは「<配置フォルダ>\gmock-1.5.0\include」)を追加
    • 同じく「ライブラリファイル」を選択し、Google Mock のライブラリパス(ここでは「<配置フォルダ>\gmock-1.5.0\msvc\Debug」)を追加

使う

サンプル的なものを書いてみた。理解しているわけではないので、間違いがあるかもしれません。
大きく、EXPECT_CALL と ON_CALL があるようだけど、今回は EXCEPT_CALL だけー

#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <string>

// この行を gmock/gmock.h に入れとけばライブラリリンクもいらないかな
#pragma comment( lib, "gmock.lib" )

using testing::Invoke;
using testing::Return;
using testing::_;

// インタフェース
class Hello {
public:
    virtual std::string say() = 0;
};

// インタフェースのモック
class MockHello : public Hello {
public:
    MOCK_METHOD0( say, std::string () );
};

// テストしたいクラス
class Greeting
{
    Hello* hello_;

public:
    Greeting( Hello* hello ) : hello_( hello ) {}

    // あいさつ
    std::string hello() { return hello_->say(); }

    // 3回挨拶
    std::string hello3Times() {
        return hello_->say() + hello_->say() + hello_->say();
    }
};

// 英語であいさつ
TEST( HelloTest,  English ) {
    // モックを作って、返したいものを入れる
    MockHello mock_hello;	
    EXPECT_CALL( mock_hello, say()).WillOnce( Return( "hello" ) );

    // テストする
    Greeting greeting( &mock_hello );
    EXPECT_EQ( greeting.hello(), "hello" );
}

// 英語であいさつ(日本語で挨拶してしまった)
TEST( HelloTest,  English_Error ) {
    // モックを作って、返したいものを入れる
    MockHello mock_hello;	
    EXPECT_CALL( mock_hello, say()).WillOnce( Return( "こんにちは" ) );

    // テストする
    Greeting greeting( &mock_hello );
    EXPECT_EQ( greeting.hello(), "hello" );
}

// 日本語であいさつ
TEST( HelloTest,  Japanese ) {
    // モックを作って、返したいものを入れる
    MockHello mock_hello;	
    EXPECT_CALL( mock_hello, say()).WillOnce( Return( "こんにちは" ) );

    // テストする
    Greeting greeting( &mock_hello );
    EXPECT_EQ( greeting.hello(), "こんにちは" );
}

// 3回呼ぶ
TEST( HelloTest,  _3Times_Success ) {
    // モックを作って、返したいものを入れる
    MockHello mock_hello;	
    EXPECT_CALL( mock_hello, say())
        .Times( 3 )
        .WillRepeatedly( Return( "こんにちは" ) );

    // テストする
    Greeting greeting( &mock_hello );
    EXPECT_EQ( greeting.hello3Times(), "こんにちはこんにちはこんにちは" );
}

// 3回呼ぶ(と見せかけて一回しか呼ばない)
TEST( HelloTest,  _3Times_Error ) {
    // モックを作って、返したいものを入れる
    MockHello mock_hello;	
    EXPECT_CALL( mock_hello, say())
        .Times( 3 )
        .WillRepeatedly( Return( "こんにちは" ) );

    // テストする
    Greeting greeting( &mock_hello );
    EXPECT_EQ( greeting.hello(), "こんにちは" );
}

// 3回呼ぶ(3回呼ぶけど結果がダメ)
TEST( HelloTest,  _3Times_Error2 ) {
    // モックを作って、返したいものを入れる
    MockHello mock_hello;	
    EXPECT_CALL( mock_hello, say())
        .Times( 3 )
        .WillRepeatedly( Return( "こんにちは" ) );

    // テストする
    Greeting greeting( &mock_hello );
    EXPECT_EQ( greeting.hello3Times(), "hellohellohello" );
}

結果