GAIO CLUB

2024年08月05日

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

Google Test
Google Testのカバレジ計測を試してみた
単体テストをする際、対象関数の動作確認のために、その関数が使用する(読む)変数に値を入れておく必要があります。関数の動作結果は前回お話ししたアサーションによって確認しますが、繰り返しテストをする際に異なる値を設定したい時はどうするのでしょうか。また、致命的なエラーが起きた時にテストを中止する方法はあるでしょうか。
今回は、Google Testを使ってテストドライバーを書く時の、そんな話です。

SetUpとTearDown

下は、前回アサーションFAILEDが出ていたソースを手直しして動かしたものです。
Google Testによるテスト結果表示をみると、set-uptear-downという情報が出ています。
[==========] Running 3 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 3 tests from Func32
[ RUN      ] Func32.TEST1
[       OK ] Func32.TEST1 (0 ms)
[ RUN      ] Func32.TEST2
[       OK ] Func32.TEST2 (0 ms)
[ RUN      ] Func32.TEST3
[       OK ] Func32.TEST3 (0 ms)
[----------] 3 tests from Func32 (0 ms total)

[----------] Global test environment tear-down
[==========] 3 tests from 1 test suite ran. (0 ms total)
[  PASSED  ] 3 tests.
FAILEDの時にも出ていた情報なのですが、テストがPASSするように直して見やすくしました。
set-uptear-downの情報は、テストの前処理と後処理の動作を示しますが、テストに必要な前後処理もこれと同じタイミングで行うことができます。

また、この処理は3つのテスト全体の前と後で動作していますが、それぞれのテストの前後で必要な処理をおこなうことも可能です。それを行うためには、::testing::Testクラスの派生クラスを作り、メンバ関数を定義する必要があります。

テストフィクスチャ

マニュアルによると、テストフィクスチャは同じようなデータを扱うテストを複数書く場合に使用し、異なるテストに対して同じオブジェクト設定を再利用できるとあります。クラスに関わるテストを行う際に便利そうです。

テストフィクスチャは ::testing::Test の派生クラスを作り、そのクラス名をテストケース名として使用します。
テストフィクスチャを使用するためにクラスを作り、SetUpとTearDownの動きを確認してみました。
#include <gtest/gtest.h>
#include <stdio.h>
int glb3;

// Test Target : function3_2	// テストターゲット関数
int function3_2(int a){
    if ( a > 0 )
    {
       glb3 = a*a;
       return a;
    }
    else
       return 0;
}

class UnitTest:public::testing::Test{
protected:
    static  void SetUpTestCase()	{ printf("=== SetUpTestCase ======\n"); }
    static  void TearDownTestCase()	{ printf("=== TearDownTestCase ===\n"); }
    virtual void SetUp()	    { printf("=== SetUp ======\n"); glb3=0; }
    virtual void TearDown()	    { printf("=== TearDown ===\n"); }
};

// TEST1
TEST_F(UnitTest, TEST1){	// テストクラス名(UnitTest):テスト名(TEST1)
    EXPECT_LT(0, function3_2(5));
    EXPECT_EQ(5*5, glb3);
}

// TEST2
TEST_F(UnitTest, TEST2){ 	// テストクラス名(UnitTest):テスト名(TEST2)
    EXPECT_LT(0, function3_2(1));
    EXPECT_EQ(1, glb3);
}

// TEST3
TEST_F(UnitTest, TEST3){ 	// テストクラス名(UnitTest):テスト名(TEST3)
    EXPECT_EQ(0, function3_2(-5));
    EXPECT_EQ(0, glb3);
}
緑字の箇所が、::testing::Test の派生クラス定義部分です。
SetUpとTearDownに関係する4つのメンバ関数を定義してあり、動作状況がわかるようにprintf文を入れました。また、テスト毎に行いたい初期化処理、glb3=0; をSetUp関数内に書いてあります。

クラス名(UnitTest)はテストケース名として使用しますが、その時のテストマクロにTEST()ではなく、TEST_F()を使用することでテストフィクスチャを利用することになります。

テスト結果はこちらです。
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 UnitTest
=== SetUpTestCase ======
[ RUN      ] UnitTest.TEST1
=== SetUp ======
=== TearDown ===
[       OK ] UnitTest.TEST1 (0 ms)
[ RUN      ] UnitTest.TEST2
=== SetUp ======
=== TearDown ===
[       OK ] UnitTest.TEST2 (0 ms)
[ RUN      ] UnitTest.TEST3
=== SetUp ======
=== TearDown ===
[       OK ] UnitTest.TEST3 (0 ms)
=== TearDownTestCase ===
[----------] 3 tests from UnitTest (0 ms total)

[----------] Global test environment tear-down
[==========] 3 tests from 1 test suite ran. (0 ms total)
[  PASSED  ] 3 tests.
main関数を削除したので、先頭にlibgtest_main内のmain()が動作した旨の情報が出ています。
テストケースに含まれるテスト全体の前と後に、SetUpTestCaseTearDownTestCaseが動き、各テストの開始・終了時に、SetUpTearDownが動いているのがわかります。

SetUp関数内に記述した初期化処理glb3=0; が各テスト実行前に動くのでテストが正常終了していますが、もしこれがなければ、3番目のテストがFAILEDになったはずでした。
テストフィクスチャ
テスト全体の前処理と後処理にはSetUpTestCaseとTearDownTestCase、各テスト項目共通の前後処理はSetUpとTearDownを使ってできそうですが、各テスト固有の入力値はどのように設定するのでしょうか。

TEST()やTEST_F()のテスト処理内にはアサーションマクロだけでなく、通常のC++言語記述が書けるので、そこで設定することが可能です。

継続と停止

アサーションにはテストを中止させるものもあります。
これまでに使ってきたアサーションはEXPECT_○○()というマクロでしたが、ASSERT_○○()を使用すると、テストに失敗した時にその後のテストを継続せず、このアサーションが書かれたところで終わります。

連続テストを行う際に途中の失敗以降を継続することに意味がない時、例えば、メモリアロックに失敗した時にテストを継続するとプログラムが異常終了してしまうような場合にASSERTを使用する例などが見られます。

また、機能テストを行う際、基本機能がPASSしなければ詳細機能テストの意味がない等の使い分けもできそうです。
継続と停止
今回はGoogle Testのテストフィクスチャ、開始終了処理、EXPECT/ASSERTをご紹介しました。

アサーションの種類はたくさんありますので、詳しくはGoogle Testのマニュアルをご覧になるのが良いでしょう。Google Testはバージョンアップも多いので、アサーションマクロの追加も行われると思います。

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

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

筆者紹介

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

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

開発1部 QTXグループ

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

人気のコラム

最新のコラム