Help us understand the problem. What is going on with this article?

Google Test / Mock の自分用チートシート

More than 1 year has passed since last update.

概要

前回、自分の仕事で使うCのためのGoogleMock環境まで作ったので、もう少し勉強してみることにしました。
Google C++ Mocking Framework チートシート」とかあるにはあるんですがいまいちわかりづらくてさっと見ただけだと頭に入ってこないので、読みながらまとめてチートシート的なものを自分用に作ることにしました。
順次更新していきます。

マクロとかのまとめ

TEST(), TEST_F(), TEST_P()

https://github.com/google/googletest/blob/master/googletest/docs/primer.md#simple-tests

TEST(TestSuiteName, TestName) {
  ... test body ...
}
  • テストケースの大項目的な名前と小項目的な名前を入れます。
    • アンダースコアを使うのは良くないらしいです。なんか使えますが。
    • 複数のテストがある場合は大項目名と小項目名の組み合わせが重複しないようにしないとビルドエラーになります。
  • TEST_Fでは第一引数はテストフィクスチャとして定義したクラス名にします。
  • TEST_Pは上級テクニックで、1つのテストをパラメーターを変えながら何度も実行することができます。

ASSERT_EQ, EXPECT_EQ

http://opencv.jp/googletestdocs/primer.html#primer-binary-comparison

  • 第一引数が期待する値、第二引数が実際の値。関数を実行したときの戻り値のチェックなどに使えます。
  • EXPECT_NEEXPECT_TRUEなどの親戚もいます
  • 状況が期待と異なったときにすぐにテストが終了させられるのがASSERT_*、続行するのがEXPECT_*です。

MOCK_METHOD*, MOCK_CONST_METHOD*

  • mockのメソッドの定義に使います。*の部分は引数の数です。
    • 引数の数は10を超えると死んだりします。やたら引数が多い関数がある残念なプロジェクトでは対策が必要です。

EXPECT_CALL

  • Mockのメソッドが呼び出されることを宣言します。第一引数がMock化されたクラスのインスタンス(ポインターではなく実体)、第二引数がメソッド名
    • メソッド名は引数をセットで指定します。引数がマッチしない呼び出しをされた場合は呼び出されなかったことになります。
    • 後述の::testing::_を使うことで引数のチェックを省けます
  • 後述のNiceMockではない場合、EXPECTされていないMockメソッド呼び出しは警告されます。(テストは成功したりします)。EXPECTした呼び出しがなかった場合はテストは失敗になります。

::testing::_

https://github.com/google/googletest/blob/master/googlemock/docs/cheat_sheet.md#wildcard

  • 正確な定義としてはMatcherのwildcardであり、その名のとおり任意の引数を許します
  • Matcherは上記のページにいろいろあるので見ておくと何か使えるものがあるかもしれません

Times

http://opencv.jp/googlemockdocs/fordummies.html#cardinalities
* EXPECT_CALLのメンバーのような形で使用して、呼び出し回数を指定できます。cardinality(基数)というそうです。
* ::testing::AtLeast(n)(nは0以上の整数)で回数チェックを緩くできます
* 指定回数まで呼び出されてないとテストは失敗になります
* Times(0)にすることでそのメソッドが呼び出されないことを宣言できます
* Times(1)は省略できます。

WillOnce, WillRepeatedly

http://opencv.jp/googlemockdocs/fordummies.html#fordummies-general-syntax

  • EXPECT_CALLのメンバーのような形で使用して、呼び出されたときのactionを定義できます
    • actionは主に戻り値の指定になると思います。戻り値がないメソッドではそれはできません。
  • Will**Timesのあとに書く必要があります。
  • WillOnceは複数使用でき、その都度の戻り値をactionを変えることができます。
using ::testing::Return;...
EXPECT_CALL(turtle, GetX())
    .Times(5)
    .WillOnce(Return(100))
    .WillOnce(Return(150))
    .WillRepeatedly(Return(200));

::testing::Return

https://github.com/google/googletest/blob/master/googlemock/docs/cheat_sheet.md#actions-actionlist

  • 上述のWill**のactionとして値を戻す動作をします
  • actionも上記のページのようにいくつか種類があるようです。使いどころがいまいちわからないですが……

RetiresOnSaturation

http://opencv.jp/googlemockdocs/fordummies.html#expectation-sticky

  • EXPECT_CALLのメンバーのような形で使用して、そのEXPECT_CALLの役割が終わったらそれ以上EXPECT_CALLを見ないように指定できます。

Google Mock の Expectation がデフォルトでは,「sticky」であることを表しています

  • stickyが具体的にどういうものかはいろいろテストを作って肌で学ぶしかないかと思います

::testing::Invoke

