C/C++

【C/C++】gtestの使い方まとめ(基本編)

以前の記事(http://www.mathkuro.com/?p=1294)の続きです。
インストール方法やコンパイル方法等の基本的な部分は、以前の記事を参照してください。

※pythonのunittestの時みたいに記事が長くなって読みにくくなりそうなので基本編・応用編に分けようと思います。

1.gtest概要

以前も紹介しましたが、gtestはgoogle謹製のC/C++向け単体試験ツールです。
python使ったことがある人ならunittestを想像してもらえれば良いです。

gtestでとりあえず覚えておくべきことは以下の三つです。
①アサーション
②テスト
③テストケース

それぞれ説明していきます。

1-1 アサーション

テスト対象の関数等の実行結果を判定するためのマクロです。

例えば、合計値を返す関数をテストする場合は以下のようなアサーションを使用します。
EXPECT_EQ(3, sum(1, 2));
これはsum(1, 2)の戻り値が3であればOK、そうでなければNGとなる判定です。

アサーションにはASSERT_EQ, EXPECT_EQ等、いろいろな種類があります。
数が多いので別章にまとめています。

1-2 テスト

個別のテストのことです。
基本的にテスト毎のOK/NGが結果のOK数/NG数に計上されます。

上述のアサーションはテスト内に記述し、一つ以上のアサーションがNGの場合にテストはNGとなります。
※アサーションが全くないテストはOK扱いとなります。

1-3 テストケース

テストを分類するためのもので、全てのテストはテストケースに属する必要があります。

テスト実行時にテストケース毎に実行したりできるので、基本的には意味のある単位でまとめるべきです。
※クラスの分け方に近いかもしれないです

1-4 アサーション・テスト・テストケースの記述例

// TEST()マクロを使用して、テストを作成
TEST(Hoge, Fuga) {
    // アサーションを使用してテスト
    EXPECT_EQ(3, sum(1, 2));
}

gtestではTEST()マクロを使用してテストを記述します。

マクロの第一引数(Hoge)がテストケース名、第二引数(Fuga)がテスト名になります。
※テストケース名・テスト名はアンダースコア(_)が使用できないので注意。

テストケースは1ファイルに複数存在しても問題ないですし、逆に複数ファイルに分けても問題ないです。


この辺までは前回もチラッと触れた部分ですが、おさらいも兼ねて概要としてまとめました。
ここから先は、上述の内容が理解できている前提で、より具体的な使用例を紹介していきます。

2.gtestの使い方(基本編)

2-1 普通の関数の試験

まずは基本中の基本、普通の関数の試験です。

概要でほとんど説明してしまった感があるので早速サンプルコードです。

テスト対象のコード(sum.cxx)

int sum(int a, int b) {
    return a + b;
}


テストコード(test.cxx)

#include "gtest/gtest.h"

#include "sum.cxx"

TEST(MyTestCase, TestSum) {
    EXPECT_EQ(3, sum(1, 2));
}


コンパイル(gtestとテスト対象コードのパスは通っている前提)
$ g++ -std=c++11 ./test.cxx -lgtest_main -lgtest

※コンパイル方法は変わらないので次の例からは省略します。

2-2 クラスの試験

クラスの試験もぶっちゃけ普通の関数の試験と大差ありません。

サンプルコードです。

※一ファイルで記述しているのは、記事を書く上でファイルを分けるのが面倒だっただけです。一つ前の例同様、ファイルを分けても問題ないです。

2-3 例外の試験

gtestは例外の試験を行うことも可能です。

準正常/異常系の試験を行う上でとても便利で、テストコードもとても簡単です。

以下のいずれかのアサーションを使用するだけです。
・「特定の例外が投げられた(EXPECT_THROW)」
・「何らかの例外が投げられた(EXPECT_ANY_THROW)」
・「例外が投げられない(EXPECT_NO_THROW)」

以下、サンプルコードです。

2-4 テストフィクスチャ

テストフィクスチャは、同じようなデータを持つテストをまとめるためのものです。

前述のテストケースの上位互換と考えれば分かり易いかもしれません。
(意味的には異なりますが)

テストフィクスチャでは、以下のようなことができます。
・データの再利用
・テスト毎の初期化・終了処理の共通化

使用方法はたったの2ステップでイージーです。
①テストフィクスチャクラスの作成
②TEST_F()マクロの使用

イメージ的には、①で作成したテストフィクスチャクラスのオブジェクトや初期化・終了処理を②のTEST_F()を使用することで自動的に適用してくれる、といった感じです。

細かい部分はコードを見た方が分かりやすいかと思いますので、サンプルコードをどうぞ。

初期化処理等を共通化できるので、クラスの試験等でとても便利です。

ただ、一つだけ注意点があります。
テストフィクスチャクラスのインスタンスはテスト毎に生成されます

例えば、TEST_F(MyFixture, Test01), TEST_F(MyFixture, Test02)があった場合に、Test01MyFixtureに何らかの値を設定したとしても、その値はTest02では参照できないです。

テスト毎に初期化・終了処理が行われるんだと覚えておきましょう(自戒)。

余談ですが、フィクスチャ(fixture)は、備品という意味らしいです。

3.アサーションについて

概要で紹介したアサーションですが、種類が多いので別章にしました。

3-1 ASSERTとEXPECTの違い

まず、アサーションには大きく分けて、ASSERTとEXPECTがあります。

ASSERTASSERTでNGとなった場合は、そのテストはそこで終了し、次のテストへと移行する。
EXPECTEXPECTでNGとなった場合は、そのテストはNG扱いとはなるが、テスト自体は最後まで実行する。

どちらもNGとなることに変わりはないのですが、NGの結果出力が変わってきます。

例えば、テスト内にアサーションが複数あり、その全てでNGとなる場合に、EXPECTだと全てのNG理由が結果として出力されますが、ASSERTの場合は、一つ目で実行を停止するため、二つ目以降のNGは出力されません。

「じゃあ全部EXPECTでよくね?」と思うかもしれませんが、逆に、一つ目がNGの場合は以降の値は全て意味がない場合、EXPECTだと無駄にテストが進んでしまい、最悪セグフォ等の恐れがあります。

以降のテストを実施する意味がない場合はASSERT、そうでない場合は EXPECTと、使い分けるようにしましょう。

3-2 アサーション一覧

よく使いそうなアサーションをまとめました。

※省略してEXPECT_〜のみ記載していますが、いずれのアサーションもASSERT_〜がありますので適宜置き換えてください。

アサーションマクロどのような判定が行われるか備考
EXPECT_TRUE(condition);condition == true
EXPECT_FALSE(condition);condition == false
EXPECT_EQ(val1, val2);val1 == val2std::string比較可能
EXPECT_NE(val1, val2);val1 != val2std::string比較可能
EXPECT_LT(val1, val2);val1 < val2std::string比較可能
EXPECT_LE(val1, val2);val1 <= val2std::string比較可能
EXPECT_GT(val1, val2);val1 > val2std::string比較可能
EXPECT_GE(val1, val2);val1 >= val2std::string比較可能
EXPECT_STREQ(str1, str2);二つの文字列が等しいC文字列用(char*等)
EXPECT_STRNE(str1, str2);二つの文字列が等しくないC文字列用(char*等)
EXPECT_STRCASEEQ(str1, str2);大文字小文字を無視した場合、二つの文字列が等しいC文字列用(char*等)
EXPECT_STRCASENE(str1, str2);大文字小文字を無視した場合、二つの文字列が等しくないC文字列用(char*等)
EXPECT_THROW(func, exception);funcが指定したexceptionを投げる
EXPECT_ANY_THROW(func);funcが何らかの例外を投げる。
EXPECT_NO_THROW(func);funcが一切例外を投げない。
EXPECT_FLOAT_EQ(val1, val2);2つのfloat値がほぼ等しい4 ULPs 以内
EXPECT_DOUBLE_EQ(val1, val2);2つのdouble値がほぼ等しい4 ULPs 以内
EXPECT_NEAR(val1, val2, abs);val1とval2の差がabs以内に収まる
EXPECT_THAT(val, matcher);googlemockのMatcherを使用する正規表現等を比較可能だが、
mockの知識が必要なので応用編で紹介

因みに、EXPECT_EQ(val1, val2);のval1, val2は、val1がexpected(予期する値)、val2がactual(実際の値(=関数の戻り値等))だそうです。

終わりに

今回はgtestの使い方の基本を紹介していきました。
次回(もしくは次次回も?)は応用編でmock等を紹介していきたいと思います。

自動試験さえ用意しておけば、リファクタリングも怖くないので、是非みなさんもgtestを使いこなしましょう〜

参考

↓gtest日本語ガイド入門編
http://opencv.jp/googletestdocs/primer.html
↓日本語ガイド上級編
http://opencv.jp/googletestdocs/advancedguide.html

コメント

  1. […] Tab 1 のテストケースを参考に、テストコードを作成しました。クラス化されたコード用の google test の書き方はこのサイトを参考にしました。 […]

タイトルとURLをコピーしました