クックブック

Google C++ Mocking Framework クックブック

ここでは,Google Mock を利用したレシピを紹介します.もし未読ならば,基礎を確実に理解するために,ドキュメント 超入門編 を読んでください.

注意: Google Mock は testing 名前空間に属しています.読みやすいように,Google Mock で定義された Foo を利用する各ファイルで,それより前に using ::testing::Foo; を書くことをお勧めします.このページでは,簡潔さのためにそのような文を省略していますが,自分のコードではちゃんと書いてください.

モッククラスを作る

Private または Protected なメソッドをモック化する

モック化されるメソッドが基底クラスにおいて public か protected か private か,に関わらず,モックメソッドの定義(MOCK_METHOD*)は,必ずモッククラスの public: セクションに書く必要があります.これによって,モッククラス外部の ON_CALL および EXPECT_CALL が,モック関数を参照できます.(そう,C++ では,基底クラスの仮想関数のアクセスレベルを派生クラスで変更することができます.)以下に例を示します:

class Foo {
 public:
  ...
  virtual bool Transform(Gadget* g) = 0;

 protected:
  virtual void Resume();

 private:
  virtual int GetTimeOut();
};

class MockFoo : public Foo {
 public:
  ...
  MOCK_METHOD1(Transform, bool(Gadget* g));

  // 基底クラスのメソッドが protected や private でも
  // 以下は必ず public にしてください.
  MOCK_METHOD0(Resume, void());
  MOCK_METHOD0(GetTimeOut, int());
};

オーバーロードされたメソッドをモック化する

オーバーロードされた関数も同じようにモック化することができます.特に気を付けることはありません.

class Foo {
  ...

  // Foo を継承するので,これは必ず virtual.
  virtual ~Foo();

  // 引数の型や数を変えてオーバーロードされます.
  virtual int Add(Element x);
  virtual int Add(int times, Element x);

  // オブジェクトの const のありなしでオーバーロードされます.
  virtual Bar& GetBar();
  virtual const Bar& GetBar() const;
};

class MockFoo : public Foo {
  ...
  MOCK_METHOD1(Add, int(Element x));
  MOCK_METHOD2(Add, int(int times, Element x);

  MOCK_METHOD0(GetBar, Bar&());
  MOCK_CONST_METHOD0(GetBar, const Bar&());
};

注意: オーバーロードされたメソッドの全バージョンをモック化するわけではない場合,基底クラスのメソッドが見えない状態になっている,という警告をコンパイラが出します.これを修正するには,スコープ内にインポートするために using を使ってください:

class MockFoo : public Foo {
  ...
  using Foo::Add;
  MOCK_METHOD1(Add, int(Element x));
  // int Add(int times, Element x); の方はモック化したくありません.
  ...
};

クラステンプレートをモック化する

クラステンプレートをモック化するには,MOCK_* マクロに _T を追加します:

template <typename Elem>
class StackInterface {
  ...
  // StackInterface を継承するので,これは必ず virtual.
  virtual ~StackInterface();

  virtual int GetSize() const = 0;
  virtual void Push(const Elem& x) = 0;
};

template <typename Elem>
class MockStack : public StackInterface<Elem> {
  ...
  MOCK_CONST_METHOD0_T(GetSize, int());
  MOCK_METHOD1_T(Push, void(const Elem& x));
};

非仮想メソッドをモック化する

Google Mock は, 高効率な依存性の注入 時に利用するために,非仮想関数をモック化することができます.

この場合,実際のクラスとモッククラスで基底クラスを共有するのではなく,モッククラスと実際のクラスは無関係になりますが,これらは同じシグネチャのメソッドを持ちます.非仮想メソッドをモック化するための構文は,仮想メソッドをモック化する際と同様です.

// 簡単なパケットストリームクラス.virtual なメンバはありません.
class ConcretePacketStream {
 public:
  void AppendPacket(Packet* new_packet);
  const Packet* GetPacket(size_t packet_number) const;
  size_t NumberOfPackets() const;
  ...
};

// モックパケットストリームクラス.何も継承しませんが,
// GetPacket() と NumberOfPackets() は定義されます.
class MockPacketStream {
 public:
  MOCK_CONST_METHOD1(GetPacket, const Packet*(size_t packet_number));
  MOCK_CONST_METHOD0(NumberOfPackets, size_t());
  ...
};

モッククラスは,実際のクラスとは異なり AppendPacket() を定義していないことに注意してください.テストがこれの呼び出しを必要としない限り,問題はありません.

次に,製品版コードでは ConcretePacketStream を,テストコードでは MockPacketStream を使用する,ということを明示する必要があります.この関数は仮想関数ではなく,2つのクラスは無関係なので,(実行時ではなく)コンパイル時に指定する必要があります.

方法の1つは,パケットストリームを利用しなければならないコードをテンプレート化することです.より具体的には,コードにテンプレート型引数を導入して,これをパケットストリームの型とします.製品では,テンプレートに型引数として ConcretePacketStream を与えてインスタンス化します.また,テストでは,同じテンプレートに MockPacketStream を与えてインスタンス化します.次に例を示します:

template <class PacketStream>
void CreateConnection(PacketStream* stream) { ... }

template <class PacketStream>
class PacketReader {
 public:
  void ReadPackets(PacketStream* stream, size_t packet_num);
};

そして,製品コードでは,CreateConnection<ConcretePacketStream>() と PacketReader<ConcretePacketStream> を,テストでは,CreateConnection<MockPacketStream>() と PacketReader<MockPacketStream> を利用します.

MockPacketStream mock_stream;
EXPECT_CALL(mock_stream, ...)...;
// ... mock_stream に,いろいろな Expectation を設定します ...
PacketReader<MockPacketStream> reader(&mock_stream);
// ... reader を実行します ...

フリー関数をモック化する

Google Mock を使って,フリー関数(つまり,C形式の関数,または static メソッド)をモック化することもできます.必要なのは,コードをインタフェース(抽象クラス)を使うように書き直すことだけです.

フリー関数(例えば,OpenFile)を直接呼び出す代わりに,そのインタフェースを導入し,具象クラス派生させ,そこでフリー関数を呼び出します.

class FileInterface {
 public:
  ...
  virtual bool Open(const char* path, const char* mode) = 0;
};

class File : public FileInterface {
 public:
  ...
  virtual bool Open(const char* path, const char* mode) {
    return OpenFile(path, mode);
  }
};

コードでは ,ファイルを開くために FileInterface を利用します.このように,フリー関数をモック化するのは簡単です.

これは面倒に見えるかもしれませんが,実際には,同じインタフェースに入れられる複数の関連する関数があるので,1つの関数を書く上での労力はより小さくなります.

仮想関数によるパフォーマンスオーバーヘッドが心配で,実際にそれをプロファイラで確認したなら, 非仮想メソッドをモック化する のレシピと併用することもできます.

Nice モックと Strict モック

EXPECT_CALL が指定されていないにもかかわらず,そのメソッドが呼び出されると,Google Mock は,”uninteresting call” の警告を出力します.その理由は次の通りです:

  • テストを書いた後にインタフェースに新しいメソッドが追加された可能性がある.知らないメソッドが呼び出されたから,という理由のみでテストを失敗させるべできはない.
  • しかし,テストのバグという可能性もあるので,Google Mock は黙って見過ごすべきでもない.この呼び出しが無害だとユーザが分かっているならば,EXPECT_CALL() を追加してこの警告を消すことができる.

しかし,全ての “uninteresting call” 警告を抑制したい場合や,その正反対の場合,例えば,全部エラーとして扱いたい,といった場合があるかもしれません. Google Mock では,モックオブジェクト毎にそれを決めることができます.

テストで MockFoo というモッククラスを使う場合を考えます:

TEST(...) {
  MockFoo mock_foo;
  EXPECT_CALL(mock_foo, DoThis());
  // ... mock_foo を利用するコード ...
}

DoThis() 以外の mock_foo メソッドが呼び出されると,Google Mock によって警告が出されます.しかし,代わりに NiceMock<MockFoo> を使うようにテストを書き直すと,この警告は消え,綺麗な出力結果になります.

using ::testing::NiceMock;

TEST(...) {
  NiceMock<MockFoo> mock_foo;
  EXPECT_CALL(mock_foo, DoThis());
  // ... mock_foo を利用するコード ...
}

NiceMock<MockFoo> は,MockFoo の派生クラスなので,MockFoo が使える場所ならどこでも利用可能です.

NiceMock<MockFoo> は MockFoo のコンストラクタを「継承」するので,MockFoo のコンストラクタが引数をとる場合も問題なく動作します.

using ::testing::NiceMock;

TEST(...) {
  NiceMock<MockFoo> mock_foo(5, "hi");  // MockFoo(5, "hi") を呼び出します.
  EXPECT_CALL(mock_foo, DoThis());
  // ... mock_foo を利用するコード ...
}

StrictMock の使い方も同様ですが,こちらは不要な呼び出しをすべて失敗として扱います.

using ::testing::StrictMock;

TEST(...) {
  StrictMock<MockFoo> mock_foo;
  EXPECT_CALL(mock_foo, DoThis());
  // ... mock_foo を利用するコード ...

  // mock_foo の DoThis() 以外のメソッドが呼び出されると,
  // テストは失敗します.
}

いくつかの注意事項があります(私はこういうのが人一倍好きではないのですが,悲しいかな c++ の制限による副作用なのです):

  1. NiceMock<MockFoo> と StrictMock<MockFoo> は,MockFoo クラス内で 直接 MOCK_METHOD* 関連のマクロを使って定義されたモックメソッドに対してのみ有効です.MockFoo の 基底クラス で定義されたモックメソッドに対して,”nice” や “strict” の修飾子が影響するかどうかはコンパイラ依存です.特に,NiceMock と StrictMock がネストしている場合(例えば,NiceMock<StrictMock<MockFoo> >)はサポートされません.
  2. 基底モッククラス(MockFoo)のコンストラクタは,const ではない参照で渡された引数をとることができません.これは,図らずも Google C++ style guide で禁止されています.
  3. MockFoo のコンストラクタやデストラクタの実行中は,モックオブジェクトは nice や strict ではありません.なので,コンストラクタやデストラクタが,this オブジェクトのモックメソッドを呼び出した場合,予期しないことが起こる可能性があります.(しかし,この挙動は,C+++ の一般的なルールに矛盾するものではありません:コンストラクタやデストラクトが,this オブジェクトの仮想メソッドを呼び出した場合,そのメソッドは非仮想関数として扱われます.言い換えれば,基底クラスのコンストラクタやデストラクタに対して,this オブジェクトは,派生クラスではなく基底クラスのインスタンスのように振る舞う,ということです.このルールは安全性のために必要です.これがなければ,基底クラスのコンストラクタが初期化前の派生クラスのメンバを使う可能性や,基底クラスのデストラクタが破棄されてしまった派生クラスのメンバを使う可能性があります.)

最後に,この機能は,モッククラスの今後すべてに変更を適用するという決断なので, 非常に慎重に 利用するべきです.モック化しているインタフェースに(そして,モックラスにも)重大な変更が起こった場合,テストが破壊される可能性(StrictMock を利用する場合)や,バグが警告されず見過ごされる可能性(NiceMock を利用する場合)があります.したがって,まずは EXPECT_CALL を明示してモックの挙動を指定しましょう.NiceMock や StrictMock は最後の手段と考えるべきです.

既存のコードを壊さずにインタフェースを単純化する

メソッドが多くの引数をとるものの,そのほとんどが不要,という場合があります.

class LogSink {
 public:
  ...
  virtual void send(LogSeverity severity, const char* full_filename,
                    const char* base_filename, int line,
                    const struct tm* tm_time,
                    const char* message, size_t message_len) = 0;
};

このメソッドの引数リストは長く,扱いにくいものです(引数 message が 0-終端でさえないと仮定しています).もしこれを,そのままモック化すると,モックの利用が大変になります.かといって,このインタフェースを簡単にしようとすると,これに依存するもの全てを修正しなければならなくなり,これは大抵の場合不可能です.

メソッドをモッククラスに再ディスパッチするのがミソです:

class ScopedMockLog : public LogSink {
 public:
  ...
  virtual void send(LogSeverity severity, const char* full_filename,
                    const char* base_filename, int line, const tm* tm_time,
                    const char* message, size_t message_len) {
    // ログの重要度(severity),完全なファイル名(full_filename),
    // そして,メッセージ(message) のみが必要とされます.
    Log(severity, full_filename, std::string(message, message_len));
  }

  // モックメソッドを実装します:
  //
  //   void Log(LogSeverity severity,
  //            const string& file_path,
  //            const string& message);
  MOCK_METHOD3(Log, void(LogSeverity severity, const string& file_path,
                         const string& message));
};

限定された引数をとる新しいモックメソッドを定義することで,ユーザフレンドリーなモッククラスを作成できます.

具象クラスのモック化に対する代替案

インタフェースを持たないクラスを利用することも多々あるかもしれません.そして,そのようなクラス(これを,具象クラスと呼びましょう)を利用するコードをテストするために,具象クラスのメソッドを仮想メソッドにして,それをモック化するという誘惑に駆られるかもしれません.

そのようなことはしないでください.

非仮想関数を仮想関数に変更するのは重大な決断です.これによって,派生クラスがあなたのクラスの挙動を変更できてしまう拡張ポイントが作成されます.クラスを不変な状態に保つのが難しくなるので,そのクラスに対するあなたの支配力が弱まります.派生クラスがそれをオーバーライドする正当な理由がある場合のみ,仮想関数に変更するべきでしょう.

具象クラスを直接モック化するのも問題です.そのクラスとテストが密接に結びついてしまうので,クラスの些細な変更によってテストが無効になり,テストのメンテナンスが大変面倒なことになるかもしれません.

このような問題を避けるために,多くのプログラマが「インタフェースに対するコーディング」を実践してきました:この場合,具象クラスを扱う代わりに,あなたのコードでインタフェースを定義し,それに対して処理を行うことになります.そしてインタフェースは,具象クラスにかぶせるアダプタとして実装されます.テストでは,そのインタフェースをモック化して,コードの挙動をより簡単に観測できます.

このテクニックは,多少のオーバーヘッドを引き起こします:

  • 仮想関数を呼び出すコストを払うことになります(これが問題になることは,ほとんどありませんが).
  • プログラマは抽象化について学ぶ必要があります.

しかし,テストしやすくなる上に,次のような十分な恩恵がもたらされます:

あるサービスを利用しているのがあなた1人ではなく,その具象クラスの API が,あなたの問題に対してあまり適切ではないことがあるかもしれません.あなた自身のインタフェースを設計すれば,単にクラスを整理するだけでなく,高度な機能の追加や,名前の変更などを行って,それを自分の必要にうまく合わせることができる場合があります.これによって,(インタフェースを利用する)あなたのコードがより自然で読みやすいものになり,生産性が向上します. 具象クラスの実装の変更が必要になったとしても,それを利用している側では書き換えの必要がありません.あなたのインタフェースの実装がその変更を吸収して,そのほかのコードを変更の影響から守ることができます. このテクニックを皆が使うと冗長なコードが大量に書かれる羽目にならないか,と心配する人もいます.この心配はもっともですが,そうはならない理由が2つあります:

