TopC++ 入門 › 実践 › GoogleTest / Catch2

GoogleTest / Catch2 入門 — C++ ユニットテスト

C++ のユニットテストは GoogleTest(GTest)Catch2 が事実上の双璧。GTest は Google 製で豊富な機能、Catch2 はヘッダオンリーで気軽。タブで切り替えながら両方の最短入門を。

GoogleTest
Catch2

GT-1. 最小テスト

math_test.cpp
#include <gtest/gtest.h>
#include "math.h"

TEST(MathTest, Add) {
    EXPECT_EQ(add(2, 3), 5);
    EXPECT_EQ(add(-1, 1), 0);
}

TEST(MathTest, DivZero) {
    EXPECT_THROW(divide(1, 0), std::invalid_argument);
}

// main は不要。GTest 側が提供。

GT-2. 主要マクロ

マクロ意味
EXPECT_EQ(a,b)a==b(失敗しても続行)
ASSERT_EQ(a,b)a==b(失敗で即中断)
EXPECT_TRUE(x) / EXPECT_FALSE(x)boolean
EXPECT_NEAR(a,b,e)浮動小数の誤差許容
EXPECT_THROW(expr, T)例外 T を投げるか
EXPECT_NO_THROW(expr)投げないこと

GT-3. CMake で入れる(FetchContent)

CMakeLists.txt
include(FetchContent)
FetchContent_Declare(googletest
    GIT_REPOSITORY https://github.com/google/googletest.git
    GIT_TAG        v1.14.0)
FetchContent_MakeAvailable(googletest)

enable_testing()
add_executable(math_test math_test.cpp math.cpp)
target_link_libraries(math_test PRIVATE GTest::gtest_main)

include(GoogleTest)
gtest_discover_tests(math_test)
$ cmake -S . -B build && cmake --build build $ ctest --test-dir build --output-on-failure

GT-4. Fixture(共通セットアップ)

fixture.cpp
class DbTest : public ::testing::Test {
protected:
    void SetUp() override     { db.connect("test"); }
    void TearDown() override  { db.close(); }
    Database db;
};

TEST_F(DbTest, Insert) {
    db.insert("alice");
    EXPECT_EQ(db.count(), 1);
}

GT-5. GMock でモック

mock.cpp
#include <gmock/gmock.h>

class MockDb : public IDatabase {
public:
    MOCK_METHOD(bool, insert, (std::string), (override));
    MOCK_METHOD(int, count, (), (const, override));
};

using ::testing::Return;
using ::testing::_;

TEST(Service, HandlesDbFail) {
    MockDb m;
    EXPECT_CALL(m, insert(_)).WillOnce(Return(false));
    UserService svc(m);
    EXPECT_FALSE(svc.register_user("alice"));
}

C2-1. 最小テスト

math_test.cpp
#define CATCH_CONFIG_MAIN
#include <catch2/catch_test_macros.hpp>
#include "math.h"

TEST_CASE("add works", "[math]") {
    REQUIRE(add(2, 3) == 5);
    REQUIRE(add(-1, 1) == 0);
}

TEST_CASE("divide by zero") {
    REQUIRE_THROWS_AS(divide(1, 0), std::invalid_argument);
}

C2-2. 主要マクロ

マクロ意味
REQUIRE(expr)条件満たさなければ中断
CHECK(expr)条件満たさなくても継続
REQUIRE_THROWS_AS(e, T)T を投げるか
REQUIRE_THAT(v, Matcher)matcher を使った柔軟な比較
SECTION(name)テスト内のサブケース

SECTION — BDD スタイル

section.cpp
TEST_CASE("vector basic") {
    std::vector<int> v{1,2,3};

    SECTION("size is 3") { REQUIRE(v.size() == 3); }
    SECTION("push_back") {
        v.push_back(4);
        REQUIRE(v.back() == 4);
    }
}
// SECTION ごとに v が再初期化される

C2-3. CMake で入れる

CMakeLists.txt
include(FetchContent)
FetchContent_Declare(Catch2
    GIT_REPOSITORY https://github.com/catchorg/Catch2.git
    GIT_TAG        v3.5.2)
FetchContent_MakeAvailable(Catch2)

add_executable(tests math_test.cpp)
target_link_libraries(tests PRIVATE Catch2::Catch2WithMain)

include(CTest)
include(Catch)
catch_discover_tests(tests)

どちらを選ぶか?

GoogleTestCatch2
導入CMake 経由ヘッダオンリー可
モックGMock 同梱trompeloeil などを追加
学習コストやや多い少ない
パラメータ化◎ 機能豊富◯ GENERATE
出力標準的色付きで見やすい
判断基準: 「Google 系エコシステム(gRPC, protobuf, abseil)」なら GTest、小規模・個人プロジェクト・BDD 志向なら Catch2。どちらも十分実用的。