GAIO CLUB

2024年12月02日

Google Mock 3 – Google Testのカバレッジ計測を試してみた #6

Google Test
Google Testのカバレジ計測を試してみた
Google Mock使用例の最後に、C言語プログラムのテストで使ってみようと思います。前回までに使用したプログラムをC言語に書き換え、Google Mock使ってテストします。

C言語記述に変更

メンバ関数のようすを残してC言語プログラムに書き換えてみました。

【AirConditionerController.h】

#ifndef AIR_CONDITIONER_CONTROLLER_H_
#define AIR_CONDITIONER_CONTROLLER_H_

#define MODE_OFF (0)	        // モード:オフ
#define MODE_COOLING (1)	// モード:冷房
#define MODE_HEATING (2)	// モード:暖房

#define COOLING_THRESHOLD (30)	// 冷房をつける基準値(単位:℃)
#define HEATING_THRESHOLD (20)	// 暖房をつける基準値(単位:℃)

extern int Mode;	        // エアコンのモード (オフ・冷房・暖房)

extern void AirConditionerController_Init();	        // 初期化処理
extern void AirConditionerController_AutoMode();	// 自動運転判定
extern int  AirConditionerController_GetMode();		// モード取得
extern int  TemperatureSensor_GetTemperature();         // 温度センサ

#endif // AIR_CONDITIONER_CONTROLLER_H_

【AirConditionerController.c】

#include "AirConditionerController.h"

int Mode;	/* エアコンの運転モード (オフ・冷房・暖房)  */

/* --- 温度センサ --- (モックにする関数) */
extern int TemperatureSensor_GetTemperature();

/* --- 運転モードの初期化処理 --- */
void AirConditionerController_Init()
{
  Mode = MODE_OFF;
}

/* --- 運転モードの判定処理 --- */
void AirConditionerController_AutoMode()
{
  /* 温度の取得 */
  int temperature = TemperatureSensor_GetTemperature();
  
  if (temperature >= COOLING_THRESHOLD) {
      Mode = MODE_COOLING;		/* 冷房運転モードに設定 */
  } else if (temperature <= HEATING_THRESHOLD) {
      Mode = MODE_HEATING;		/* 暖房運転モードに設定 */
  } else {
      Mode = MODE_OFF;		        /* 運転停止モードに設定 */
  } 
  return;
}

/* --- 運転モードの取得 --- */
int AirConditionerController_GetMode()
{
    return Mode;
}
テスト対象関数は、AirConditionerController_AutoMode()です。テスト結果は、Modeの値で確認します。
テスト対象関数が使用する子関数TemperatureSensor_GetTemperature()は未作成という前提で、これをMockとして動かします。

Mock

MockはC++言語で作ります。
// モッククラスの定義
class MockTemperatureSensor {
public:
    // int TemperatureSensor_GetTemperature() のモック定義
    MOCK_METHOD(int , TemperatureSensor_GetTemperature, ());
} *mockTemperatureSensor;

extern "C" {     /* C言語プログラムが呼び出す温度センサ(モック) */
    int TemperatureSensor_GetTemperature()
    {
        return mockTemperatureSensor->TemperatureSensor_GetTemperature();
    };
}
TemperatureSensor_GetTemperature()はC言語から呼べるようにし、この中からモックを呼出すように書いてみました。

テストフィクスチャ

テストフィクスチャもC++言語です。
// テストフィクスチャクラスの定義
class AirConditionerControllerTest : public Test {
protected:
   virtual void SetUp() {	// テスト毎の初期処理
       // 運転モード(Mode変数)の初期化
       AirConditionerController_Init();
       // モッククラス変数のアロック
       mockTemperatureSensor = new MockTemperatureSensor();
   }
   virtual void TearDown() {	// テスト毎の終了処理
       // モッククラス変数の開放
       delete mockTemperatureSensor;
   }
};
テスト毎にSetUp()内でMode変数を初期化し、Mockクラス変数をアロックします。テスト終了時にはTearDown()内で、Mockクラス変数を開放します。

テスト