  • 異なるプロジェクトでは,異なる方法で具象クラスを使う必要がありますので,最適なインタフェースはそれぞれ違ったものになります.したがって,具象クラスに各自が特有のインタフェースをかぶせることになり,それらは同じコードにはなりません.
  • 同じインタフェースを使いたいプロジェクトが沢山あれば,具象クラスを共有するのと同じように,いつでもそれを共有できます.インタフェースやアダプタを具象クラスの近く(おそらくは,contrib サブディレクトリの中)にチェックインして,多くのプロジェクトにそれを利用してもらうことができます

あなたの問題に対する利点と欠点を慎重に見極める必要があります.しかし,Java コミュニティでは長い間これが実践されており,さまざまな状況に適用できる効率的な手法であることが証明されている,ということは断言しておきましょう.:-)

フェイクに呼び出しを委譲する

インタフェースのフェイク実装が重要なものである場合があります.以下に例を示します.

class Foo {
 public:
  virtual ~Foo() {}
  virtual char DoThis(int n) = 0;
  virtual void DoThat(const char* s, int* p) = 0;
};

class FakeFoo : public Foo {
 public:
  virtual char DoThis(int n) {
    return (n > 0) ? '+' :
        (n < 0) ? '-' : '0';
  }

  virtual void DoThat(const char* s, int* p) {
    *p = strlen(s);
  }
};

さて,Expectation を設定できるようにこのインタフェースをモック化したい,とします.しかし,デフォルトの動作で FakeFoo も利用したいとなると,モックオブジェクト内でこれを再現することになり,作業が大変になります.

Google Mock を利用してモッククラスを定義する際,次のパターンを利用して,デフォルト Action を既存のフェイククラスに委譲することができます:

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

class MockFoo : public Foo {
 public:
  // Google Mock による通常のモックメソッド定義
  MOCK_METHOD1(DoThis, char(int n));
  MOCK_METHOD2(DoThat, void(const char* s, int* p));

  // そのメソッドのデフォルト Action を FakeFoo オブジェクトに委譲します.
  // これは必ず,ON_CALL() 文よりも *前* に呼ばれる必要があります.
  void DelegateToFake() {
    ON_CALL(*this, DoThis(_))
        .WillByDefault(Invoke(&fake_, &FakeFoo::DoThis));
    ON_CALL(*this, DoThat(_, _))
        .WillByDefault(Invoke(&fake_, &FakeFoo::DoThat));
  }
 private:
  FakeFoo fake_;  // フェイクのインスタンスをモック内部に保持しておきます.
};

こうすると,テストコードで MockFoo をいつもどおり利用できます.ON_CALL() または EXPECT_CALL() で Action を明示的に指定しない場合,このフェイクが呼ばれることだけ考慮してください.

using ::testing::_;

TEST(AbcTest, Xyz) {
  MockFoo foo;
  foo.DelegateToFake(); // 委譲先のフェイクを有効にします.

  // 必要なら,ON_CALL(foo, ...) をここに.

  // Action が指定されない場合,このデフォルト Action が利用されることを意味します.
  EXPECT_CALL(foo, DoThis(5));
  EXPECT_CALL(foo, DoThat(_, _));

  int n = 0;
  EXPECT_EQ('+', foo.DoThis(5));  // FakeFoo::DoThis() が呼び出されます.
  foo.DoThat("Hi", &n);           // FakeFoo::DoThat() が呼び出されます.
  EXPECT_EQ(2, n);
}

ヒント:

  • あなたが望むなら,ON_CALL() や EXPECT_CALL() 内で .WillOnce() / .WillRepeatedly() を使って,このデフォルト Action をオーバーライドすることもできます.
  • DelegataToFake() 内部で必要なことは,実際に使いたいフェイク実装にメソッドを委譲することだけです.
  • ここで議論される一般的なテクニックはオーバーロードされたメソッドに対しても動作しますが,どのバージョンを使うのかをコンパイラに教える必要があります.(ON_CALL() の丸カッコ内部で指定する)モック関数の曖昧さを解消するには,このページの「 オーバーロードされた関数の選択 」のセクションを参照してください.また,(Invoke() 内に書く)フェイク関数の曖昧さを解消するには,static_cast を利用して関数の型を指定します.
  • モックとフェイクをミックスせざるを得ない状況は,何らかの不具合の表れである場合が多いです.おそらく,まだインタラクションに基づくテストのやり方に慣れていないのでしょう.あるいは,インタフェースに多くの役割がありすぎて,それを分割するべきなのかもしれません.そういうことなので, この方法を乱用しないようにしてください .コードをリファクタリングするときの中間段階としてのみ利用することをお勧めします.

ヒントで述べたモックとフェイクを混ぜる話に関して,それがなぜ悪い兆候なのかを示す例を挙げます:ローレベルのシステム操作,具体的には,ファイル操作と I/O 操作を行う System クラスがあるとします.そして,I/O 操作を行うために System を利用しているコードのテストを行いたいとしましょう.このとき,ファイル操作に関しては,普通に動作すればよいものとします.ここで,System クラス全体をモック化すると,ファイル操作部分に関するフェイク実装を用意する必要が生じてしまいます.これは,System の役割が多すぎることを示唆しています.

代わりに,FileOps インタフェースと IOOps インタフェースを定義し,System の機能を2つに分割する方法があります.すると,FileOps をモック化することなく,IOOps だけをモック化できます.

実際のオブジェクトに呼び出しを委譲する

テスト用の身代わり(モック,フェイク,スタブ,など)を利用する際,これらの動作が実際のオブジェクトと異なることがあります.この違いには,意図的な場合(エラーハンドリングコードのテストができるように,エラーをシミュレートしている場合など)と,そうではない場合があります.もし,手違いで,モックの挙動が実際のオブジェクトと違ってしまうと,テストをパスしたコードでも製品では失敗してしまうことが起こりえます.

delegating-to-real というテクニックを使うと,呼び出しの検証能力はそのままに,モックと実際のオブジェクトとが同じ挙動であることを保証できます.このテクニックは,delegating-to-fake テクニックと非常に似ており,その違いは,フェイクの代わりに実際のオブジェクトを使う点です.次に例を示します.

using ::testing::_;
using ::testing::AtLeast;
using ::testing::Invoke;

class MockFoo : public Foo {
 public:
  MockFoo() {
    // デフォルトでは,すべての呼び出しが,実際のオブジェクトに委譲されます.
    ON_CALL(*this, DoThis())
        .WillByDefault(Invoke(&real_, &Foo::DoThis));
    ON_CALL(*this, DoThat(_))
        .WillByDefault(Invoke(&real_, &Foo::DoThat));
    ...
  }
  MOCK_METHOD0(DoThis, ...);
  MOCK_METHOD1(DoThat, ...);
  ...
 private:
  Foo real_;
};
...

  MockFoo mock;

  EXPECT_CALL(mock, DoThis())
      .Times(3);
  EXPECT_CALL(mock, DoThat("Hi"))
      .Times(AtLeast(1));
  // ... テストでモックを利用 ...

こうすることで,Google Mock が,あなたのコードの呼び出しが正しい(正しい引数を,正しい順番で,正しい回数,など)ことを検証し,実際のオブジェクトが,その呼び出しに答えます(よって,その動作は製品版と同じになります).これは,両者のいいとこどりです.

親クラスに呼び出しを委譲する

理想的には,インタフェースに対するコードを書くべきであり,そのメソッドはすべて純粋仮想関数であるはずです.しかし実際には,純粋仮想関数ではない仮想メソッド(つまり,すでに実装が存在するメソッド)をモック化する必要があります.以下に例を示します:

class Foo {
 public:
  virtual ~Foo();

  virtual void Pure(int n) = 0;
  virtual int Concrete(const char* str) { ... }
};

class MockFoo : public Foo {
 public:
  // 純粋仮想メソッドのモック化.
  MOCK_METHOD1(Pure, void(int n));
  // 具象メソッドのモック化.Foo::Concrete() is shadowed.
  MOCK_METHOD1(Concrete, int(const char* str));
};

時には,MockFoo::Concrete() の代わりに Foo::Concrete() を呼び出したいことがあります.スタブ動作の一部としてそうしたいのかもしれないし,実はテストで Concrete() をモック化する必要が全くないのかもしれません(しかし,そのメソッドの1つをモック化する必要がないときでも,新しいモッククラスを定義しなければならないのは,あぁ,恐ろしいことです).

このトリックを使うと,基底クラス内の実際のメソッドにアクセスする裏口をモックラスに残すことができます.

class MockFoo : public Foo {
 public:
  // 純粋仮想メソッドのモック化.
  MOCK_METHOD1(Pure, void(int n));
  // 具象メソッドのモック化.Foo::Concrete() is shadowed.
  MOCK_METHOD1(Concrete, int(const char* str));

  // Foo で定義された ConCrete() を呼び出すには,これを使います.
  int FooConcrete(const char* str) { return Foo::Concrete(str); }
};

これで,次のようにして Action の内部で Foo::Concrete() を呼び出すことができます:

using ::testing::_;
using ::testing::Invoke;
...
  EXPECT_CALL(foo, Concrete(_))
      .WillOnce(Invoke(&foo, &MockFoo::FooConcrete));

また,Concrete() をモック化したくないモックオブジェクトを使うには次のようにします:

using ::testing::Invoke;
...
  ON_CALL(foo, Concrete(_))
      .WillByDefault(Invoke(&foo, &MockFoo::FooConcrete));

(どうして,単に Invoke(&foo, &Foo::Concrete) を書くだけではだめなのでしょうか?もしそうすると,Foo::Concrete() は仮想メソッドなので,MockFoo::Concrete() が呼び出されます(そして,無限再帰に陥ります).これは,単に C++ の仕様です.)

Matcher を使う

引数の値に対して厳密にマッチさせる

モックメソッドが期待する引数を,厳密に指定することができます:

using ::testing::Return;
...
  EXPECT_CALL(foo, DoThis(5))
      .WillOnce(Return('a'));
  EXPECT_CALL(foo, DoThat("Hello", bar));

単純な Matcher を利用する

matcher を利用して,ある条件を満たす引数にマッチすることができます:

using ::testing::Ge;
using ::testing::NotNull;
using ::testing::Return;
...
  EXPECT_CALL(foo, DoThis(Ge(5)))  // 引数は,必ず >= 5
      .WillOnce(Return('a'));
  EXPECT_CALL(foo, DoThat("Hello", NotNull()));
  // 2番目の引数は,必ず NULL 以外.

よく使われる matcher は _ で,これは任意の入力にマッチします:

using ::testing::_;
using ::testing::NotNull;
...
  EXPECT_CALL(foo, DoThat(_, NotNull()));

Matcher を組み合わせる

AllOf(), AnyOf(), Not() を利用して,既存のものから複雑な matcher を構築できます:

using ::testing::AllOf;
using ::testing::Gt;
using ::testing::HasSubstr;
using ::testing::Ne;
using ::testing::Not;
...
  // 引数は,必ず > 5 かつ != 10.
  EXPECT_CALL(foo, DoThis(AllOf(Gt(5),
                                Ne(10))));

  // 1番目の引数は,部分文字列として "blah" を含みません.
  EXPECT_CALL(foo, DoThat(Not(HasSubstr("blah")),
                          NULL));

Matcher をキャストする

Google Mock の matcher は,静的に型付けされているので,ユーザが間違った型の matcher を使っていると(例えば,Eq(5) を文字列型の引数にマッチさせようとした場合など),その間違いをコンパイラがキャッチできます.よかったですね!

しかし時には,何をしているかを分かったうえで,コンパイラに見逃してほしい場合もあります.1つの例は,long に対する matcher があり,マッチさせたい引数が int の場合です.2つの型は厳密には等しくありませんが,Matcher<long> を int にマッチさせても問題になることはありません.しかし結局は,matcher に渡す前にまず,int 型の引数を long に変換することになります.

この要求をサポートするために,Google Mock には, SafeMatcherCast<T>(m) 関数が用意されています.これは,matcher m を Matcher<T> 型にキャストします. 安全性を保証するため,Google Mock は,次のことをチェックします( U は m のとれる型とします):

  1. 型 T は,明示的に 型 U にキャスト可能.
  2. T と U が共に組み込みの算術型(ブール,整数,浮動小数点数)の場合,T から U への変換損失はない(別の言い方をすれば,T で表現される任意の値は, Uでも表現可能).
  3. U が参照の場合,T も必ず参照(内部的に利用される matcher が,U の値のアドレスを必要とするかもしれないので).

これらの条件が満たされなければ,そのコードはコンパイルできません.

1つ例を示します:

using ::testing::SafeMatcherCast;

// 基底クラスと派生クラス.
class Base { ... };
class Derived : public Base { ... };

class MockFoo : public Foo {
 public:
  MOCK_METHOD1(DoThis, void(Derived* derived));
};
...

  MockFoo foo;
  // m は,どこかで作成済みの Matcher<Base*> .
  EXPECT_CALL(foo, DoThis(SafeMatcherCast<Derived*>(m)));

SafeMatcherCast<T>(m) の制限がきつすぎるならば,同様な関数 MatcherCast<T>(m) を使うこともできます.MatcherCast は,型 T から型 U への static_cast が可能な場合に動作する,という点が異なります.

MatcherCast は基本的に C++ の型システムへのバイパス(static_cast は 常に安全とは限りません.例えば,情報を捨てる可能性もあります)なので,間違って使ったり乱用したりしないように気を付けてください.

オーバーロードされた関数の選択

オーバーロードされた関数の呼び出しを期待する場合,オーバーロードされたどのバージョンなのかをコンパイラが決めるために,助けが必要になるかもしれません.

const な this オブジェクトで呼ばれるオーバーロードされた関数の曖昧さをなくすためには, Const() 引数ラッパーを利用します:

using ::testing::ReturnRef;

class MockFoo : public Foo {
  ...
  MOCK_METHOD0(GetBar, Bar&());
  MOCK_CONST_METHOD0(GetBar, const Bar&());
};
...

  MockFoo foo;
  Bar bar1, bar2;
  EXPECT_CALL(foo, GetBar())         // non-const GetBar()
      .WillOnce(ReturnRef(bar1));
  EXPECT_CALL(Const(foo), GetBar())  // const GetBar()
      .WillOnce(ReturnRef(bar2));

(Const() は,Google Mock で定義されており,その引数の const な参照を返します.)

