Communitygithub.com

C++ テストスキル

GoogleTest/CTest を使用した C++ テストの作成、修正、診断、カバレッジ/サニタイザーの追加に特化したエージェントスキルです。

C++ テストスキル とは?

このスキルは、AIエージェント(Claude Code, Cursor, Codex など)が最新の C++ (C++17/20) プロジェクトにおいて、GoogleTest/GoogleMock と CMake/CTest を用いたテスト駆動開発(TDD)を効率的に実行するための完全なワークフローを提供します。新しい単体テストや統合テストの作成、既存テストの修正、テスト失敗やフレーキーなテストの診断、カバレッジの計測、サニタイザー(AddressSanitizer, UndefinedBehaviorSanitizer, ThreadSanitizer)の導入までをカバーします。RED→GREEN→REFACTOR の TDD ループに従い、依存性注入とモック/フェイクの適切な使い分けを推奨。CMakeLists.txt の設定例、gtest のフィクスチャ、gmock を使ったモック、CTest によるテスト実行、カバレッジレポートの生成方法など、実践的なコードスニペットとベストプラクティスが豊富に含まれており、エージェントが自律的に高品質な C++ テストインフラを構築・保守できるように設計されています。

対応~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/tree/main/skills/cpp-testing

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

C++ テスト(エージェントスキル)

GoogleTest/GoogleMock と CMake/CTest を使用した、最新 C++(C++17/20)向けのエージェント特化型テストワークフロー。

使用するタイミング

  • 新しい C++ テストを作成する、または既存のテストを修正する場合
  • C++ コンポーネントの単体/結合テストカバレッジを設計する場合
  • テストカバレッジ、CI ゲーティング、またはリグレッション保護を追加する場合
  • 一貫した実行のための CMake/CTest ワークフローを設定する場合
  • テストの失敗やフレーキーな動作を調査する場合
  • メモリ/競合診断用のサニタイザーを有効にする場合

使用すべきでないタイミング

  • テスト変更を伴わない新しいプロダクト機能の実装
  • テストカバレッジや失敗に関係のない大規模リファクタリング
  • テストリグレッションで検証しないパフォーマンスチューニング
  • C++ 以外のプロジェクト、またはテスト以外のタスク

コアコンセプト

  • TDD ループ: レッド → グリーン → リファクタ(テストファースト、最小の修正、その後クリーンアップ)。
  • 分離: グローバル状態よりも依存性注入とフェイクを優先。
  • テストレイアウト: tests/unit、tests/integration、tests/testdata。
  • モック vs フェイク: モックはインタラクション用、フェイクはステートフルな振る舞い用。
  • CTest ディスカバリ: 安定したテスト発見には gtest_discover_tests() を使用。
  • CI シグナル: 最初にサブセットを実行し、その後 --output-on-failure 付きでフルスイートを実行。

TDD ワークフロー

RED → GREEN → REFACTOR ループに従ってください:

  1. RED: 新しい振る舞いを捉える失敗するテストを書く
  2. GREEN: テストを通過させる最小の変更を実装する
  3. REFACTOR: テストがグリーンのままクリーンアップする
// tests/add_test.cpp
#include <gtest/gtest.h>

int Add(int a, int b); // Provided by production code.

TEST(AddTest, AddsTwoNumbers) { // RED
  EXPECT_EQ(Add(2, 3), 5);
}

// src/add.cpp
int Add(int a, int b) { // GREEN
  return a + b;
}

// REFACTOR: simplify/rename once tests pass

コード例

基本的な単体テスト(gtest)

// tests/calculator_test.cpp
#include <gtest/gtest.h>

int Add(int a, int b); // Provided by production code.

TEST(CalculatorTest, AddsTwoNumbers) {
    EXPECT_EQ(Add(2, 3), 5);
}

フィクスチャ(gtest)

// tests/user_store_test.cpp
// Pseudocode stub: replace UserStore/User with project types.
#include <gtest/gtest.h>
#include <memory>
#include <optional>
#include <string>

struct User { std::string name; };
class UserStore {
public:
    explicit UserStore(std::string /*path*/) {}
    void Seed(std::initializer_list<User> /*users*/) {}
    std::optional<User> Find(const std::string &/*name*/) { return User{"alice"}; }
};

class UserStoreTest : public ::testing::Test {
protected:
    void SetUp() override {
        store = std::make_unique<UserStore>(":memory:");
        store->Seed({{"alice"}, {"bob"}});
    }

    std::unique_ptr<UserStore> store;
};

TEST_F(UserStoreTest, FindsExistingUser) {
    auto user = store->Find("alice");
    ASSERT_TRUE(user.has_value());
    EXPECT_EQ(user->name, "alice");
}

モック(gmock)

// tests/notifier_test.cpp
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <string>

class Notifier {
public:
    virtual ~Notifier() = default;
    virtual void Send(const std::string &message) = 0;
};

class MockNotifier : public Notifier {
public:
    MOCK_METHOD(void, Send, (const std::string &message), (override));
};

class Service {
public:
    explicit Service(Notifier &notifier) : notifier_(notifier) {}
    void Publish(const std::string &message) { notifier_.Send(message); }

private:
    Notifier &notifier_;
};

TEST(ServiceTest, SendsNotifications) {
    MockNotifier notifier;
    Service service(notifier);

    EXPECT_CALL(notifier, Send("hello")).Times(1);
    service.Publish("hello");
}

CMake/CTest クイックスタート

