📝

GoogleTestの書き方(初心者向け)

2020/09/27に公開

※この記事は、Qiitaに投稿した記事を一部変更したものです。
https://qiita.com/kunosu/items/0f0f063fff189482a97e


こんな人向け

  • 仕事でGoogleTest/GoogleMockを使うことになったが使ったことがない
  • GoogleTest自体の導入はすでに済んでいる
  • テスト対象はC言語で書かれている

テストコードの全体像

GoogleTestはC++で動く。
Cで実装したコードはCの部分を「extern "C"」で囲めば試験可能。

全体はこんな感じ

  1. インクルード
    • 試験対象が動くのに必要なヘッダファイルもインクルード
  2. モッククラスの宣言
  3. テストフィクスチャクラス
  4. テストケース1
  5. テストケース2
  6. ...
  7. テストケースn

今回は以下の関数に対するテストコードを例にする。

int func(int a, b) {
	if (0 < sub_func(a)) {
		return a + b;
	} else {
		return a - b;
	}
}

ここで、サブ関数sub_func()はまだ未作成。
ただし、I/Oは決まっている。

// プロトタイプ宣言
int sub_func(int a);

また、組込みだと開発対象の機械専用の関数(メーカーが独自に用意した関数など)もある。

モッククラスの宣言

まずはサブ関数の代わりに動くモックを作成。

// モッククラスの宣言
class TestMock {
public:
	// MOCK_METHODn(関数名, 戻り値の型(引数1, 引数2, ...))
	// nは引数の数
	MOCK_METHOD1(sub_func, int(int a));
} *testMock;

// モック化したい関数を書く
int sub_func(int a) {
	return testMock->sub_func(a);
}

テストフィクスチャクラスの定義

ここでは試験で使うクラス、及び共有リソース(配列など)の定義、初期化を行う。

毎回動作が決まっているモックもここで動作を定義する。

// テストフィクスチャクラスの定義
class FuncTest : public Test {
	protected:
		// 試験開始時に一回だけ実行
		static void SetUpTestCase() {
		}

		// 試験終了時に一回だけ実行
		static void TearDownTestCase() {
		}

		// 各テストケース実行前に実行
		virtual void SetUp() {
			testMock = new TestMock();
		}

		// 各テストケース実行後に実行
		virtual void SetUp() {
			delete testMock;
		}

		// 試験対象の引数などを宣言
		int a;
		int b;
		int ans;
};

テストケース

ここで一つ一つのテストケースを記述。

// 使うGoogleMockの名前をインポート
using ::testing::Return;
using ::testing::_;

// TEST_F(テストフィクスチャクラス名, テストケース名)
TEST_F(FuncTest, sample1) {
	// パラメータを設定
	a = 1;
	b = 2;

	// sub_func呼び出し時、常に0を返すように設定
	EXPECT_CALL(*testMock, sub_func(_)).WillRepeatedly(Return(0));

	// 試験対象呼び出し
	ans = func(a, b);

	// 戻り値が期待するものか確認
	EXPECT_EQ(3, ans);
}

モックの動作を指定

EXPECT_CALL() で指定する。
引数は2つで、1つ目がモックを作成したときのモッククラス、2つ目で実際に呼び出される関数名とその引数を指定する。
例のように "_" にすると任意の値になる。

EXPECT_CALL(*testMock, sub_func(_)).WillRepeatedly(Return(0));

戻り値は WillRepeatedly(Return(...))Return() の引数として記載。

呼び出し回数の指定

引数、戻り値の指定だけでなく、.Time(1) を追加して呼び出し回数も設定可能。
「この関数は呼び出されないことを試験したい」場合は呼び出し回数0にすればOK。

// 3回呼び出されることを期待
EXPECT_CALL(*testMock, sub_func(_)).Times(3).WillRepeatedly(Return(0));

呼び出されるたびに異なる値を返す

  • WillRepeatedly(Return(x)): 呼び出されるたびに x を返す
  • WillOnce(Return(x)) :1回だけ x を返す
// 1回目は0、2回目は1、3回目は2を返す
EXPECT_CALL(*testMock, sub_func(_))
	.WillOnce(Return(0)).WillOnce(Return(1)).WillOnce(Return(2));

スタブを動かす

同じテストコード内にスタブを作成。

int stb_sub_func(int a) {
  // テストで動かすのに十分な処理を記載(引数チェックとか)
}

Invoke でスタブを指定するとサブ関数呼び出し時にスタブを代わりに実行。

// stb_sub_func()を実行
EXPECT_CALL(*testMock, sub_func(_)).WillRepeatedly(Invoke(stb_sub_func));

戻り値などを比較

アサーションを使用。

成功条件(flg の値) コード
true EXPECT_TRUE(flg)
false EXPECT_FALSE(flg)

2つの値を比較する

成功条件 コード
a == b EXPECT_EQ(a, b)
a != b EXPECT_NE(a, b)
a < b EXPECT_LT(a, b)
a <= b EXPECT_LE(a, b)
a > b EXPECT_GT(a, b)
a => b EXPECT_GE(a, b)

参考:GoogleTestの公式サイト

Discussion