引数の個数は同じで,引数の型が異なるようにオーバーロードされた関数の曖昧性をなくすには,matcher の正確な型を指定する必要があります.これには, Matcher<type>() で matcher をラップするか,型が固定された matcher (TypedEq<type>,An<type>(),など)を使うかします.

using ::testing::An;
using ::testing::Lt;
using ::testing::Matcher;
using ::testing::TypedEq;

class MockPrinter : public Printer {
 public:
  MOCK_METHOD1(Print, void(int n));
  MOCK_METHOD1(Print, void(char c));
};

TEST(PrinterTest, Print) {
  MockPrinter printer;

  EXPECT_CALL(printer, Print(An<int>()));            // void Print(int);
  EXPECT_CALL(printer, Print(Matcher<int>(Lt(5))));  // void Print(int);
  EXPECT_CALL(printer, Print(TypedEq<char>('a')));   // void Print(char);

  printer.Print(3);
  printer.Print(6);
  printer.Print('a');
}

引数に応じて異なる Action を実行する

モックメソッドが呼ばれると,最後にマッチした Expectation で,まだアクティブなものが選択されます(「新しいものが古いものに優先する」と考えてください).よって,引数の値に応じて動作が異なるメソッドを作ることができます.

using ::testing::_;
using ::testing::Lt;
using ::testing::Return;
...
  // デフォルトの場合.
  EXPECT_CALL(foo, DoThis(_))
      .WillRepeatedly(Return('b'));

  // より具体的な場合.
  EXPECT_CALL(foo, DoThis(Lt(5)))
      .WillRepeatedly(Return('a'));

こうすることで,5 よりも小さい値が与えられた場合は foo.DoThis() が呼ばれ,「a」が返されます.そうでない場合は,「b」が返されます.

複数の引数全体にマッチングする

個々の引数にマッチするだけでは不十分な場合があります.例えば,1番目の引数が2番目の引数よりも小さくなってほしい場合などです.With() 節を使うと,モック関数の全ての引数全体にマッチすることができます.以下に例を示します:

using ::testing::_;
using ::testing::Lt;
using ::testing::Ne;
...
  EXPECT_CALL(foo, InRange(Ne(0), _))
      .With(Lt());

この場合,InRange() の1番目の引数は 0 以外の値で,かつ2番目の引数よりも小さくなければいけません.

With() 内部の式は,型 Matcher<tr1::tuple<A1, ..., An> > の matcher となる必要があります.,ここで A1, ..., An は引数の型です.

.With() の内部で,m の代わりに AllArgs(m) を使うこともできます.この2つの形式は等価ですが,With(AllArgs(Lt())) のほうが With(Lt()) よりも読みやすいでしょう.

また,選択された n 個の引数(タプル)に対して Args<k1, ..., kn>(m) を使うことができます.例を示します:

using ::testing::_;
using ::testing::AllOf;
using ::testing::Args;
using ::testing::Lt;
...
  EXPECT_CALL(foo, Blah(_, _, _))
      .With(AllOf(Args<0, 1>(Lt()), Args<1, 2>(Lt())));

この場合, x < y < z である引数 x,y,z で Blah() が呼び出されます.

便利なように,かつ手本として,Google Mock では,上述の Lt() matcher を含む 2-タプルに対する matcher がいくつか用意されています.完全な一覧は チートシート を参照してください.

自分の述語関数に引数を渡したい場合(例えば, .With(Args<0, 1>(Truly(&MyPredicate))) ),その述語関数は必ず tr1::tuple を引数にとるようにしてください.gMock は n 個の選択された引数を 1つのタプルとして述語関数に渡します.

Matcher を述語関数として利用する

matcher は単に,自分自身の記述方法を知っている豪華な述語関数であることに気付きましたか?引数に述語関数をとるアルゴリズムがたくさん存在し(例えば,STL の <algorithm> ヘッダで定義されているものです),もし Google Mock の matcher がそこで使えなかったら,もったいないことです.

幸運なことに, matcher を Matches() 関数でラップすれば,1変数の述語ファンクタが期待されている場所で,それを利用することができます.次に例を示します:

#include <algorithm>
#include <vector>

std::vector<int> v;
...
// v の要素数は >= 10 ?
const int count = count_if(v.begin(), v.end(), Matches(Ge(10)));

Google Mock では,単純なものを組み合わせて複雑な matcher を簡単に構築することができるので,これを使って,複合的な述語関数を都合に合わせて構成することができます(STL の <functional> ヘッダを使って同様のことをやるのは面倒なだけです).例えば以下は,0以上,100以下,かつ50ではないの任意の数によって満足できる述語関数の例です:

Matches(AllOf(Ge(0), Le(100), Ne(50)))

Google Test アサーションで Matcher を利用する

matcher は基本的に,自分自身の記述方法を知っている述語関数なので, Google Test アサーションでこれをうまく利用する方法があります.これは ASSERT_THAT と EXPECT_THAT と呼ばれます:

ASSERT_THAT(value, matcher);  // value が matcher にマッチすることをアサートします.
EXPECT_THAT(value, matcher);  // こちらは,致命的ではないバージョン.

例えば,Google Test で次のようにテストを書くことができます:

#include "gmock/gmock.h"

using ::testing::AllOf;
using ::testing::Ge;
using ::testing::Le;
using ::testing::MatchesRegex;
using ::testing::StartsWith;
...

  EXPECT_THAT(Foo(), StartsWith("Hello"));
  EXPECT_THAT(Bar(), MatchesRegex("Line \\d+"));
  ASSERT_THAT(Baz(), AllOf(Ge(5), Le(10)));

これは,(おそらくあなたの想像通り)Foo(),Bar(),Baz() を実行して,以下のことを検証します:

  • Foo() が,”Hello” ではじまる文字列を返す.
  • Bar() が,正規表現 “Line \d+” にマッチする文字列を返す.
  • Baz() が,5以上10以下の値を返す.

英語のように読めるのが,これらのマクロの良いところです.これらは,役立つメッセージも生成します.例えば,上述の最初の EXPECT_THAT() が失敗すると,次のようなメッセージが出力されます.

Value of: Foo()
  Actual: "Hi, world!"
Expected: starts with "Hello"

クレジット: (ASSERT|EXPECT)_THAT のアイディアは,JUnit に assertThat() を追加する Hamcrest プロジェクトから拝借しました.

述語関数を Matcher として利用する

Google Mock では,組み込みの matcher が複数用意されています.それでも足りない場合は,任意の1変数述語関数,またはファンクタを matcher をとして利用することができます.ただし,その述語関数は,あなたの望む型を受け取るものである必要があります.これは,述語関数を Truely() 関数でラップすることで可能になるもので,次に例を示します:

using ::testing::Truly;

int IsEven(int n) { return (n % 2) == 0 ? 1 : 0; }
...

  // Bar() は,必ず偶数の引数で呼び出されます.
  EXPECT_CALL(foo, Bar(Truly(IsEven)));

この述語関数 / ファンクタは,bool を返す必要がないことに注意してください.戻り値が, if (条件) .... という文の中の条件として利用できるものであれば動作します.

コピーできない引数をマッチングする

EXPECT_CALL(mock_obj, Foo(bar)) とする場合, Google Mock は bar のコピーを保存しておきます.その後 Foo() が呼ばれ,Google Mock は,Foo() の引数と,保存された bar のコピーとを比較します.これにより,EXPECT_CALL() が実行された後の変更や破壊を心配する必要がなくなります.Eq(bar) や Le(bar) などの matcher を利用する場合も,この場合と同じです.

しかし,bar がコピーできない(つまり,コピーコンストラクタをもたない)場合はどうなるのでしょう?前のレシピで述べたように,独自の matcher 関数をユーザが定義して,Truly() でラップして使う方法もあります.しかし,bar がEXPECT_CALL() の実行後も変更されないことを保証できれば,このようなことをせずに済みます.つまり単に,bar のコピーではなく参照を保存するように,Google Mock に命じるだけです.次に,やり方を示します:

using ::testing::Eq;
using ::testing::ByRef;
using ::testing::Lt;
...
  // Foo() の引数 == bar であることを期待.
  EXPECT_CALL(mock_obj, Foo(Eq(ByRef(bar))));

  // Foo() の引数 < bar であることを期待.
  EXPECT_CALL(mock_obj, Foo(Lt(ByRef(bar))));

注意:これを使う場合,EXPECT_CALL() の後で bar を変更しないでください.もし変更した場合の結果は未定義です.

オブジェクトのメンバを検証する

モック関数がオブジェクトの参照を引数にとることがよくあります.この引数のマッチングを行う場合,固定されたオブジェクト全体を比較するのはやり過ぎなので,そうしたくない場合があるかもしれません.代わりに,ある特定のメンバ変数や,オブジェクトのゲッターメソッドの結果を検証する必要がありそうです.このためには, Field() および Property() を使います.より具体的には,次のようになります.

Field(&Foo::bar, m)

これは,そのメンバ bar が matcher m を満足するようなオブジェクト Foo にマッチする matcher です.

Property(&Foo::baz, m)

これは,そのメソッド baz() の戻り値が matcher m を満足するようなオブジェクト Foo にマッチする matcher です.

以下に例を示します:

Property(&Foo::baz, ...) の中のメソッド baz() は引数をとらず,const として宣言されていなければいけないことに注意してください.

ところで,Field() と Property() は,オブジェクトを指す通常のポインタにもマッチできます.例えば,次のようになります.

Field(&Foo::number, Ge(3))

これは,p->number >= 3 である通常のポインタ p にマッチします.p が NULL の場合,内部の matcher に関係なく,このマッチは常に失敗します.

同時に2つ以上のメンバを検証したい場合はどうするのでしょうか? AllOf() の存在を思い出してください.

ポインタ引数に指される値を検証します

C++ の関数は,よくポインタを引数にとります.そして,NULL,NotNull(),その他の比較 matcher といった,ポインタにマッチする matcher を利用できます.しかし,ポインタ自身ではなく,そのポインタに指されている値が特定のプロパティを持つことを確認したい場合はどうすればよいのでしょうか?そう, Pointee(m) matcher を利用できます.

m がポインタの指す値にマッチした場合にのみ,Pointee(m) がポインタにマッチします.次に例を示します:

using ::testing::Ge;
using ::testing::Pointee;
...
  EXPECT_CALL(foo, Bar(Pointee(Ge(3))));

foo.Bar() は,そのポインタの指す値が3以上であるようなポインタ,を引数として呼び出されることを期待されます.

Pointee() の良いところは,NULL ポインタをマッチ失敗として扱うので,

AllOf(NotNull(), Pointee(m))

の代わりに,Pointee(m) と書いても,NULL ポインタがテストをクラッシュさせる心配がないところです.

また,Pointee() は,通常のポインタとスマートポインタ(linked_ptr, shared_ptr, scoped_ptr など)のどちらに対しても動作します.

ポインタを指すポインタの場合はどうなるのでしょう?より深い場所にある値を探索するために,Pointee() をネストして利用できます.例えば,Pointee(Pointee(Lt(3))) は,そのポインタの指すポインタの指す値(言いにくい…)が3よりも小さい場合にマッチします.

オブジェクトの特定のプロパティをテストする

引数のオブジェクトが特定のプロパティを持つことを指定したい場合があります.しかし,そのようなことをする matcher は存在しません.分かりやすいエラーメッセージを望むならば,自分で matcher を定義するべきです.しかし,汚くても手早い方法でやりたいならば,通常の関数を書いて済ます方法もあります.

あるモック関数が,型 Foo のオブジェクトを引数にとり,それが int bar() メソッドと int baz() メソッドを持つ場合に,bar() と gaz() の値の和に制約を設けたいとします.次のように matcher を定義することでこれが可能になります:

using ::testing::MatcherInterface;
using ::testing::MatchResultListener;

class BarPlusBazEqMatcher : public MatcherInterface<const Foo&> {
 public:
  explicit BarPlusBazEqMatcher(int expected_sum)
      : expected_sum_(expected_sum) {}

  virtual bool MatchAndExplain(const Foo& foo,
                               MatchResultListener* listener) const {
    return (foo.bar() + foo.baz()) == expected_sum_;
  }

  virtual void DescribeTo(::std::ostream* os) const {
    *os << "bar() + baz() equals " << expected_sum_;
  }

  virtual void DescribeNegationTo(::std::ostream* os) const {
    *os << "bar() + baz() does not equal " << expected_sum_;
  }
 private:
  const int expected_sum_;
};

inline Matcher<const Foo&> BarPlusBazEq(int expected_sum) {
  return MakeMatcher(new BarPlusBazEqMatcher(expected_sum));
}

...

  EXPECT_CALL(..., DoThis(BarPlusBazEq(5)))...;

コンテナをマッチングする

モック関数に渡された STL コンテナ(例えば,list,vevtor,map,など)を検証したい場合があるかもしれません.大部分の STL コンテナは == 演算子をサポートしているので,Eq(expected_container) ,あるいは単に expected_container と書けば,コンテナとの厳密なマッチを行うことができます.

しかし,より柔軟な方法を必要とすることがあるかもしれません(例えば,最初の要素には厳密にマッチしたいが,2番目の要素は任意の正の数でかまわない,などといった場合です).また,テストでは少数要素のコンテナが使われる場合も多く,期待されるコンテナを余計に定義しなければならないのは少し面倒です.

このような場合,ElementsAre() matcher を利用することができます:

using ::testing::_;
using ::testing::ElementsAre;
using ::testing::Gt;
...

  MOCK_METHOD1(Foo, void(const vector<int>& numbers));
...

  EXPECT_CALL(mock, Foo(ElementsAre(1, Gt(0), _, 5)));

この matcher は,コンテナが 4 要素を持ち,それぞれ 1 ,0より大きい,任意の数,5 ,となることを述べています.

ElementsAre() は,0 個から 10 個までの引数を取るようにオーバーロードされています.もっと多くの引数が必要な場合は,引数をC形式の配列に置き換えて,代わりに ElementsAreArray() を利用してください.

using ::testing::ElementsAreArray;
...

  // ElementsAreArray は,要素値の配列を引数にとります.
  const int expected_vector1[] = { 1, 5, 2, 4, ... };
  EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector1)));

  // また,要素 matcher の配列も引数にとります.
  Matcher<int> expected_vector2 = { 1, Gt(2), _, 3, ... };
  EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector2)));

動的に作成する必要がある配列(したがって,コンパイラがその配列サイズを推定できない)の場合,配列サイズを指定するための追加引数を ElementsAreArray() に渡すことができます:

using ::testing::ElementsAreArray;
...
  int* const expected_vector3 = new int[count];
  // ... expected_vector3 に値を代入します ...
  EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector3, count)));