テストの記述はこれまでのテストと同じです。最初にMockを使用した時と同じ記述にしてみます。
TEST_F(AirConditionerControllerTest, OffModeTest) {
        EXPECT_CALL(*mockTemperatureSensor, TemperatureSensor_GetTemperature())
                .Times(AtLeast(2))       // 呼び出し回数は2回以上
                .WillOnce(Return(29))    // 最初は 29℃ を返す
                .WillOnce(Return(21));   // 2回目は 21℃ を返す

        AirConditionerController_AutoMode();
        EXPECT_EQ(MODE_OFF, AirConditionerController_GetMode());
        AirConditionerController_AutoMode();
        EXPECT_EQ(MODE_OFF, AirConditionerController_GetMode());
    }

    TEST_F(AirConditionerControllerTest, HeattingTest) {
        EXPECT_CALL(*mockTemperatureSensor, TemperatureSensor_GetTemperature())
                .Times(AtLeast(2))       // 呼び出し回数は2回以上
                .WillOnce(Return(20))    // 最初は 20℃ を返す
                .WillOnce(Return(19));   // 2回目は 19℃ を返す

        AirConditionerController_AutoMode();
        EXPECT_EQ(MODE_HEATING, AirConditionerController_GetMode());
        AirConditionerController_AutoMode();
        EXPECT_EQ(MODE_HEATING, AirConditionerController_GetMode());
    }

    TEST_F(AirConditionerControllerTest, CoolingTest) {
        EXPECT_CALL(*mockTemperatureSensor, TemperatureSensor_GetTemperature())
                .Times(AtLeast(2))       // 呼び出し回数は2回以上
                .WillOnce(Return(30))    // 最初は 30℃ を返す
                .WillOnce(Return(31));   // 2回目は 31℃ を返す

        AirConditionerController_AutoMode();
        EXPECT_EQ(MODE_COOLING, AirConditionerController_GetMode());
        AirConditionerController_AutoMode();
        EXPECT_EQ(MODE_COOLING, AirConditionerController_GetMode());
    }
テスト結果です。
Running main() from /usr/local/src/googletest-1.14.0/googletest/src/gtest_main.cc
[==========] Running 3 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 3 tests from AirConditionerControllerTest
[ RUN      ] AirConditionerControllerTest.OffModeTest
[       OK ] AirConditionerControllerTest.OffModeTest (0 ms)
[ RUN      ] AirConditionerControllerTest.HeattingTest
[       OK ] AirConditionerControllerTest.HeattingTest (0 ms)
[ RUN      ] AirConditionerControllerTest.CoolingTest
[       OK ] AirConditionerControllerTest.CoolingTest (0 ms)
[----------] 3 tests from AirConditionerControllerTest (0 ms total)

[----------] Global test environment tear-down
[==========] 3 tests from 1 test suite ran. (0 ms total)
[  PASSED  ] 3 tests.
GoogleTestを使用する際、テストドライバーやモックはC++言語で書くことになりますが、C言語関数のテストで使用する場合、なんらかの工夫が必要になります。ここでご紹介した例も一つの方法として見て頂ければと思います。

本コラムで使用したソースプログラム・コマンドファイル・ログは以下にあります(ソースプログラム中のコメントは全く同じではありません)。

Google Test資産を活かした車載品質テストの効率化を実現
「QTE(Quality Town for Embedded grade)」

「QTE」は、ユーザ環境で作成したGoogleTest資産を活用し、機能安全(ISO 26262)で求められるマイコンターゲットオブジェクト実行とカバレッジ計測が可能です。また、テストエビデンス及びレポートを自動出力し、テストエビデンスの作成も効率化します。

筆者紹介

浅野 昌尚(あさの まさなお)

ガイオ・テクノロジー株式会社

開発1部 QTXグループ

1980年代から30年以上にわたり汎用構造のCコンパイラ開発に従事し、その間に8ビットマイコンからRISC・VLIW・画像処理プロセッサまで、さまざまなCPU向けのクロスCコンパイラを開発。

人気のコラム

最新のコラム