# CMakeLists.txt (excerpt)
cmake_minimum_required(VERSION 3.20)
project(example LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

include(FetchContent)
# Prefer project-locked versions. If using a tag, use a pinned version per project policy.
set(GTEST_VERSION v1.17.0) # Adjust to project policy.
FetchContent_Declare(
  googletest
  # Google Test framework (official repository)
  URL https://github.com/google/googletest/archive/refs/tags/${GTEST_VERSION}.zip
)
FetchContent_MakeAvailable(googletest)

add_executable(example_tests
  tests/calculator_test.cpp
  src/calculator.cpp
)
target_link_libraries(example_tests GTest::gtest GTest::gmock GTest::gtest_main)

enable_testing()
include(GoogleTest)
gtest_discover_tests(example_tests)
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
cmake --build build -j
ctest --test-dir build --output-on-failure

テストの実行

ctest --test-dir build --output-on-failure
ctest --test-dir build -R ClampTest
ctest --test-dir build -R "UserStoreTest.*" --output-on-failure
./build/example_tests --gtest_filter=ClampTest.*
./build/example_tests --gtest_filter=UserStoreTest.FindsExistingUser

失敗のデバッグ

  1. gtest フィルターを使って失敗した単一テストを再実行する。
  2. 失敗したアサーションの周りにスコープ付きログを追加する。
  3. サニタイザーを有効にして再実行する。
  4. 根本原因が特定できたらフルスイートに拡張する。

カバレッジ

グローバルフラグではなく、ターゲットレベルの設定を推奨。

option(ENABLE_COVERAGE "Enable coverage flags" OFF)

if(ENABLE_COVERAGE)
  if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
    target_compile_options(example_tests PRIVATE --coverage)
    target_link_options(example_tests PRIVATE --coverage)
  elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
    target_compile_options(example_tests PRIVATE -fprofile-instr-generate -fcoverage-mapping)
    target_link_options(example_tests PRIVATE -fprofile-instr-generate)
  endif()
endif()

GCC + gcov + lcov:

cmake -S . -B build-cov -DENABLE_COVERAGE=ON
cmake --build build-cov -j
ctest --test-dir build-cov
lcov --capture --directory build-cov --output-file coverage.info
lcov --remove coverage.info '/usr/*' --output-file coverage.info
genhtml coverage.info --output-directory coverage

Clang + llvm-cov:

cmake -S . -B build-llvm -DENABLE_COVERAGE=ON -DCMAKE_CXX_COMPILER=clang++
cmake --build build-llvm -j
LLVM_PROFILE_FILE="build-llvm/default.profraw" ctest --test-dir build-llvm
llvm-profdata merge -sparse build-llvm/default.profraw -o build-llvm/default.profdata
llvm-cov report build-llvm/example_tests -instr-profile=build-llvm/default.profdata

サニタイザー

option(ENABLE_ASAN "Enable AddressSanitizer" OFF)
option(ENABLE_UBSAN "Enable UndefinedBehaviorSanitizer" OFF)
option(ENABLE_TSAN "Enable ThreadSanitizer" OFF)

if(ENABLE_ASAN)
  add_compile_options(-fsanitize=address -fno-omit-frame-pointer)
  add_link_options(-fsanitize=address)
endif()
if(ENABLE_UBSAN)
  add_compile_options(-fsanitize=undefined -fno-omit-frame-pointer)
  add_link_options(-fsanitize=undefined)
endif()
if(ENABLE_TSAN)
  add_compile_options(-fsanitize=thread)
  add_link_options(-fsanitize=thread)
endif()

フレーキーテストのガードレール

  • 同期に sleep を使用しないでください。条件変数またはラッチを使用してください。
  • 一時ディレクトリはテストごとに一意にし、常にクリーンアップしてください。
  • 単体テストでは実時間、ネットワーク、ファイルシステムの依存を避けてください。
  • ランダム入力には決定論的なシードを使用してください。

ベストプラクティス

推奨事項

  • テストは決定論的かつ分離された状態に保つ
  • グローバル変数よりも依存性注入を優先する
  • 前提条件には ASSERT_*、複数チェックには EXPECT_* を使用する
  • 単体テストと結合テストを CTest ラベルまたはディレクトリで分離する
  • CI でサニタイザーを実行してメモリと競合を検出する

非推奨事項

  • 単体テストで実時間やネットワークに依存しない
  • 条件変数が使える場合に同期に sleep を使用しない
  • 単純な値オブジェクトを過剰にモックしない
  • 重要でないログのために脆弱な文字列マッチングを使用しない

よくある落とし穴

  • 固定の一時パスを使用する → テストごとに一意の一時ディレクトリを生成し、クリーンアップする。
  • ウォールクロック時間に依存する → クロックを注入するか、偽の時間ソースを使用する。
  • フレーキーな並行性テスト → 条件変数/ラッチと制限付き待機を使用する。
  • 隠れたグローバル状態 → フィクスチャでグローバル状態をリセットするか、グローバルを削除する。
  • 過剰なモック → ステートフルな振る舞いにはフェイクを優先し、インタラクションのみをモックする。
  • サニタイザー実行の欠落 → CI に ASan/UBSan/TSan ビルドを追加する。
  • デバッグ専用ビルドでのカバレッジ → カバレッジターゲットが一貫したフラグを使用することを確認する。

オプション付録: ファジング / プロパティベーステスト

プロジェクトがすでに LLVM/libFuzzer またはプロパティテスティングライブラリをサポートしている場合にのみ使用してください。

  • libFuzzer: 最小限の I/O で純粋関数に最適。
  • RapidCheck: 不変条件を検証するプロパティベーステスト。

最小限の libFuzzer ハーネス(疑似コード: ParseConfig を置き換え):

#include <cstddef>
#include <cstdint>
#include <string>

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    std::string input(reinterpret_cast<const char *>(data), size);
    // ParseConfig(input); // project function
    return 0;
}

GoogleTest の代替

  • Catch2: ヘッダオンリー、表現力豊かなマッチャー
  • doctest: 軽量、最小限のコンパイルオーバーヘッド

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

関連スキル