ヒント:

  • ElementAre*() は,たとえ STL で定義されているものではなくても,STL イテレータコンセプトが実装され(つまり,const_iterator 型を持ち, begin()/end() をサポートしている),size() をサポートする任意のコンテナに対して動作します.それどころか,前述のパターンに従う限り,まだ書かれていないコンテナ型に対しても動作します.
  • ネストした(多次元の)コンテナにマッチさせるために,ElementAre*() をネストさせて使うことができます.
  • コンテナを参照ではなくポインタで渡すには,単に Pointee(ElementsAre*(...)) と書くだけです.
  • ElementsAre*() にとって,要素の順番は重要な問題です.要素の順番が未定義なコンテナ(例えば,hash_map)に対しては,これを使用しないでください.

Matcher を共有する

内部的には,Google Mock の matcher オブジェクトは,実装オブジェクトを指す参照カウント方式のポインタで構成されています.matcher のコピーは単なるポインタのコピーなので,非常に効率的です.実装オブジェクトを参照する最後の matcher が死ぬタイミングで,その実装オブジェクトは削除されます.

したがって,ある複合 matcher を何度も繰り返し利用するつもりならば,それを毎回作成する必要はありません.matcher 変数に代入して,その変数を繰り返し使うだけで大丈夫です!以下に例を示します.

Matcher<int> in_range = AllOf(Gt(5), Le(10));
// ... 複数の EXPECT_CALL 内部で,in_range を matcher として利用します ...

Expectation を設定する

関心がない呼び出しを無視する

あるモックメソッドがどのように呼ばれるかに関心がなければ,まったく何もしないでください.この場合,そのメソッドが呼ばれると Google Mock は,テストプログラムを続行するためにデフォルト Action を実行します.Google Mock が実行するデフォルト Action では問題があるなら, DefaultValue<T>::Set() (これについては後述します),または ON_CALL() を利用してそれを上書きすることができます.

ある特定のモックメソッドについて(EXPECT_CALL() を使って)何らかの指定を行うと,そのすべての呼び出しが,必ず何かの Expectation にマッチしなければいけないことに注意してください.この関数が, EXPECT_CALL() 文のいずれにもマッチしない引数で呼び出されると,エラーになります.

不要な呼び出しを許可しない

モックメソッドが1度も呼び出されるべきものでないなら,次のように明示します:

using ::testing::_;
...
  EXPECT_CALL(foo, Bar(_))
      .Times(0);

このメソッドの呼び出しの内,いくつかだけを許可して,残りは許可しない場合,期待するすべての呼び出しを表記します:

using ::testing::AnyNumber;
using ::testing::Gt;
...
  EXPECT_CALL(foo, Bar(5));
  EXPECT_CALL(foo, Bar(Gt(10)))
      .Times(AnyNumber());

どの EXPECT_CALL() 文にもマッチしない foo.Bar() の呼び出しは,エラーになります.

順番通りの呼び出しを期待する

Google Mock が関数呼び出しを Expection にマッチさせようとする場合に,先に定義された EXPECT_CALL() 文が優先するとは言っても,デフォルトでは,EXPECT_CALL() 文が書かれた順番で関数呼び出しが起こる必要はありません.例えば引数が,1番目や2番目ではなく3番目の EXPECT_CALL() の matcher にマッチする場合,その3番目の Expectation が利用されます.

全ての呼び出しが Expectation の順番どおりに起こってほしいならば, InSequence 型の変数定義と同じブロック内に EXPECT_CALL() 文を置いてください.

using ::testing::_;
using ::testing::InSequence;

{
  InSequence s;

  EXPECT_CALL(foo, DoThis(5));
  EXPECT_CALL(bar, DoThat(_))
      .Times(2);
  EXPECT_CALL(foo, DoThis(6));
}

この例では,foo.DoThis(5) の次に,任意の引数をとる bar.DoThat() が2回呼び出され,そして foo.DoThis(6) が呼び出される,という順番を期待しています.この順序で呼び出しが行われなかった場合,Google Mock はエラーをレポートします.

部分的に順番通りの呼び出しを期待する

全てが事前に定義した順番どおりに起こる必要があるとしたら,それはときに脆いテストになります.例えば,A が B と C よりも前に起こるようにしたいが,B と C の相対的な順番には関心がない,という場合を考えます.この場合テストに必要なのは,過剰な制約ではなく,我々の本当の意図を反映することです.

Google Mock では,呼び出しに対して,任意の DAG(directed acyclic graph:有向非巡回グラフ)を当てはめることができます. DAG を表現する方法の1つは,EXPECT_CALL で After 節を利用することです.

また,もう1つの方法は,InSequence() 節(InSequence クラスとは異なります)を使うことで,これは jMock 2 から拝借しました.これは After() よりも柔軟性が低いですが,チェーン中の Expectations に応じた異なる名前を考えなくてもよいので,順序付いた長い呼び出しチェーンを書くときには便利な方法です.以下に例を示します:

EXPECT_CALL() 文をグラフのノードとみなし,A が B よりも前に起こらなければいけない場所すべてに,ノード A からノード B へのエッジを追加することで, DAG を記述できます.この DAG の有向パスの意味で,「シーケンス」という用語を使います.さて,DAG をシーケンスに分解した場合,元の DAG を再構成するためには,それぞれの EXPECT_CALL() がどのシーケンスに属するか,という情報だけが必要になります.

したがって,Expectation の部分的な順番を指定するには,次の2点が必要になります:まず,Sequence オブジェクトを定義すること.そして,それぞれの EXPECT_CALL() が,どの Sequence オブジェクトに属するかを記述すること,です.同じシーケンスに属する複数の Expectation は,それらが書かれた順番通りに起こらなければいけません.次に例を示します.

using ::testing::Sequence;

Sequence s1, s2;

EXPECT_CALL(foo, A())
    .InSequence(s1, s2);
EXPECT_CALL(bar, B())
    .InSequence(s1);
EXPECT_CALL(bar, C())
    .InSequence(s2);
EXPECT_CALL(foo, D())
    .InSequence(s2);

これは,次のような DAG(ここで s1 は A -> B,s2 は A -> C -> D を意味します)を表しています:

     +---> B
     |
A ---|
     |
     +---> C ---> D

これは,A は B と C よりも前に,C は D よりも前に起きなければいけないことを意味しています.順番に関するそれ以外の制約はありません.

Expectation の非アクティブ化を制御する

モックメソッドが呼び出された際,Google Mock は,アクティブな Expectation のみを考慮します.Expectation は,作成された時点ではアクティブであり,自分より後に呼ばれるべきものが呼ばれた時点で非アクティブ(リタイアとも言います)になります.以下に例を示します.

using ::testing::_;
using ::testing::Sequence;

Sequence s1, s2;

EXPECT_CALL(log, Log(WARNING, _, "File too large."))     // #1
    .Times(AnyNumber())
    .InSequence(s1, s2);
EXPECT_CALL(log, Log(WARNING, _, "Data set is empty."))  // #2
    .InSequence(s1);
EXPECT_CALL(log, Log(WARNING, _, "User not found."))     // #3
    .InSequence(s2);

#2 または #3 にマッチしたらすぐに,#1 が非アクティブになります.その後に,”File too large.” という警告が記録されると,エラーが発生します.

Expectation が飽和しても,そこで自動的に非アクティブになるわけではないことに注意してください.次に例を示します.

using ::testing::_;
...
  EXPECT_CALL(log, Log(WARNING, _, _));                  // #1
  EXPECT_CALL(log, Log(WARNING, _, "File too large."));  // #2

これは,”File too large.” というメッセージの警告が1度だけ起こることを想定しています.このメッセージの警告が2度起こると,2度目は #2 にマッチして,上限違反エラーが発生します.

これが望む動作ではない場合,Expectation が飽和した時点ですぐに非アクティブになるようにすることができます:

using ::testing::_;
...
  EXPECT_CALL(log, Log(WARNING, _, _));                 // #1
  EXPECT_CALL(log, Log(WARNING, _, "File too large."))  // #2
      .RetiresOnSaturation();

この場合,#2 は1度だけ利用されますので,”File too large.” というメッセージの警告が2度起こると,最初の警告は #2 にマッチし,2度目の警告は #1 にマッチして,エラーは起こりません.

Action を利用する

モックメソッドから参照を返す

モック関数の戻り値の型が参照の場合,結果を返すために,Retern() の代わりに ReturnRef() を使う必要があります:

using ::testing::ReturnRef;

class MockFoo : public Foo {
 public:
  MOCK_METHOD0(GetBar, Bar&());
};
...

  MockFoo foo;
  Bar bar;
  EXPECT_CALL(foo, GetBar())
      .WillOnce(ReturnRef(bar));

モックメソッドで,現在の値を返す

Return(x) という Action は,Action が作成されたときに x のコピーを保存します.そして,これが実行されたときは常に同じ値を返します.しかし,x の現在の値(つまり,Action が実行された時点での値)を返してほしい場合があるかもしれません.

前のレシピ( モックメソッドから参照を返す )で述べたように,このモック関数の戻り値の型が参照の場合,ReternRef(x) とすれば可能です. しかし,Google Mockでは,戻り値の型が参照ではないモック関数の中で ReturnRef() を使うことはできないので,これはユーザエラーになります.では,どうすれば良いのでしょうか?

ByRef() を試してみようと考えるかもしれません:

using testing::ByRef;
using testing::Return;

class MockFoo : public Foo {
 public:
  MOCK_METHOD0(GetValue, int());
};
...
  int x = 0;
  MockFoo foo;
  EXPECT_CALL(foo, GetValue())
      .WillRepeatedly(Return(ByRef(x)));
  x = 42;
  EXPECT_EQ(42, foo.GetValue());

残念ながら,これではうまく動きません.このコードは,エラーで失敗します:

Value of: foo.GetValue()
  Actual: 0
Expected: 42

これは,Action が実行され時点ではなく,作成された時点で,Return(value) が,値をモック関数の実際の戻り値型に変換するからです(値が一時オブジェクトを参照するプロキシオブジェクトであっても,安全に Action を実行できるように,このような挙動になっています). 結果として,Expectation が設定された時点で,ByRef(x) は(const int& ではなく)int 値に変換されます.そして,Return(ByRef(x)) は常に0を返します.

この問題に対処するために ReturnPointee(pointer) が用意されています.これは,Action が 実行された 時点で,pointer に指されている値を返します:

using testing::ReturnPointee;
...
  int x = 0;
  MockFoo foo;
  EXPECT_CALL(foo, GetValue())
      .WillRepeatedly(ReturnPointee(&x));  // ここで & に注意してください.
  x = 42;
  EXPECT_EQ(42, foo.GetValue());  // これは,成功します.

Action を組み合わせる

ある関数が呼ばれたときに,2つ以上のことをしたいですか?いいでしょう.DoAll() を使えば,連続した Action を毎回実行できます.この場合,最後の Action の戻り値のみが利用されます.

using ::testing::DoAll;

class MockFoo : public Foo {
 public:
  MOCK_METHOD1(Bar, bool(int n));
};
...

  EXPECT_CALL(foo, Bar(_))
      .WillOnce(DoAll(action_1,
                      action_2,
                      ...
                      action_n));

副作用をモック化する

メソッドによっては,戻り値ではなく副作用を介して,自分の効果を発揮するものがあります.例えば,グローバル状態を変えたり,出力引数を変更したりするようなものです.副作用をモック化するには,通常は,::testing::ActionInterface を実装して独自の Action を定義します.

出力変数を変更するだけで十分な場合,組み込みの SetArgPointee() Action を使うのが便利です:

using ::testing::SetArgPointee;

class MockMutator : public Mutator {
 public:
  MOCK_METHOD2(Mutate, void(bool mutate, int* value));
  ...
};
...

  MockMutator mutator;
  EXPECT_CALL(mutator, Mutate(true, _))
      .WillOnce(SetArgPointee<1>(5));

この例では,mutator.Mutate() が呼ばれると,#1 (0基準)の引数 で指された int 変数に 5 を代入します.

SetArgPointee() は,渡された値の内部的なコピーを作成しますので,スコープ内で値を有効な状態に保っておく必要がなくなります.しかし,この実装では,値がコピーコンストラクタおよび代入演算子をサポートしている必要があります.

モックメソッドが戻り値も必要とする場合,SetArgPointee() と Return() を DoAll() でつなげることができます:

using ::testing::_;
using ::testing::Return;
using ::testing::SetArgPointee;

class MockMutator : public Mutator {
 public:
  ...
  MOCK_METHOD1(MutateInt, bool(int* value));
};
...

  MockMutator mutator;
  EXPECT_CALL(mutator, MutateInt(_))
      .WillOnce(DoAll(SetArgPointee<0>(5),
                      Return(true)));

出力引数が配列の場合,代わりに SetArrayArgument<N>(first, last) Action を利用してください.これは,入力範囲 [first, last) の要素を,N-番目(0基準)の引数が指す配列にコピーします:

using ::testing::NotNull;
using ::testing::SetArrayArgument;

class MockArrayMutator : public ArrayMutator {
 public:
  MOCK_METHOD2(Mutate, void(int* values, int num_values));
  ...
};
...

  MockArrayMutator mutator;
  int values[5] = { 1, 2, 3, 4, 5 };
  EXPECT_CALL(mutator, Mutate(NotNull(), 5))
      .WillOnce(SetArrayArgument<0>(values, values + 5));

これは,引数が出力イテレータの場合でも動作します:

using ::testing::_;
using ::testing::SeArrayArgument;

class MockRolodex : public Rolodex {
 public:
  MOCK_METHOD1(GetNames, void(std::back_insert_iterator<vector<string> >));
  ...
};
...

  MockRolodex rolodex;
  vector<string> names;
  names.push_back("George");
  names.push_back("John");
  names.push_back("Thomas");
  EXPECT_CALL(rolodex, GetNames(_))
      .WillOnce(SetArrayArgument<0>(names.begin(), names.end()));

モックオブジェクトの状態に応じて挙動を変える

モックオブジェクトの挙動を変更する関数呼び出しをテストしたい場合,その呼び出しの前後で別の挙動を指定するには, ::testing::InSequence を利用します.

using ::testing::InSequence;
using ::testing::Return;

...
  {
    InSequence seq;
    EXPECT_CALL(my_mock, IsDirty())
        .WillRepeatedly(Return(true));
    EXPECT_CALL(my_mock, Flush());
    EXPECT_CALL(my_mock, IsDirty())
        .WillRepeatedly(Return(false));
  }
  my_mock.FlushIfDirty();

この場合,my_mock.IsDirty() は,my_mock.Flush() が呼ばれる前は true を返し,呼ばれた後は false を返します.

挙動の変化がより複雑な場合は,効果を変数に保存しておき,モックメソッドの戻り値が,その変数の値になるようにします:

using ::testing::_;
using ::testing::SaveArg;
using ::testing::Return;