http://opencv.jp/googlemockdocs/cheatsheet.html#cheatsheet-using-afunction-or-functor

  • 下記のように関数をactionとして定義できます。mockではなくfake的な使い方になりますね。
double Distance(Unused, double x, double y) { return sqrt(x*x + y*y); }
...
EXPECT_CALL(mock, Foo("Hi", _, _)).WillOnce(Invoke(Distance));
  • actionにInvokeで登録する関数は、Mockのメソッドと同じ関数の形(もしくはvoid*など互換性のある形)である必要があります。
    • 使用しない引数はUnusedにすることもできます。上記の例でも使ってます。
  • InvokeWithoutArgsなどもあるようです。これは引数を受け取らない代わりに一切の引数を無視できるようです。
  • Actionを定義するなどもありますが……

NiceMock<>

http://opencv.jp/googlemockdocs/cookbook.html#nice-strict

  • これで宣言されたMockは、そのMockのメソッドがEXPECT_CALLで設定される前に呼ばれてもAssertなどを出しません。
    • 「まずは EXPECT_CALL を明示してモックの挙動を指定しましょう」
    • 「非常に慎重に利用するべきです」「バグが警告されず見過ごされる可能性があります」
    • どうでもいいクラスに対してのみ使うようにするのを私もおすすめします
  • 親戚にStrictMockもいます。

文法的なもの

テストフィクスチャ

https://github.com/google/googletest/blob/master/googletest/docs/primer.md#test-fixtures-using-the-same-data-configuration-for-multiple-tests

  • ::testing::Testから派生したクラスを定義してフィクスチャ(妥当な日本語がないが、定番とか基本的な概念といったニュアンスだと思います)を作れます。
  • 具体的には、フィクスチャで作成したインスタンスをテストケース間で共有したりとかできます。、

RUN_ALL_TESTSとmain関数

http://opencv.jp/googletestdocs/primer.html#primer-invoking-the-tests
http://opencv.jp/googlemockdocs/fordummies.html#fordummies-using-mocks-in-tests

  • フィクスチャやモックを使用する場合はそれらの初期化のためにmain()が必要なようです。
  • main()を用意した場合はmain()のreturnでRUN_ALL_TESTS()を実行するようにすると良いようです。
    • RUN_ALL_TESTSですべてのテストを実行します。このとき、Setup()とTearDown()が各テストごとに実行されることに注意が必要です。

::testing::InitGoogleMock

  • Mockを使用する場合の初期化をするようです。詳しくはよくわからない……おまじない状態です。

複数のException(EXPECT_CALL)

http://opencv.jp/googlemockdocs/fordummies.html#fordummies-using-multiple-expectations

  • 複数のmatcher(match条件)に対するEXPECT_CALLをあらかじめ書いておくことができます。
EXPECT_CALL(turtle, Forward(_));  // #1
EXPECT_CALL(turtle, Forward(10))  // #2
    .Times(2);
  • ただし複数のExceptionは独特の動作をするのでテストに苦労することがあります:
    • Matchの判定は最後に定義されたものから順にするようです
    • 同じmatcherに対して複数のEXPECT_CALLを書くと最後に宣言したもので上書きされたりします
  • 同じMatch条件で複数の動作をさせたい場合はWillOnceを複数つけたり、::testing::Invokeを使います

InSequence

http://opencv.jp/googlemockdocs/fordummies.html#fordummies-ordered-vs-unordered

  • メソッドの呼び出し順をチェックできます
    • あまり使わないので詳説できないです。呼び出し順をテストしなければいけない状況がすでに終わってる……でもうまく使えばテストコードが見やすくなるんでしょうか?
    • ここら辺になるともう中級テクニックな感じですね
  • 別の例ではEXPECT_CALLにくっつけてシーケンスを定義する方法も書いてあります。
  • 順序に関連してAfterというのあります。

ON_CALLとデフォルトのaction

http://opencv.jp/googlemockdocs/cheatsheet.html#action

  • ON_CALLでメソッドのデフォルトのactionを指定するようです
  • Times未指定のWillRepeatedlyでも同じようなことができますが、ON_CALLを使うのが本来の手順なのかもしれません
  • DefaultValue<T>::Set(value)というのもあるようです。

よくわからなかったやつ

  • MOCK_METHOD_1_WITH_CALLTYPE
  • ::testing::Mock::VerifyAndClearExpectations + その仲間
    • destructionを検証できる?
hakua-doublemoon
横浜の外周部で組み込み装置のファームウェア開発やってます。RTOSのカーネル・ネットワーク関連からはじまりゴリゴリのHW依存のアプリケーション作ったりQtでGUI作ったり、LabVIEWでの画像処理とかもしてます。Ruby/RailsやRustが好きですがそれは本職とはあんまり関係ない。
https://pawoo.net/web/accounts/586636
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした