Communitygithub.com

C++ 테스트

C++ 테스트 작성/수정/수정, GoogleTest/CTest 설정, 실패 또는 불안정한 테스트 진단, 커버리지/새니타이저 추가 시에만 사용합니다.

C++ 테스트란 무엇인가요?

이 스킬은 GoogleTest/GoogleMock과 CMake/CTest를 사용하는 최신 C++(C++17/20) 프로젝트를 위한 에이전트 기반 테스트 워크플로우를 제공합니다. 개발자가 TDD(레드-그린-리팩터) 사이클을 따르도록 안내하며, 단위 테스트 및 통합 테스트 작성을 위한 모범 사례, 픽스처, 목 객체를 포함합니다. 또한 CTest를 사용한 테스트 발견 및 실행, AddressSanitizer(ASan), UndefinedBehaviorSanitizer(UBSan), ThreadSanitizer(TSan)와 같은 새니타이저 활성화, GCC/Clang을 사용한 코드 커버리지 측정 방법을 다룹니다. 불안정한 테스트 방지, 일반적인 함정, 퍼징 및 속성 기반 테스트와 같은 고급 주제에 대한 지침을 제공합니다. 지원 플랫폼: CMake 기반 C++ 프로젝트 (Claude Code, Cursor, Codex 등 AI 코딩 에이전트에 적합).

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/ECC/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); // 프로덕션 코드에서 제공.

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

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

// REFACTOR: 테스트 통과 후 단순화/이름 변경

코드 예제

기본 단위 테스트 (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 "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); // 프로젝트 함수
    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.

관련 스킬