ACTION_P(ReturnPointee, p) { return *p; }
...
  int previous_value = 0;
  EXPECT_CALL(my_mock, GetPrevValue())
      .WillRepeatedly(ReturnPointee(&previous_value));
  EXPECT_CALL(my_mock, UpdateValue(_))
      .WillRepeatedly(SaveArg<0>(&previous_value));
  my_mock.DoSomethingToUpdateValue();

この場合,my_mock.GetPrevValue() は,直前の UpdateValue() の引数の値を常に返します.

ある戻り値型に対するデフォルト値を設定する

モックメソッドの戻り値の型が組み込みの C++ 型やポインタならば,実行時にはデフォルトで 0 を返します.このデフォルト値では不十分な場合のみ,Action を指定する必要があります.

このデフォルト値を変更したり,Google Mock が知らない型のデフォルト値を指定したりすることが必要な場合も考えられます. ::testing::DefaultValue クラステンプレートを利用すれば,これが可能です.

class MockFoo : public Foo {
 public:
  MOCK_METHOD0(CalculateBar, Bar());
};
...

  Bar default_bar;
  // デフォルトの Bar 型リターン値 をセットします.
  DefaultValue<Bar>::Set(default_bar);

  MockFoo foo;

  // デフォルトのリターン値があるので,
  // ここで Action を指定する必要はありません.
  EXPECT_CALL(foo, CalculateBar());

  foo.CalculateBar();  // これは default_bar を返すはず.

  // デフォルトのリターン値を外します.
  DefaultValue<Bar>::Clear();

ある型のデフォルト値を変更すると,テストの可読性が下がることには注意してください.これは,注意して使う機能であることを忘れないでください.例えば,モックを利用するコードのすぐ隣で Set() と Clear() を呼び出すようにしてください.

モックメソッドのデフォルト Action を設定する

ある型のデフォルト値を変更する方法は既に学びました.しかし,やりたい事を実現するには,これだけでは不足かもしれません:同じ戻り値型を持つ2つのモックメソッドがあり,それぞれに異なった動作をさせたい場合などです. ON_CALL() マクロを使えば,メソッドレベルでモックの動作をカスタマイズすることができます.

using ::testing::_;
using ::testing::AnyNumber;
using ::testing::Gt;
using ::testing::Return;
...
  ON_CALL(foo, Sign(_))
      .WillByDefault(Return(-1));
  ON_CALL(foo, Sign(0))
      .WillByDefault(Return(0));
  ON_CALL(foo, Sign(Gt(0)))
      .WillByDefault(Return(1));

  EXPECT_CALL(foo, Sign(_))
      .Times(AnyNumber());

  foo.Sign(5);   // これは, 1 を返します.
  foo.Sign(-9);  // これは, -1 を返します.
  foo.Sign(0);   // これは, 0 を返します.

あなたの推測どおり,1つ以上の ON_CALL() 文がある箇所では,新しいものが古いものを上書きします.別の言い方をすれば,関数の引数に最後にマッチしたものが利用されます.このようなマッチング順序があるおかげで,モックオブジェクトのコンストラクタやテストフィクスチャの set-up 内で共通の動作をセットし,後からモックの動作を個別に指定することができます.

関数/メソッド/ファンクタを Action として利用する

組み込みの Action では不足な場合,既存の関数,メソッド,ファンクタを Action として簡単に利用することができます:

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

class MockFoo : public Foo {
 public:
  MOCK_METHOD2(Sum, int(int x, int y));
  MOCK_METHOD1(ComplexJob, bool(int x));
};

int CalculateSum(int x, int y) { return x + y; }

class Helper {
 public:
  bool ComplexJob(int x);
};
...

  MockFoo foo;
  Helper helper;
  EXPECT_CALL(foo, Sum(_, _))
      .WillOnce(Invoke(CalculateSum));
  EXPECT_CALL(foo, ComplexJob(_))
      .WillOnce(Invoke(&helper, &Helper::ComplexJob));

  foo.Sum(5, 6);       // CalculateSum(5, 6) を呼び出します.
  foo.ComplexJob(10);  // helper.ComplexJob(10) を呼び出します.

ここで必要なのは,呼び出す関数の型などが,モック関数のシグネチャと互換性があることです.つまり,後者の引数が対応する前者の引数に暗黙に型変換可能で,前者の戻り値型が後者のそれに暗黙に型変換可能である,という意味です.これが安全に行える限り,モック関数と型が異なるものでも呼び出すことができます.どう?いいでしょ?

関数/メソッド/ファンクタを引数なしで呼び出す

Invoke() は,より複雑な Action を実行するのにはとても便利です.この場合,モック関数の引数が呼び出し対象の関数やファンクタに渡されるので,呼び出しの完全なコンテキストを把握した上で動作します.もし呼び出される関数にとって,一部または全部の引数が不要な場合,それらを簡単に無視することができます.

しかし,テストを書く側は皆,モック関数の引数を使わずに関数を呼び出したい,と考えます.内部の引数なし関数を呼び出す前に,引数を捨ててしまうようなラッパ関数を使えば,Invoke() でそれを実現することができます.言うまでもないことですが,この方法はつまらないですし,テストの意図を不明瞭にしてしまう可能性があります.

InvokeWithoutArgs() は,この問題を解決します.これは,モック関数の引数を,呼び出される関数に渡さないことを除いて,Invoke() と同じです.次に例を示します:

using ::testing::_;
using ::testing::InvokeWithoutArgs;

class MockFoo : public Foo {
 public:
  MOCK_METHOD1(ComplexJob, bool(int n));
};

bool Job1() { ... }
...

  MockFoo foo;
  EXPECT_CALL(foo, ComplexJob(_))
      .WillOnce(InvokeWithoutArgs(Job1));

  foo.ComplexJob(10);  // Job1() を呼び出します.

モック関数の引数を呼び出す

モック関数の引数として,関数ポインタやファンクタ(別の言い方をすれば,”callable”)を受け取る場合があります.例えば,次のような例です.

class MockFoo : public Foo {
 public:
  MOCK_METHOD2(DoThis, bool(int n, bool (*fp)(int)));
};

この呼び出し可能な引数を,次のように呼び出したいと考えるでしょう:

using ::testing::_;
...
  MockFoo foo;
  EXPECT_CALL(foo, DoThis(_, _))
      .WillOnce(...);
  //  (*fp)(5) を実行します.ここで,fp は
  // DoThis() の2番目の引数です.

ここで,モック関数の引数を参照する必要がありますが,C++ には(まだ)ラムダ式がないので,自分で Action を定義する必要があります.:-( えっ,本当に?

Google Mock には,まさにこの問題を解決するための Action が用意されています.

InvokeArgument<N>(arg_1, arg_2, ..., arg_m)

これは,モック関数が受け取る N-番目(0基準)の実行可能な引数に,arg_1,arg_2,...,arg_m を渡して呼び出します.引数が関数ポインタやファンクタのどちらでも,Google Mock は扱うことができます.

これを使うと,次のように書くことができます:

using ::testing::_;
using ::testing::InvokeArgument;
...
  EXPECT_CALL(foo, DoThis(_, _))
      .WillOnce(InvokeArgument<1>(5));
  //  (*fp)(5) を実行します.ここで,fp は
  // DoThis() の2番目の引数です.

callable の引数が参照型の場合はどうでしょう?問題ありません - ByRef() でラップするだけです:

...
  MOCK_METHOD1(Bar, bool(bool (*fp)(int, const Helper&)));
...
using ::testing::_;
using ::testing::ByRef;
using ::testing::InvokeArgument;
...

  MockFoo foo;
  Helper helper;
  ...
  EXPECT_CALL(foo, Bar(_))
      .WillOnce(InvokeArgument<0>(5, ByRef(helper)));
  // ByRef(helper) は,helper のコピーではなく,参照が
  // callable に渡されることを保証します.

では,callable の引数が参照の場合に,その引数を ByRef() でラップ しなかった らどうなるでしょうか?InvokeArgument() は,引数の コピーを作成し ,元の値への参照ではなく コピーへの参照 を callable へ渡します.これは特に,引数が一時的な値である場合に便利です.

...
  MOCK_METHOD1(DoThat, bool(bool (*f)(const double& x, const string& s)));
...
using ::testing::_;
using ::testing::InvokeArgument;
...

  MockFoo foo;
  ...
  EXPECT_CALL(foo, DoThat(_))
      .WillOnce(InvokeArgument<0>(5.0, string("Hi")));
  // (*f)(5.0, string("Hi")) を実行します.ここで,f は DoThat が受け取った
  // 関数ポインタです.値 5.0 と string("Hi") は,一時的なもので,
  // EXPECT_CALL() 文が終了した際に同時に無効になることに注意してください.
  // しかし,これらの値のコピーが InvokeArgument Action 内部に保存されているので,
  // 後からこの Action を実行しても大丈夫です.

Action の結果を無視する

何か を返す Action があるけれど,実は void を返す Action が必要という場合があります(void を返すモック関数の内で使いたいのかもしれませんし,DoAll() の中の最後以外の場所で利用されるのかもしれません).IgnoreResult() を使えば,それが可能になります.以下に例を示します:

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

int Process(const MyData& data);
string DoSomething();

class MockFoo : public Foo {
 public:
  MOCK_METHOD1(Abc, void(const MyData& data));
  MOCK_METHOD0(Xyz, bool());
};
...

  MockFoo foo;
  EXPECT_CALL(foo, Abc(_))
  // .WillOnce(Invoke(Process));
  // Abc() は void の戻り値が必要なのに,Process() が int を返すので,
  // 上の行はコンパイルできません.
      .WillOnce(IgnoreResult(Invoke(Process)));

  EXPECT_CALL(foo, Xyz())
      .WillOnce(DoAll(IgnoreResult(Invoke(DoSomething)),
      // DoSomething() が返す文字列を無視します.
                      Return(true)));

元から void を返す Action の中では IgnoreResult() を利用できないことに注意してください.もし,これをすると,ひどいコンパイルエラーが起こります.

Action の引数を選択する

7つの引数をとるモック関数 Foo() と,その Foo() が呼ばれたときに呼び出したいカスタム Action があるとしましょう.ここで問題なのは,そのカスタム Action が 3つの引数しか必要としないことです:

using ::testing::_;
using ::testing::Invoke;
...
  MOCK_METHOD7(Foo, bool(bool visible, const string& name, int x, int y,
                         const map<pair<int, int>, double>& weight,
                         double min_weight, double max_wight));
...

bool IsVisibleInQuadrant1(bool visible, int x, int y) {
  return visible && x >= 0 && y >= 0;
}
...

  EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _))
      .WillOnce(Invoke(IsVisibleInQuadrant1));  // うーん,コンパイルできない.:-(

コンパイラ様を満足させるには,Foo() と同じシグネチャを持ち,内部でカスタム Action を呼び出すような「アダプタ」を定義します:

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

bool MyIsVisibleInQuadrant1(bool visible, const string& name, int x, int y,
                            const map<pair<int, int>, double>& weight,
                            double min_weight, double max_wight) {
  return IsVisibleInQuadrant1(visible, x, y);
}
...

  EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _))
      .WillOnce(Invoke(MyIsVisibleInQuadrant1));  // 今度は動作します.

でも,これってカッコ悪いですよね?

Google Mock には,一般的な Action アダプタ が用意されていますので,独自のアダプタを書く事よりも重要な仕事に注力できます.以下が,その構文です:

WithArgs<N1, N2, ..., Nk>(action)

これは,指定されたインデックス(0基準)で表現されるモック関数の引数を,内部の Action に渡して実行するような Action を作成します.WithArgs を使うと,元々の例は次のように書くことができます:

using ::testing::_;
using ::testing::Invoke;
using ::testing::WithArgs;
...
  EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _))
      .WillOnce(WithArgs<0, 2, 3>(Invoke(IsVisibleInQuadrant1)));
      // 独自のアダプタを定義する必要はありません.

さらに読みやすくするために,Google Mock には次のようなものが用意されています:

  • 内部の Action が引数を取らない場合に利用できる,WithoutArgs(action) .
  • 内部の Action が引数を1つ取る場合に利用できる,WithArg<N>(action) (Arg の後の s はナシ ).

気づいたかもしれませんが,InvokeWithoutArgs(...) は,単に WithoutArgs(Inovke(...)) のシンタックスシュガーです.

ヒントをいくつか書いておきましょう:

  • WithArgs とその仲間で利用される内部 Action は,必ずしも Invoke() される必要はありません.– これは,何であっても問題ありません.
  • 必要ならば,例えば, WithArgs<2, 3, 3, 5>(...) というように,引数リストの引数を繰り返し使うことができます.
  • 例えば,WithArgs<3, 2, 1>(...) というように,引数の順番を変更することができます.
  • 選択された引数の型が,内部 Action のシグネチャに厳密に一致する必要はありません.内部 Action の対応する引数に,暗黙に型変換できれば動作します.例えば,モック関数の4番目の引数が int で,my_action が double を取る場合でも,WithArg<4>(my_action) は動作します.

Action 関数の引数を無視する

Action の引数の選択に関するレシピでは,モック関数と Action で,互換性のない引数リストを互いに適合させる方法を学びました.これの欠点は,Action を WtihArgs<...>() でラップするのが,テストを書く人にとって面倒かもしれないことです.

Invoke*() で利用される関数,メソッド,ファンクタを定義する際,いくつかの引数が不要な場合,WithArgs に代わる方法は,不要な引数を利用しないものとして宣言することです.これにより,定義が簡潔になり,そして不要な引数の型が変更された場合も影響を受けずに済みます.また,Action 関数を再利用する機会が増加する可能性もあります.では,次に例を示します.

MOCK_METHOD3(Foo, double(const string& label, double x, double y));
MOCK_METHOD3(Bar, double(int index, double x, double y));

これが,与えられている場合,

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

double DistanceToOriginWithLabel(const string& label, double x, double y) {
  return sqrt(x*x + y*y);
}

double DistanceToOriginWithIndex(int index, double x, double y) {
  return sqrt(x*x + y*y);
}
...

  EXEPCT_CALL(mock, Foo("abc", _, _))
      .WillOnce(Invoke(DistanceToOriginWithLabel));
  EXEPCT_CALL(mock, Bar(5, _, _))
      .WillOnce(Invoke(DistanceToOriginWithIndex));

上記のような書き方の代わりに,次のように書くことができます.

using ::testing::_;
using ::testing::Invoke;
using ::testing::Unused;

double DistanceToOrigin(Unused, double x, double y) {
  return sqrt(x*x + y*y);
}
...

  EXEPCT_CALL(mock, Foo("abc", _, _))
      .WillOnce(Invoke(DistanceToOrigin));
  EXEPCT_CALL(mock, Bar(5, _, _))
      .WillOnce(Invoke(DistanceToOrigin));

Action を共有する

