Communitygithub.com

C++ 测试

仅用于编写/更新/修复 C++ 测试、配置 GoogleTest/CTest、诊断失败或不稳定的测试,或添加覆盖率/消毒器。

C++ 测试 是什么?

此技能为 AI 代理提供了一个专注于 C++ 测试的工作流程,主要针对现代 C++(C++17/20),使用 GoogleTest/GoogleMock 框架和 CMake/CTest 构建系统。它涵盖了完整的测试生命周期:从使用 TDD(红-绿-重构)循环编写新测试,到诊断和修复失败或不稳定的测试,以及配置覆盖率分析和消毒器(如 AddressSanitizer、UndefinedBehaviorSanitizer)。该技能支持单元测试、集成测试、模拟(Mock)和固件(Fixture),并提供了详细的 CMake 配置示例和命令行运行指令。它遵循严格的测试最佳实践,强调测试的确定性、隔离性和可重复性,并明确指出了应避免的常见陷阱,如使用固定临时路径、依赖实际时间或过度模拟。该技能还包含可选的模糊测试和属性测试附录,适用于已支持 LLVM/libFuzzer 或 RapidCheck 的项目。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/ECC/tree/main/skills/cpp-testing

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

C++ 测试(代理技能)

面向代理的现代 C++(C++17/20)测试工作流,使用 GoogleTest/GoogleMock 和 CMake/CTest。

何时使用

  • 编写新的 C++ 测试或修复现有测试
  • 为 C++ 组件设计单元/集成测试覆盖率
  • 添加测试覆盖率、CI 门控或回归保护
  • 配置 CMake/CTest 工作流以实现一致的执行
  • 调查测试失败或不稳定行为
  • 启用消毒器进行内存/竞争诊断

何时不使用

  • 实现没有测试变更的新产品功能
  • 与测试覆盖率或失败无关的大规模重构
  • 没有测试回归验证的性能调优
  • 非 C++ 项目或非测试任务

核心概念

  • TDD 循环:红→绿→重构(先测试,最小修复,然后清理)。
  • 隔离:优先使用依赖注入和伪造对象,而非全局状态。
  • 测试布局:tests/unit、tests/integration、tests/testdata。
  • 模拟 vs 伪造:模拟用于交互,伪造用于有状态行为。
  • CTest 发现:使用 gtest_discover_tests() 实现稳定的测试发现。
  • CI 信号:先运行子集,再运行带 --output-on-failure 的完整套件。

TDD 工作流

遵循红→绿→重构循环:

  1. 红:编写一个捕获新行为的失败测试
  2. 绿:实现最小的更改以通过
  3. 重构:在测试保持绿色的情况下进行清理
// tests/add_test.cpp
#include <gtest/gtest.h>

int Add(int a, int b); // 由生产代码提供。

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

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

// 重构:测试通过后简化/重命名

代码示例

基本单元测试(gtest)

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

int Add(int a, int b); // 由生产代码提供。

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

固件(gtest)

// tests/user_store_test.cpp
// 伪代码存根:将 UserStore/User 替换为项目类型。
#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(节选)
cmake_minimum_required(VERSION 3.20)
project(example LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

include(FetchContent)
# 优先使用项目锁定的版本。如果使用标签,请根据项目策略锁定版本。
set(GTEST_VERSION v1.17.0) # 根据项目策略调整。
FetchContent_Declare(
  googletest
  # Google Test 框架(官方仓库)
  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 "启用覆盖率标志" 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 "启用 AddressSanitizer" OFF)
option(ENABLE_UBSAN "启用 UndefinedBehaviorSanitizer" OFF)
option(ENABLE_TSAN "启用 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:最适合纯函数且输入输出最小。
  • 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); // 项目函数
    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/content-engine

Create platform-native content systems for X, LinkedIn, TikTok, YouTube, newsletters, and repurposed multi-platform campaigns. Use when the user wants social posts, threads, scripts, content calendars, or one source asset adapted cleanly across platforms.

affaan-m/ECC

Multi-platform content distribution across X, LinkedIn, Threads, and Bluesky. Adapts content per platform using content-engine patterns. Never posts identical content cross-platform. Use when the user wants to distribute content across social platforms.

affaan-m/fal-ai-media

Unified media generation via fal.ai MCP — image, video, and audio. Covers text-to-image (Nano Banana), text/image-to-video (Seedance, Kling, Veo 3), text-to-speech (CSM-1B), and video-to-audio (ThinkSound). Use when the user wants to generate images, videos, or audio with AI.

affaan-m/manim-video

日本語翻訳:このファイルは manim-video 用の日本語翻訳が必要です

affaan-m/remotion-video-creation

Remotion のベストプラクティス - React で動画を作成する。3D、アニメーション、音声、字幕、チャート、トランジションなどをカバーするドメイン固有の29のルール。

affaan-m/video-editing

AI-assisted video editing workflows for cutting, structuring, and augmenting real footage. Covers the full pipeline from raw capture through FFmpeg, Remotion, ElevenLabs, fal.ai, and final polish in Descript or CapCut. Use when the user wants to edit video, cut footage, create vlogs, or build video content.

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.

agent-self-evaluation

Use after completing any non-trivial task. The agent self-rates its output on 5 axes — accuracy, completeness, clarity, actionability, conciseness — with concrete evidence per criterion. Produces a structured 1-5 scorecard with specific improvement suggestions.

agent-sort

Build an evidence-backed ECC install plan for a specific repo by sorting skills, commands, rules, hooks, and extras into DAILY vs LIBRARY buckets using parallel repo-aware review passes. Use when ECC should be trimmed to what a project actually needs instead of loading the full bundle.

ai-first-engineering

Engineering operating model for teams where AI agents generate a large share of implementation output. Use when setting team process, review gates, or ownership rules for a codebase largely written by agents.

ai-regression-testing

Regression testing strategies for AI-assisted development. Sandbox-mode API testing without database dependencies, automated bug-check workflows, and patterns to catch AI blind spots where the same model writes and reviews code. Use when adding regression coverage to AI-assisted code, or when the same model both wrote and reviewed a change.

android-clean-architecture

Clean Architecture patterns for Android and Kotlin Multiplatform projects — module structure, dependency rules, UseCases, Repositories, and data layer patterns. Use when structuring modules, layers, or data flow in an Android or KMP project.

angular-developer

Generates Angular code and provides architectural guidance. Trigger when creating projects, components, or services, or for best practices on reactivity (signals, linkedSignal, resource), forms, dependency injection, routing, SSR, accessibility (ARIA), animations, styling (component styles, Tailwind CSS), testing, or CLI tooling.

相关技能