1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GoogleTest導入記録

Last updated at Posted at 2024-12-30

目的

  1. 作成したC++プログラムのテストを行う
  2. GoogleTestの練習
  3. 共有ライブラリを使う練習

環境

  • M1 MacBook Air Sonoma 14.7.1
  • Homebrew 4.4.13
  • GCC 14.2.0_1
  • cmake 3.31.3
  • GoogleTest stable 1.15.2

手順

GoogleTestのinstall

Homebrewでinstallする。GitHubからクローンしてcmakeでビルドする方法もあり。

$ brew install googletest

installされたか確認。

$ ls -l /opt/homebrew/include | grep googletest
lrwxr-xr-x   1 user  admin    41 Dec 30 12:32 gmock -> ../Cellar/googletest/1.15.2/include/gmock
lrwxr-xr-x   1 user  admin    46 Dec 30 12:32 googlemock -> ../Cellar/googletest/1.15.2/include/googlemock
lrwxr-xr-x   1 user  admin    46 Dec 30 12:32 googletest -> ../Cellar/googletest/1.15.2/include/googletest
lrwxr-xr-x   1 user  admin    41 Dec 30 12:32 gtest -> ../Cellar/googletest/1.15.2/include/gtest

基本的なTestの実行方法

  1. TEST() マクロを使って、テスト関数の定義と命名を行う
  2. テスト関数の中で、任意の有効なC++ステートメントをincludeし、GoogleTestのアサーションで動作を確認する
  3. テスト結果は、アサーションによって決まる。どれか一つでもアサーションが失敗すると、テスト全体が止まる

TEST() マクロの基本的な使い方は、以下。

TEST(TestSuiteName, TestName) {
  ... test body ...
}

TestSuiteName: あるテストのまとまりの名前
TestName: そのテストの名前

GoogleTestは、関連するテストスイートごとにグループ化するため、関連するテストは同じテストスイートにする。使用可能アサーションは、下のリンクに一覧されている。

GoogleTest アサーションまとめ (引数と使用例付き)

アサーション 説明 引数 使用例 便利な場面
EXPECT_TRUE 条件が真であることを検証する。 condition: 真偽値を返す式 EXPECT_TRUE(x > 5); 条件式の評価結果がテストの成否を決定する場合。
EXPECT_FALSE 条件が偽であることを検証する。 condition: 真偽値を返す式 EXPECT_FALSE(y == 0); 条件式の評価結果がテストの成否を決定する場合。
EXPECT_EQ 2つの値が等しいことを検証する。 val1, val2: 比較する2つの値 EXPECT_EQ(actual, expected); 変数の値が期待値と等しいかどうかを比較する場合。
EXPECT_NE 2つの値が等しくないことを検証する。 val1, val2: 比較する2つの値 EXPECT_NE(result, error_code); 変数の値が特定のエラーコードと異なるかどうかを比較する場合。
EXPECT_LT ある値が別の値より小さいことを検証する。 val1, val2: 比較する2つの値 EXPECT_LT(a, b); 変数の大小関係(より小さい)を比較する場合。
EXPECT_LE ある値が別の値以下であることを検証する。 val1, val2: 比較する2つの値 EXPECT_LE(count, max_count); 変数の大小関係(以下)を比較する場合。
EXPECT_GT ある値が別の値より大きいことを検証する。 val1, val2: 比較する2つの値 EXPECT_GT(size, 0); 変数の大小関係(より大きい)を比較する場合。
EXPECT_GE ある値が別の値以上であることを検証する。 val1, val2: 比較する2つの値 EXPECT_GE(age, 18); 変数の大小関係(以上)を比較する場合。
EXPECT_STREQ 2つのC文字列の内容が同じであることを検証する。 str1, str2: 比較するC文字列 EXPECT_STREQ("hello", actual_string); C文字列の内容を比較する場合。
EXPECT_STRNE 2つのC文字列の内容が異なることを検証する。 str1, str2: 比較するC文字列 EXPECT_STRNE("goodbye", input); C文字列の内容が特定の値と異なるかどうかを比較する場合。

補足:

  • ASSERT_ で始まるアサーションは、失敗した場合にテスト関数を即座に中断する。EXPECT_ で始まるアサーションは、失敗してもテスト関数は続行される
  • これらのアサーションは、単体テストにおいて、コードの挙動が期待通りかどうかを検証するために使用される
  • 引数の型が一致しない場合、コンパイルエラーが発生する
  • 浮動小数点数の比較には、EXPECT_FLOAT_EQEXPECT_DOUBLE_EQEXPECT_NEAR など、より適切なアサーションが用意されている。これは、浮動小数点数の演算誤差を考慮するため

GoogleTestの公式サンプルを試す

このリンクにSampleが乗っていたので、試しに実行する。下のコードは、Googleのサンプルコードを一部改変したものである。BSDライセンスなので、本記事への記載は問題ないと思われる。オリジナルテストコードの著作権は、Google Inc.に帰属する。

sample1.hpp

#pragma once

// 階乗の計算
int Factorial(int n);

// 素数判定
bool IsPrime(int n);

sample1.cpp

#include "sample1.hpp"