Google Mock の Action オブジェクトは,丁度 matcher と同様に,参照カウント方式の実装オブジェクトへのポインタで構成されています.したがって,Action は効率的にコピーすることが可能です.実装オブジェクトを参照する最後の Action が死ぬと,その実装オブジェクトは削除されます.

複雑な Action を何度も再利用したい場合,毎回それを最初から作成する必要はないかもしれません.その Action が内部状態を持たない場合(つまり,呼び出された回数にかかわらず常に同じ動作をする場合),それを Action 変数に代入し,その変数を繰り返し使います.次に例を示します:

Action<bool(int*)> set_flag = DoAll(SetArgPointee<0>(5),
                                    Return(true));
// ... .WillOnce() と .WillRepeatedly() の内部で set_flag を利用します ...

しかし,Action が自身の状態を持っている場合,その Action を共有すると予期しない事が起こる可能性があります.Action ファクトリ IncrementCounter(init) があり,これは,初期値が init であるカウンタ値を増加させて,それを返す Action を生成するとします.同じ式から作られた2つの Action を利用する場合と,共有 Action を利用する場合では,違う挙動を示します.例を示しましょう:

EXPECT_CALL(foo, DoThis())
    .WillRepeatedly(IncrementCounter(0));
EXPECT_CALL(foo, DoThat())
    .WillRepeatedly(IncrementCounter(0));
foo.DoThis();  // 1 を返す.
foo.DoThis();  // 2 を返す.
foo.DoThat();  // 1 を返す. Blah() と Bar() は,
               // 違うカウンタを利用します.

これに対して,次のようになります.

Action<int()> increment = IncrementCounter(0);

EXPECT_CALL(foo, DoThis())
    .WillRepeatedly(increment);
EXPECT_CALL(foo, DoThat())
    .WillRepeatedly(increment);
foo.DoThis();  // 1 を返す.
foo.DoThis();  // 2 を返す.
foo.DoThat();  // 3 を返す.カウンタは共有されます.

Google Mock を利用したその他のレシピ

強制的に検証を行う

モックオブジェクトが破壊されると,あなたのモックオブジェクトは,すべての Expectation が満足されていたかどうか検証し,そうでなければ Google Test の失敗を生成します.これは,あなたの心配事をとりあえず1つ減らしてくれる便利な機能です.つまり,モックオブジェクトが破壊されるかどうかが分からない場合は,やっぱり心配だということですが.

モックオブジェクトが破壊されなかった場合はどうなるのでしょうか?例えば,あなたがテストしているコードがモックオブジェクトをヒープ上に作って持っているかもしれません.そのコードにバグがあり,モックオブジェクトを適切に削除しないとすると,実際にはバグがある箇所のテストをパスしてしまうことになります.

ヒープチェッカーを使うのは良い考えですし,多少なりとも心配が減りますが,その実装が100%信用できるものとは限りません.そういうわけで,Google Mock が モックオブジェクトを,(できれば)それが破壊される前に強制的に検証して欲しい場合があります. Mock::VerifyAndClearExpectations(&mock_object) を使えば,それが可能になります.

TEST(MyServerTest, ProcessesRequest) {
  using ::testing::Mock;

  MockFoo* const foo = new MockFoo;
  EXPECT_CALL(*foo, ...)...;
  // ... その他の Expectation ...

  // server が foo を所有しています.
  MyServer server(foo);
  server.ProcessRequest(...);

  // server のデストラクタが foo を削除し忘れた場合に備えて,
  // これは,とにかく Expectation を検証します.
  Mock::VerifyAndClearExpectations(foo);
}  // このスコープから外れると server が破壊されます.

ヒント: Mock::VerifyAndClearExpectations() 関数は,検証が成功した(その場合は,true )かどうかを示す bool 値を返します.よって,検証が失敗した場合にそれ以上処理を続けない場合は,その関数呼び出しを ASSERT_TRUE() でラップします.

チェクポイントを利用する

テストにおける様々なチェックポイントで,モックオブジェクトを「リセット」したい場合があります:各チェックポイントでは,モックオブジェクトに存在するすべての Expectation が満足されていることを検証し,もし新しく作られた Expectation があれば,それをセットします.これによって,モックオブジェクトを「段階的」に動作させ,それぞれのサイズを個々に管理することができます.

このような状況は,テストの SetUp() 関数の中で起こり得ます.例えば,現在テストしているオブジェクトを,ある状態にして,その状態になった後は,TEST_F の中に新しい Expectatioin をセットできるように,モックのすべての Expectation をクリアしたい,といった状況が考えられます.

お気づきかもしれませんが,前のレシピで見た Mock::VerifyAndClearExpectations() 関数が,ここでも役に立ちます.もし,ON_CALL() を利用してモックオブジェクトのデフォルトの Action をセットしており,それをクリアするために同様に ON_CALL() を利用しようとしているならば,代わりに Mock::VerifyAndClear(&mock_object) を使ってください.この関数は, Mock::VerifyAndClearExpectations(&mock_object) と同じ事を行い,同じ bool 値を返します. さらに ,モックオブジェクトの ON_CALL() 文のクリアも行います.

同じ効果を得るためのもう1つの方法は,シーケンス内に Expectation を配置し,ダミーの「チェックポイント」関数呼び出しを特定の場所に挿入することです.そうすると,モック関数が適切な時点で呼び出されていることを検証できます.例えば,次のようなコードを実行するとしましょう:

Foo(1);
Foo(2);
Foo(3);

そして, Foo(1) と Foo(3) は共に mock.Bar(“a”) を呼び出すが Foo(2) は何も呼び出さない,ということを検証したいとします.これは,次のように書けます:

using ::testing::MockFunction;

TEST(FooTest, InvokesBarCorrectly) {
  MyMock mock;
  // MockFunction<F> クラスは,1つのメソッドだけを持ちます.
  // それは Call() という名前で,戻り値型は F です.
  MockFunction<void(string check_point_name)> check;
  {
    InSequence s;

    EXPECT_CALL(mock, Bar("a"));
    EXPECT_CALL(check, Call("1"));
    EXPECT_CALL(check, Call("2"));
    EXPECT_CALL(mock, Bar("a"));
  }
  Foo(1);
  check.Call("1");
  Foo(2);
  check.Call("2");
  Foo(3);
}

この Expectation は,最初の Bar(“a”) は必ずチェックポイント “1” よりも前に起こる,2番目の Bar(“a”) は必ずチェックポイント “2” よりも後に起こる,そして2つのチェックポイントの間では何も起こらない,ということを規定しています.チェックポイントを明示することで,どの Foo() 呼び出しによって,どの Bar(“a”) が呼び出されるのかが分かりやすくなります.

デストラクタをモック化する

モックオブジェクトが適切な時期,例えば bar->A() が呼ばれた後で bar->B() が呼ばれる前,に確実にデストラクトされるようにしたい場合があります.モック関数の呼び出し順序を指定する方法を既に知っていますので,必要なのは,モック関数のデストラクタをモック化する事だけです.

これは簡単に思えますが,1つ問題があります:デストラクタは,特別な構文を持ち特別な動作を行う特殊な関数で,MOCK_METHOD0 マクロではうまくいかないという点です:

MOCK_METHOD0(~MockFoo, void());  // コンパイルできない!

幸いなことに,簡単なパターンを使って同じことができます.以下のように,まずモッククラスにモック関数 Die() を追加し,デストラクタでそれを呼び出します:

class MockFoo : public Foo {
  ...
  // モッククラスに次の2行を追加します.
  MOCK_METHOD0(Die, void());
  virtual ~MockFoo() { Die(); }
};

(もし,Die() という名前が既にあるシンボルと衝突する場合は,別の名前にしてください.)そして,MockFoo オブジェクトが死んだ場合のテスト,という問題を,Die() メソッドが呼び出された場合のテスト,に置き換えます.

MockFoo* foo = new MockFoo;
MockBar* bar = new MockBar;
...
{
  InSequence s;

  // bar->A() の後,bar->B() の前で *foo が死ぬことを期待.
  EXPECT_CALL(*bar, A());
  EXPECT_CALL(*foo, Die());
  EXPECT_CALL(*bar, B());
}

これだけです.

Google Mock とスレッドを使う

重要な注意: このレシピで述べることは,Google Mock がスレッドセーフであるプラットフォーム のみ において正しいものです.これは現在のところ,pthreads ライブラリをサポートするプラットフォーム(Linux や Mac)に限られます.その他のプラットフォームにおいてスレッドセーフを実現するには, “gtest/internal/gtest-port.h” に同期操作を実装する必要があります.

単体テストにおいて,コードを部分的に分離し,シングルスレッドなコンテキストでテストできるならば,それがベストです.そうすることで,競合状態やデッドロックを避け,テストのデバッグが非常に簡単になります.

しかし,多くのプログラムはマルチスレッド化されており,場合によっては,何らかのテストを行うために1つ以上のスレッドからそれをたたく必要があります.Google Mock は,この目的でも利用されます.

モックを利用するステップを思い出してください:

  1. モックオブジェクトを作成します.
  2. ON_CALL() および EXPECT_CALL() を用いて,デフォルト Action と Expectation をセットします.
  3. テストコードから foo の メソッドを呼び出します.
  4. オプションとして,モックの検証とリセットを行います.
  5. 自分でモックを破棄するか,テストコードに破棄させるか,します.デストラクタは,自動的にそれを検証します.

次の簡単なルールを守れば,モックとスレッドの利用は楽しく共存できます:

  • テストコードは(テストされているコードとは逆に),1つのスレッドで実行してください.これで,テストを追いかけやすくなります.
  • ステップ #1 をロックせずに行えるのは,明らかです.
  • ステップ #2 と #5 実行時に,他のスレッドが foo にアクセスしないようにします.これも明らか,ですよね?
  • #3 と #4 は,1つのスレッドでも複数のスレッドでも,望む方で動作可能です.ロック は Google Mock が対処するので,あなたのテストロジックが必要としない限り,何する必要がありません.

このルールを破った場合(例えば,他のスレッドが,モックメソッドを呼んでいる最中に,そのモックに Expectation をセットする)の動作は未定義です.まぁ,楽しいものではないので,破らないようにしてください.

Google Mock は,モック関数の Action が,そのモック関数を呼び出したのと同一のスレッドで実行されることを保証します.次に例を示します.

EXPECT_CALL(mock, Foo(1))
    .WillOnce(action1);
EXPECT_CALL(mock, Foo(2))
    .WillOnce(action2);

スレッド 1 で Foo(1) が呼ばれ,スレッド 2 で Foo(2) が呼ばれると,Google Mock は,スレッド 1 で action1 を実行し,スレッド 2 で action2 を実行します.

Google Mock では,異なるスレッドで実行される Action がシーケンスのように連続して実行されるという制約はありません(これはデッドロックを起こす可能性があるので,Action 同士の協調が必要になるかもしれません).つまり,上述のサンプルにおける action1 と action2 の実行が,交互に起こるかもしれないという意味です.これが問題ならば,テストをスレッドセーフにするために,action1 と action2 に適切な同期ロジックを追加してください.

また,DefaultValue<T> は,プログラム内のすべてのモックオブジェクトに影響を与える可能性のあるグローバルリソースだという事を思い出してください.当然,これを複数のスレッドから扱ったり,実行中のモックが存在する瞬間に操作したりしないようにしてください.

Google Mock が出力する情報の量を制御する

Google Mock は,潜在的にエラーになるかもしれない何か(例えば,Expectation がないモック関数が呼ばれること,つまり,不要な呼び出しがその例です.これは可能ですが,その呼び出しを明示的に禁止するのを忘れた可能性もあります)を見つけると,その関数の引数と戻り値を含む警告メッセージを表示します.これを見れば,それが実際に問題にならないかどうかを確認する気になるかもしれません.

あるときは,あなたは自分のテストの正しさに自信があり,このような親切なメッセージに価値を認めないかもしれません.別のあるときは,テストをデバッグしている際や,テストしているコードの動作を調べている際に,発生している各モックの呼び出し(そして,その引数と戻り値)を監視したい場合があるかもしれません.万能な設定がないのは明らかです.

コマンドラインフラグ — gmock_verbose=LEVEL を用いて,Google Mock が出力する情報の量を制御することができます.ここで LEVEL は,以下の3つの値を取ることができます:

  • info:Google Mock は,全ての情報を含むメッセージ,警告,エラーを出力します(最も詳細).この設定ではさらに,Google Mock が ON_CALL/EXPECT_CALL マクロの全ての呼び出しを記録します.
  • warning:Google Mock は,警告とエラーを出力します(やや詳細).これがデフォルトです.
  • error:Google Mock は,エラーのみを出力します(詳細ではない).

別の方法として,次のように,テスト内部でこのフラグの値を設定することもできます:

::testing::FLAGS_gmock_verbose = "error";

では,Google Mock をより役立てられるように,正しいフラグを賢く使ってください.

Emacs でテストを実行する

Emacs でテストを書いて実行すると,ソースファイルでの Google Mock と Google Test のエラーの場所が強調表示されます.その1つを選択して <Enter> を押すだけで,問題の行に移動します.また,C-x とタイプすると,次のエラーにジャンプします.

これをさらに簡単にするには,あなたの ~/.emacs ファイルに,次の行を追加してください:

(global-set-key "\M-m"   'compile)  ; m is for make
(global-set-key [M-down] 'next-error)
(global-set-key [M-up]   '(lambda () (interactive) (next-error -1)))

M-m でビルド開始,M-up/M-down で前後のエラーに移動します.

Google Mock のソースファイルを統合する

Google Mock の実装は,(それ自身のテストを含む)数ダースのファイルから構成されています.新しいマシンに簡単にコピーして使うために,これらをより少ないファイルにまとめたい場合があります.scripts/ ディレクトリに,このための実験的な Python スクリプト fuse_gmock_files.py を用意しています(バージョン 1.2.0 以降).マシンに Python 2.4 以降がインストールされていれば,そのディレクトリに移動して,次のように実行

python fuse_gmock_files.py OUTPUT_DIR

すると,OUTPUT_DIR ディレクトリに,gtest/gtest.h と gmock/gmock.h,gmock-gtest-all.cc が作成されているはずです.これらのファイルには,Google Mock(および Google Test) を使うためのすべてが含まれています.これらを好きな場所にコピーするだけで,テストを書いてモックを使う準備が整います.これを使ってテストをコンパイルする例として,ファイル scripts/test/Makefile が参考になります.

Google Mock を拡張する

新規の Matcher を簡単に書く

MATCHER* 形式のマクロを使って,カスタム matcher を簡単に定義することができます.構文は,次のようになります:

MATCHER(name, description_string_expression) { statements; }

これは,statements を実行する,name という名の matcher を定義します.これは,マッチに成功したか否かを示す bool 値を返さなければいけません. statements の中では,マッチされる値を arg で,その型を arg_type で参照できます.

説明文字列は,matcher が何をするかを示す文字列型の式であり,マッチ失敗時の失敗メッセージを生成するのに利用されます.これは,特別な bool 変数 negation を参照できます(そして,ぜひ参照すべきです).negation が false であれば matcher を説明し,negation が true であれば matcher の否定を説明するようにします.

便利のよいように,説明文字列には空文字 (“”) を指定できます.この場合,Google Mock は matcher の名前を構成する一連の文字を説明文として利用します.

例えば:

MATCHER(IsDivisibleBy7, "") { return (arg % 7) == 0; }

とすれば,次のように書くことができます.

// n が 7 の倍数の場合に mock_foo.Bar(n) が呼ばれることを期待します.
EXPECT_CALL(mock_foo, Bar(IsDivisibleBy7()));

または,

using ::testing::Not;
...
  EXPECT_THAT(some_expression, IsDivisibleBy7());
  EXPECT_THAT(some_other_expression, Not(IsDivisibleBy7()));

上記のアサーションが失敗すると,次のようなメッセージが出力されます:

  Value of: some_expression
  Expected: is divisible by 7
    Actual: 27
...
  Value of: some_other_expression
  Expected: not (is divisible by 7)
    Actual: 21

この “is divisible by 7” および “not (is divisible by 7)” という説明文は,matcher 名の IsDivisibleBy7 から自動的に作られるものです.

お気づきのように,自動生成された説明文(特に,否定に対しての文)は,特に優れているというわけではありません.自分の文字列式で,いつでもこれらを上書きできます.

MATCHER(IsDivisibleBy7, std::string(negation ? "isn't" : "is") +
                        " divisible by 7") {
  return (arg % 7) == 0;
}

オプションとして,マッチ結果を説明するための result_listener という名前の隠れ引数に,追加情報を流し込むことができます.例えば,IsDivisibleBy7 のより良い定義は:

MATCHER(IsDivisibleBy7, "") {
  if ((arg % 7) == 0)
    return true;

  *result_listener << "the remainder is " << (arg % 7);
  return false;
}

この説明文を使うと,前述のアサーションは,より分かりやすいメッセージを出力します:

Value of: some_expression
Expected: is divisible by 7
  Actual: 27 (the remainder is 6)

MatchAndExplain() において任意の追加情報を出力し,ユーザがマッチ結果を理解しやすいようにするべきです.成功の場合は,(明らかな場合は除いて)なぜマッチが成功したのかを説明するべきであることに注意してください.- これは, matcher が Not() 内部で利用される場合に役立ちます.Google Mock は既に引数の値を出力するので,それを改めて出力する必要はありません.

注意事項:

  1. マッチされる値の型(arg_type)は,matcher を利用する際のコンテキストにより決まるもので,これはコンパイラによって提供されます.よって,これの宣言について心配する必要はありません(し,そもそも宣言できません).これによって,matcher が多様性を持ちます.例えば,IsDivisibleBy(7) は,(arg % 7) == 0 の値が暗黙のうちに bool に変換可能な任意の型に対して利用できます.上述の Bar(IsDivisibleBy7()) の例では,メソッド Bar() が int を引数にとると arg_type は int に,unsigned long をとると arg_type も unsigned long になります.
  2. Google Mock は,matcher がいつ,何回呼び出されるかを保証しません.したがって,matcher のロジックは純粋関数的(つまり,副作用がなく,その結果は,マッチしている値と matcher のパラメータ以外には影響を受けないもの)でなければいけません.これは,どのように matcher を定義するか(例えば,以降のレシピで説明されるような方法を利用する,など)に関係なく,必ず満足されるべきです.特に,モックオブジェクトと Google Mock の状態に影響を与えてしまうので,matcher はモック関数を呼ぶことができません.

パラメータ化された新規の matcher を簡単に書く

パラメータを持つ matcherを定義したいことがあります.そのためには,次のマクロを利用します:

MATCHER_P(name, param_name, description_string) { statements; }

ここで,説明文字列には “” や,negation および param_name を参照する文字列式が利用できます.

以下に例を示します:

MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; }

この定義により,次のように書くことができます:

EXPECT_THAT(Blah("a"), HasAbsoluteValue(n));

(n が 10 だとすると)これは次のようなメッセージを出力します:

Value of: Blah("a")
Expected: has absolute value 10
  Actual: -9

ヒューマンフレンドリーなメッセージになるように,matcher の説明文とパラメータの両方が出力されることに注意してください

matcher 定義本体では,foo という名前のパラメータの型を参照するために foo_type を使うことができます.例えば,前述の MATCHER_P(HasAbsoluteValue, value) の定義では,value の型を参照するための value_type を利用できます.

Google Mock では,MATCHER_P2, MATCHER_P3, から MATCHER_P10 までの,複数パラメタ用 matcher が用意されています:

MATCHER_Pk(name, param_1, ..., param_k, description_string) { statements; }

カスタムされた説明文字列は,matcher の特定の インスタンス に対してのものであることに注意してください.そこでは,パラメータが実際のある値である事を前提としています.したがって,パラメータ値を説明文の一部として出力してほしいと思うのが普通です.Google Mock では,説明文字列式の中で matcher のパラメータを参照することで,それを可能にします.

以下に例を示します:

using ::testing::PrintToString;
MATCHER_P2(InClosedRange, low, hi,
           std::string(negation ? "isn't" : "is") + " in range [" +
           PrintToString(low) + ", " + PrintToString(hi) + "]") {
  return low <= arg && arg <= hi;
}
...
EXPECT_THAT(3, InClosedRange(4, 6));

これは,次のようなメッセージを含む失敗を生成します:

Expected: is in range [4, 6]

説明文として “” を指定した場合,matcher 名を構成する一連の文字の後に,タプルとして出力されるパラメータ値が続く失敗メッセージになります.以下に例を示します:

MATCHER_P2(InClosedRange, low, hi, "") { ... }
...
EXPECT_THAT(3, InClosedRange(4, 6));

これは,以下のテキストを含む失敗を生成します:

Expected: in closed range (4, 6)

タイプする量を減らすために,次のような表現も可能です.

MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... }

これは,以下の省略表現です.

template <typename p1_type, ..., typename pk_type>
FooMatcherPk<p1_type, ..., pk_type>
Foo(p1_type p1, ..., pk_type pk) { ... }

Foo(v1, ..., vk) と書くと,コンパイラがパラメータ v1, ..., vk の型を推定します.推定された型がふさわしくないものならば,Foo<long, bool>(5, false) というように,テンプレートを明示的にインスタンス化することで型を指定することができます.以前述べたように,arg_type は matcher が利用されるコンテキストによって決められるので,この指定は行いません(必要がありません).

また, FooMatcherPk<p1_type, ..., pk_type> 型の変数に,式 Foo(p1, ..., pk) の結果を代入することができます.これは,matcher を組み合わせる際に便利です.パラメータを持たない matcher ,または1つのパラメータだけを持つ matcher は,特別な型を持ちます:Foo() は FooMatcher 型の変数に代入でき,Foo(p) は FooMatcherP<p_type> 型の変数に代入できます.

参照する型に応じて matcher テンプレートをインスタンス化できますが,そのパラメータをポインタで渡すと,コードが読みやすくなることが多いです.しかし,もしパラメータを参照で渡したいならば,matcher に生成される失敗メッセージ中に表示されるのは,参照されたオブジェクトのアドレスではなく値である,という点に注意してください.

異なる数のパラメータをとる matcher をオーバーロードすることができます:

MATCHER_P(Blah, a, description_string_1) { ... }
MATCHER_P2(Blah, a, b, description_string_2) { ... }

新しい matcher を定義する際に,常に MATCHER* マクロを利用するという選択肢は魅力的ですが,それの代わりに,MatcherInterface を実装したり, MakePolymorphicMatcher() (後述のレシピを参照)を利用したりすることを考慮するべきです.大量の matcher を利用する必要がある場合は,特にそうです.これらのアプローチでは,やることは多いですが,マッチされている値の型や matcher のパラメータの制御を行うことができます.通常は,それによって,コンパイルエラーメッセージがより分かりやすいものになるので,長い目で見れば優れいていると言えます.また,(単にパラメータの個数に基づくものではなく)パラメータの型に基づいた matcher のオーバーロードも可能になります.

新規の モノモーフィック matcher を書く

引数の型が T である matcher は, ::testing::MatcherInterface<T> を実装し,2つのことを実行します:型が T である値が matcher にマッチするかどうかをテストします.そして,マッチする値がどういう種類のものなのかを記述します.後者の機能は,Expectation が満たされなかった場合に,読みやすいエラーメッセージを生成するために利用されます.

そのインタフェースは,次のようになります:

class MatchResultListener {
 public:
  ...
  // 内部の ostream に x を流し込みます.もし, ostream が
  // NULL の場合には何もしません.
  template <typename T>
  MatchResultListener& operator<<(const T& x);

  // 内部の ostream を返します.
  ::std::ostream* stream();
};

template <typename T>
class MatcherInterface {
 public:
  virtual ~MatcherInterface();

  // matcher が x にマッチした場合にのみ true を返します.
  // また,そのマッチ結果を `listener` に説明します.
  virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0;

  // この matcher の説明を ostream に書きだします.
  virtual void DescribeTo(::std::ostream* os) const = 0;

  // この matcher の negation の説明を ostream に書きだします.
  virtual void DescribeNegationTo(::std::ostream* os) const;
};

カスタム matcher が必要にもかかわらず,Truly() を使う選択肢が適切でない場合(例えば,Truly(predicate) を使った場合の自分自身の説明が適切でない場合,または Eq(value) のようにポリモーフィックな matcher が欲しい場合,などです),完全に自分の望む動作をする matcher を2段階で定義します:まず,matcher インタフェースを実装して,それから,matcher インスタンスを作成するファクトリ関数を定義します.これの,第2段階部分は必須というわけではないですが,matcher の構文を便利なものにしてくれます.

例えば次のようにすると,ある整数が 7 で割り切れるかどうかをテストする matcher を定義して,それを利用できます:

using ::testing::MakeMatcher;
using ::testing::Matcher;
using ::testing::MatcherInterface;
using ::testing::MatchResultListener;

class DivisibleBy7Matcher : public MatcherInterface<int> {
 public:
  virtual bool MatchAndExplain(int n, MatchResultListener* listener) const {
    return (n % 7) == 0;
  }

  virtual void DescribeTo(::std::ostream* os) const {
    *os << "is divisible by 7";
  }

  virtual void DescribeNegationTo(::std::ostream* os) const {
    *os << "is not divisible by 7";
  }
};

inline Matcher<int> DivisibleBy7() {
  return MakeMatcher(new DivisibleBy7Matcher);
}
...

  EXPECT_CALL(foo, Bar(DivisibleBy7()));

MatchAndExplain() の listener 引数に対して,追加の情報を流し込むことで,この matcher メッセージを改良することができます.

class DivisibleBy7Matcher : public MatcherInterface<int> {
 public:
  virtual bool MatchAndExplain(int n,
                               MatchResultListener* listener) const {
    const int remainder = n % 7;
    if (remainder != 0) {
      *listener << "the remainder is " << remainder;
    }
    return remainder == 0;
  }
  ...
};

EXPECT_THAT(x, DivisibleBy7()); は,次のようなメッセージを生成します:

Value of: x
Expected: is divisible by 7
  Actual: 23 (the remainder is 2)

新規の ポリモーフィック matcher を書く

上述のレシピでは,独自の matcher を書く方法を学びました.ただし,1つだけ問題があります:MakeMatcher() を使って作成された matcher は,引数の特定の型に対してのみ動作するということです.もし,複数の型に対して動作するポリモーフィックな matcher (例えば Eq(x) の場合, value == x がコンパイル可能ならば,value に対するマッチに利用できます.ここで, value と x は同じ型である必要はありません)が必要ならば, “gmock/gmock-matchers.h” に書かれてあるトリックを学ぶのもありです.ただし,少しややこしいですが.

幸いなことに,MakePolymorphicMatcher() を利用すれば,大抵の場合,簡単にポリモーフィック matcher を定義することができます.ここでは例として,NotNull() を定義する方法を示します:

using ::testing::MakePolymorphicMatcher;
using ::testing::MatchResultListener;
using ::testing::NotNull;
using ::testing::PolymorphicMatcher;

class NotNullMatcher {
 public:
  // ポリモーフィック matcher を実装するために,まず,
  // 以下のように MatchAndExplain(), DescribeTo(),  DescribeNegationTo()
  // の3つのメンバ関数を持つ「コピー可能な」クラスを定義します.

  // この例では,NotNull() を任意のポインタに対して利用したいので,
  // MatchAndExplain() は,第1引数として任意の型のポインタを受け取ります.
  // 通常,MatchAndExplain() を,普通のメソッドやメソッドテンプレート
  // のように定義するか,または,それをオーバーロードします.
  template <typename T>
  bool MatchAndExplain(T* p,
                       MatchResultListener* /* listener */) const {
    return p != NULL;
  }

  // この matcher にマッチする値の性質を記述します.
  void DescribeTo(::std::ostream* os) const { *os << "is not NULL"; }

  // この matcher にマッチしない値の性質を記述します.
  void DescribeNegationTo(::std::ostream* os) const { *os << "is NULL"; }
};

// ポリモーフィック matcher を作成するには,そのクラスのインスタンスを
// MakePolymorphicMatcher() に渡します.戻り値の型に注意してください.
inline PolymorphicMatcher<NotNullMatcher> NotNull() {
  return MakePolymorphicMatcher(NotNullMatcher());
}
...

  EXPECT_CALL(foo, Bar(NotNull()));   // この引数は,必ず NULL ではないポインタです.

注意: ポリモーフィック matcher クラスは,MatcherInterface などの他のクラスを継承する必要は ありません. そして,そのメソッドも virtual である必要は ありません.

モノモーフィック matcher のように,MatchAndExplain() の listener 引数に追加情報を流し込んで,マッチ結果を説明することもできます.

新規の Cardinality を書く

cardinality は,ある呼び出しに期待する発生回数を Google Mock に伝えるために,Times() で利用されます.これは厳密な回数である必要はありません.例えば,AtLeast(5) や Between(2, 4) という書き方もできます.

cardinality の組み込みセットでは不十分ならば,(testing 名前空間にある)次に示すインタフェースを実装することで,自由にそれを定義することができます:

class CardinalityInterface {
 public:
  virtual ~CardinalityInterface();

  // call_count の呼び出しが,この cardinality を満足する場合にのみ true を返します.
  virtual bool IsSatisfiedByCallCount(int call_count) const = 0;

  // call_count の呼び出しが,この cardinality を飽和する場合にのみ true を返します.
  virtual bool IsSaturatedByCallCount(int call_count) const = 0;

  // 自分自身の説明を ostream に出力します.
  virtual void DescribeTo(::std::ostream* os) const = 0;
};

例えば,呼び出しが必ず偶数回でなければいけないならば,次のように書きます.

using ::testing::Cardinality;
using ::testing::CardinalityInterface;
using ::testing::MakeCardinality;

class EvenNumberCardinality : public CardinalityInterface {
 public:
  virtual bool IsSatisfiedByCallCount(int call_count) const {
    return (call_count % 2) == 0;
  }

  virtual bool IsSaturatedByCallCount(int call_count) const {
    return false;
  }

  virtual void DescribeTo(::std::ostream* os) const {
    *os << "called even number of times";
  }
};

Cardinality EvenNumber() {
  return MakeCardinality(new EvenNumberCardinality);
}
...

  EXPECT_CALL(foo, Bar(3))
      .Times(EvenNumber());

新規の Action を簡単に書く

もし,組み込みの Action では不十分で,Invoke() を使うのが不便だと思うならば,新しい Action を素早く定義するのに ACTION* 形式のマクロを利用できます.この Action は,あなたのコード内で,組み込みの Action と同様に利用できます.

次のように書きます.

ACTION(name) { statements; }

これによって,名前空間内部で(つまり,クラスや関数の内部ではありません),statements を実行する name という名前の Action が定義されます.statements に返される値が,この Action の戻り値として利用されます.statements 内部では,モック関数の K-番目(0基準)の引数を argK として参照できます.次に例を示します:

ACTION(IncrementArg1) { return ++(*arg1); }

これにより,次のように書くことができます.

... WillOnce(IncrementArg1());

ここで,モック関数の引数の型を指定する必要がないことに注意してください.しかし,あなたのコードは型安全なので安心してください:*arg1 が ++ 演算子をサポートしていない場合,または,++(*arg1) の型がモック関数の戻り値と互換性がない場合は,コンパイルエラーが起こります.

さらに,別の例を示します:

ACTION(Foo) {
  (*arg2)(5);
  Blah();
  *arg1 = 0;
  return arg0;
}

これは,以下のような動作を行う Action Foo() を定義します.まず,2番目の引数(関数ポインタ)に 5 を与えて実行します.そして,関数 Blah() を呼び出します.さらに,1番目の引数によって指される値に 0 をセットします.最後に,0番目の引数を返します.

利便性と柔軟性のために,ACTION の定義部分で,次のような定義済みシンボルを利用することもできます:

   
argK_type モック関数のK-番目(0基準)の引数の型
args タプルで表現された,モック関数の全ての引数
args_type タプルで表現された,モック関数の全ての引数の型
return_type モック関数の戻り値の型
function_type モック関数の型

例えば,次のようなモック関数のスタブ Action として ACTION を利用する場合を考えます:

int DoSomething(bool flag, int* ptr);

ここで,以下のシンボルを利用できます:

定義済みシンボル 紐づけられた先
arg0 flag の値
arg0_type bool 型
arg1 ptr の値
arg1_type int* 型
args タプル (flag, ptr)
args_type std::tr1::tuple<bool, int*> 型
return_type int 型
function_type int(bool, int*) 型

新規の パラメータ化された Action を簡単に書く

あなたが定義した Action をパラメータ化したい場合もあるでしょう.それ用のマクロを用意してあります.

ACTION_P(name, param) { statements; }

例えば,次のように書きます.

ACTION_P(Add, n) { return arg0 + n; }

これにより,以下のように書くことができます.

// 0番目の引数 + 5 を返します.
... WillOnce(Add(5));

ここでは便宜上,モック関数の実行時に使われる値を表すのに 引数 ,Action をインスタンス化するための値を表すのに パラメータ という表現を用います.

パラメータの型を与える必要もないことに注意してください.パラメータが param という名前だとすると,Google-Mock が定義した シンボル param_type を利用して,コンパイラによって推定されたパラメータの型を参照することができます.例えば,上述した ACTION_P(Add, n) の定義部分で,n の型を参照するのに n_type を利用することができます.

Google Mock には,ACTION_P2,ACTION_P3 などの,マルチパラメータ Action をサポートするものも用意されています.例えば,

ACTION_P2(ReturnDistanceTo, x, y) {
  double dx = arg0 - x;
  double dy = arg1 - y;
  return sqrt(dx*dx + dy*dy);
}

とすると,次のように書くことができます.

... WillOnce(ReturnDistanceTo(5.0, 26.5));

ACTION は,パラメータ化された Action の劣化版,つまりパラメータ数が 0 個のもの,と見なすこともできます.

また,パラメータ数をオーバーロードした Action も簡単に定義できます:

ACTION_P(Plus, a) { ... }
ACTION_P2(Plus, a, b) { ... }

ACTION の引数やパラメータの型を制限する

最も簡潔かつ再利用可能にするため,ACTION* マクロでは,モック関数の引数の型と Action パラメータの型を与えなくても構いません.代わりに,それらの型をコンパイラに推定してもらいます.

しかし,場合によっては,その型について明示したいことがあるでしょう.それを行うためのトリックがいくつかあります.例を示しましょう:

ACTION(Foo) {
  // arg0 が確実に int に変換できることを確認します.
  int n = arg0;
  // ... ここでは,arg0 の代わりに n を利用します ...
}

ACTION_P(Bar, param) {
  // arg1 の型が const char* であることを確認します.
  ::testing::StaticAssertTypeEq<const char*, arg1_type>();

  //  param が確実に bool に変換できることを確認します.
  bool flag = param;
}

ここで, StaticAssertTypeEq は,2つの型が同じであることを検証する,Google Test のコンパイル時アサーションです.

新規の Action テンプレートを簡単に書く

場合によっては,値パラメータからの推定が不可能なテンプレートパラメータを明示的に Action に渡したいこともあるでしょう.ACTION_TEMPLATE() は,それをサポートするもので,ACTION() と ACTION_P*() の拡張のように見なすことができます.

構文は次のようになります:

ACTION_TEMPLATE(ActionName,
                HAS_m_TEMPLATE_PARAMS(kind1, name1, ..., kind_m, name_m),
                AND_n_VALUE_PARAMS(p1, ..., p_n)) { statements; }

これは,m 個の明示的なテンプレートパラメータ,および n 個の値パラメータを受け取る Action テンプレートを定義します.ここで,m は 1 から 10 の間,n は 0 から 10 の間の数です.name_i は,i-番目のテンプレートパラメータの名前であり,kind_i は,それが typename ,整数の値,テンプレートのいずれであるかを示します.また,p_i は,i-番目の値パラメータの名前です.

例:

// DuplicateArg<k, T>(output) は,モック関数の k-番目の引数を
// 型 T に変換して,それを *output にコピーします.
ACTION_TEMPLATE(DuplicateArg,
                // Note the comma between int and k:
                HAS_2_TEMPLATE_PARAMS(int, k, typename, T),
                AND_1_VALUE_PARAMS(output)) {
  *output = T(std::tr1::get<k>(args));
}

Action テンプレートのインスタンスを作成するには,次のように書きます:

ActionName<t1, ..., t_m>(v1, ..., v_n)

ここで t はテンプレート引数で,v は値引数です.値引数の型は,コンパイラによって推定されます.例えば,次のようになります:

using ::testing::_;
...
  int n;
  EXPECT_CALL(mock, Foo(_, _))
      .WillOnce(DuplicateArg<1, unsigned char>(&n));

値引数の型を明示的に指定したい場合,追加テンプレート引数に追加して渡すことができます:

ここで, u_i は,希望する v_i の型となります.

ACTION_TEMPLATE および ACTION/ACTION_P* は,値パラメータの数を変えてオーバーロードすることができますが,テンプレートパラメータの数に対しては,そういうことはできません.もし,この制限がなければ,以下のような場合の解釈があいまいになります:

OverloadedAction<int, bool>(x);

これは,1つのテンプレートパラメータを持つ Action で,bool は x の型を参照するものなのでしょうか,それとも,2つのテンプレートパラメータを持つ Action で,x の型はコンパイラが推定するのでしょうか?

ACTION オブジェクトの型を利用する

ACTION オブジェクトを返す関数を書く場合,その型を知っておく必要があります.その型は,Action を定義するマクロとそのパラメータ型に依存します.そのルールは,比較的シンプルです:

定義
ACTION(Foo) Foo() FooAction
ACTION_TEMPLATE(Foo, HAS_m_TEMPLATE_PARAMS(...), AND_0_VALUE_PARAMS()) Foo<t1, ..., t_m>() FooAction<t1, ..., t_m>
ACTION_P(Bar, param) Bar(int_value) BarActionP<int>
ACTION_TEMPLATE(Bar, HAS_m_TEMPLATE_PARAMS(...), AND_1_VALUE_PARAMS(p1)) Bar<t1, ..., t_m>(int_value) FooActionP<t1, ..., t_m, int>
ACTION_P2(Baz, p1, p2) Baz(bool_value, int_value) BazActionP2<bool, int>
ACTION_TEMPLATE(Baz, HAS_m_TEMPLATE_PARAMS(...), AND_2_VALUE_PARAMS(p1, p2)) Baz<t1, ..., t_m>(bool_value, int_value) FooActionP2<t1, ..., t_m, bool, int>
... ... ...

値パラメータの個数が異なる Action に対しては,異なるサフィックスを付ける必要がある(Action,ActionP,ActionP2 など)ことに注意してください.そうしなければ,Action の定義がオーバーロードされてしまいます.

新規の モノモーフィック Action を書く

ACTION* マクロは非常に便利ですが,時には適切ではない場合もあります.例えば,前述のレシピで説明したトリックを用いても,モック関数の引数の型,およびアクションパラメータの型を,直接指定することはできず,そのようなことをすると,慣れていないユーザを困惑させるコンパイラのエラーメッセージが出されるのが普通です.また,いくつかの要求に従う事なしには,パラメータの型のオーバーロードもできません.

ACTION* マクロに変わる代替手段は, ::testing::ActionInterface<F> を実装することです.ここで F は,その中で Action が利用されるモック関数の型です.

template <typename F>class ActionInterface {
 public:
  virtual ~ActionInterface();

  // Action を実行します.結果は,型 F の関数の戻り値型であり,
  // ArgumentTuple は,F の引数のタプルです.
  //
  // 例えば,F が int(bool, const string&) とすると,この結果は int になり,
  // ArgumentTuple は,tr1::tuple<bool, const string&> となります.
  virtual Result Perform(const ArgumentTuple& args) = 0;
};

using ::testing::_;
using ::testing::Action;
using ::testing::ActionInterface;
using ::testing::MakeAction;

typedef int IncrementMethod(int*);

class IncrementArgumentAction : public ActionInterface<IncrementMethod> {
 public:
  virtual int Perform(const tr1::tuple<int*>& args) {
    int* p = tr1::get<0>(args);  // 最初の引数を捕まえます.
    return *p++;
  }
};

Action<IncrementMethod> IncrementArgument() {
  return MakeAction(new IncrementArgumentAction);
}
...

  EXPECT_CALL(foo, Baz(_))
      .WillOnce(IncrementArgument());

  int n = 5;
  foo.Baz(&n);  // 5が返され,nは6に変更されます.

新規の ポリモーフィック Action を書く

前述のレシピでは,独自の Action を定義する方法を説明しました.関数(この中で Action が利用されます)の型を知る必要があることを除けば,これは良いことずくめの方法です.しかし,これが問題になる場合もあります.例えば,(Return() と SetArgPointee() のように)複数の異なる型の関数内で Action を利用したい場合です.

複数の型のモック関数内で利用できる Action を, ポリモーフィック であるといいます. MakePolymorphicAction() 関数テンプレートを使うと,このような Action を簡単に定義できます:

namespace testing {

template <typename Impl>
PolymorphicAction<Impl> MakePolymorphicAction(const Impl& impl);

}  // testing 名前空間

例として,モック関数の引数リストの内,2番目の引数を返すような Action を定義してみましょう.最初のステップは,実装クラスを定義することです:

class ReturnSecondArgumentAction {
 public:
  template <typename Result, typename ArgumentTuple>
  Result Perform(const ArgumentTuple& args) const {
    // i-番目(0基準)の引数を得るには, tr1::get<i>(args) を使います.
    return tr1::get<1>(args);
  }
};

この実装クラスは,基底クラスを継承する必要がありません.必ず Perform() メソッドテンプレートを持つ,という事が肝心なのです.このメソッドテンプレートは,モック関数の引数を要素とする 1つの タプル,を引数にとり,この Action の結果を返します.const でも,そうでなくても構いませんが,厳密に1つのテンプレート引数,つまり結果の型を与えて実行可能なものである必要があります.言い換えれば,必ず Perform<R>(args) を呼び出すことができなければいけない,とうことです.ここで,R はモック関数の戻り値型であり,args はその引数を要素とするタプルです.

次のステップでは,MakePolymorphicAction() を使って,この実装クラスのインスタンスを必要なポリモーフィック Action に変換します.これ用のラッパーがあれば便利でしょう:

using ::testing::MakePolymorphicAction;
using ::testing::PolymorphicAction;

PolymorphicAction<ReturnSecondArgumentAction> ReturnSecondArgument() {
  return MakePolymorphicAction(ReturnSecondArgumentAction());
}

これで,組み込みのものと同様に,ポリモーフィック Action を使うことができます:

using ::testing::_;

class MockFoo : public Foo {
 public:
  MOCK_METHOD2(DoThis, int(bool flag, int n));
  MOCK_METHOD3(DoThat, string(int x, const char* str1, const char* str2));
};
...

  MockFoo foo;
  EXPECT_CALL(foo, DoThis(_, _))
      .WillOnce(ReturnSecondArgument());
  EXPECT_CALL(foo, DoThat(_, _, _))
      .WillOnce(ReturnSecondArgument());
  ...
  foo.DoThis(true, 5);         // 5 を返します.
  foo.DoThat(1, "Hi", "Bye");  // "Hi" を返します.

Google Mock に値の表示方法を教示する

不要な,または期待されない呼び出しが起こった場合,Google Mock は,デバッグの助けになるように,その引数の値とスタックトレースを出力します.EXPECT_THAT や EXPECT_EQ のようなアサーションマクロも,そのアサーションが失敗した時には,式の値を出力します.Google Mock と Google Test は,ユーザが拡張可能な値プリンタという Google Test の機能を利用して,これを行います.

このプリンタは,C++ の組み込み型,ネイティブな配列,STL コンテナ,<< 演算子をサポートする任意の型を出力することができます.しかし,その他の型の場合は,生のバイト値を表示して,ユーザがそれの意味を分かってくれることを願うのみです.特定の型を,バイトダンプするよりも綺麗な形式で出力できるようにこのプリンタを拡張する方法は,Google Test の 上級ガイド で説明されています.

目次

このページ