// 階乗の計算
int Factorial(int n)
{
    int result = 1;
    for (int i = 1; i <= n; i++)
    {
        result *= i;
    }
    return result;
}

// 素数判定
bool IsPrime(int n)
{
    // 1を除外
    if (n <= 1)
        return false;

    // 偶数のうち2だけ素数
    if (n % 2 == 0)
        return n == 2;

    // 3以降
    for (int i = 3;; i += 2)
    {
        // nの平方根だけの回数実行
        if (i > n / i)
            break;

        // 合致する値があれば、素数でない
        if (n % i == 0)
            return false;
    }

    return true;
}

階乗の計算と素数判定のシンプルなプログラム。次に、このプログラムに対するテストコードを作成する。(TDDがお好きな方は、こちらから先に書いても良いかもしれない)。

#include "sample1.hpp"
#include <limits.h>

#include <gtest/gtest.h>

TEST(FactorialTest, Negative)
{
    // This test is named "Negative", and belongs to the "FactorialTest"
    // test case.
    EXPECT_EQ(1, Factorial(-5));
    EXPECT_EQ(1, Factorial(-1));
    EXPECT_GT(Factorial(-10), 0);
}

// Tests factorial of 0.
TEST(FactorialTest, Zero) { EXPECT_EQ(1, Factorial(0)); }

// Tests factorial of positive numbers.
TEST(FactorialTest, Positive)
{
    EXPECT_EQ(1, Factorial(1));
    EXPECT_EQ(2, Factorial(2));
    EXPECT_EQ(6, Factorial(3));
    EXPECT_EQ(40320, Factorial(8));
}

// Tests IsPrime()

// Tests negative input.
TEST(IsPrimeTest, Negative)
{
    // This test belongs to the IsPrimeTest test case.

    EXPECT_FALSE(IsPrime(-1));
    EXPECT_FALSE(IsPrime(-2));
    EXPECT_FALSE(IsPrime(INT_MIN));
}

// Tests some trivial cases.
TEST(IsPrimeTest, Trivial)
{
    EXPECT_FALSE(IsPrime(0));
    EXPECT_FALSE(IsPrime(1));
    EXPECT_TRUE(IsPrime(2));
    EXPECT_TRUE(IsPrime(3));
}

// Tests positive input.
TEST(IsPrimeTest, Positive)
{
    EXPECT_FALSE(IsPrime(4));
    EXPECT_TRUE(IsPrime(5));
    EXPECT_FALSE(IsPrime(6));
    EXPECT_TRUE(IsPrime(23));
}

main.cpp

#include <gtest/gtest.h>
#include "sample1.hpp"

int main(int argc, char **argv)
{
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

このmain関数で、テストを実行する。最終的なファイル構成は、以下のようになった。

├── CMakeLists.txt
├── main.cpp
├── sample1.cpp
├── sample1.hpp
└── sample1_unittest.cpp

CMakeLists.txtの作成

# CMakeのバージョン設定
cmake_minimum_required(VERSION 3.13)

# C++のバージョン設定
set(CMAKE_CXX_STANDARD 14)

# プロジェクト名
project(gtest_practice)

# googletestをひもづける
find_package(GTest REQUIRED)

# テスト用の実行ファイルを作成
add_executable(
    ${PROJECT_NAME}_tests
    main.cpp
    sample1.cpp
    sample1_unittest.cpp
)

# googletestをリンク
target_link_libraries(
    ${PROJECT_NAME}_tests
    PRIVATE
    GTest::gtest
)
cmake -S . -B build
cmake --build build

結果

$ ./gtest_practice_tests 
[==========] Running 6 tests from 2 test suites.
[----------] Global test environment set-up.
[----------] 3 tests from FactorialTest
[ RUN      ] FactorialTest.Negative
[       OK ] FactorialTest.Negative (0 ms)
[ RUN      ] FactorialTest.Zero
[       OK ] FactorialTest.Zero (0 ms)
[ RUN      ] FactorialTest.Positive
[       OK ] FactorialTest.Positive (0 ms)
[----------] 3 tests from FactorialTest (0 ms total)

[----------] 3 tests from IsPrimeTest
[ RUN      ] IsPrimeTest.Negative
[       OK ] IsPrimeTest.Negative (0 ms)
[ RUN      ] IsPrimeTest.Trivial
[       OK ] IsPrimeTest.Trivial (0 ms)
[ RUN      ] IsPrimeTest.Positive
[       OK ] IsPrimeTest.Positive (0 ms)
[----------] 3 tests from IsPrimeTest (0 ms total)

[----------] Global test environment tear-down
[==========] 6 tests from 2 test suites ran. (0 ms total)
[  PASSED  ] 6 tests.

その他の調べ物

C言語標準ライブラリ・limits.h

#include <limits.h>

ヘッダー では、標準的な整数型のさまざまな限界値やパラメータに展開するマクロがいくつか定義されています。標準的な整数型のさまざまな制限やパラメータに展開するいくつかのマクロを定義しています。
フリースタンディング環境で使える標準ライブラリの1つです。

色々な変数の限界値や大きさをまとめたマクロ。標準ライブラリの一つ。

参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?