
关于
仅在编写/更新/修复 C++ 测试、配置 GoogleTest/CTest、诊断失败或不稳定测试,或添加覆盖率/Sanitizer 时使用。
name: cpp-testing description: 仅在编写/更新/修复 C++ 测试、配置 GoogleTest/CTest、诊断失败或不稳定测试、或添加覆盖率/消毒器时使用。 origin: ECC
C++ 测试(Agent 技能)
面向 Agent 的现代 C++(C++17/20)测试工作流,使用 GoogleTest/GoogleMock 配合 CMake/CTest。
何时使用
- 编写新的 C++ 测试或修复现有测试
- 为 C++ 组件设计单元/集成测试覆盖
- 添加测试覆盖、CI 门控或回归保护
- 配置 CMake/CTest 工作流以实现一致执行
- 调查测试失败或不稳定行为
- 启用消毒器进行内存/竞态诊断
不使用的情况
- 实现新产品功能而不涉及测试变更
- 与测试覆盖或失败无关的大规模重构
- 没有测试回归需要验证的性能调优
- 非 C++ 项目或非测试任务
核心概念
- TDD 循环:红 → 绿 → 重构(先写测试,最小修复,然后清理)。
- 隔离:优先使用依赖注入和 fake 而非全局状态。
- 测试布局:
tests/unit、tests/integration、tests/testdata。 - Mock vs Fake:mock 用于交互验证,fake 用于有状态行为。
- CTest 发现:使用
gtest_discover_tests()实现稳定的测试发现。 - CI 信号:先运行子集,然后使用
--output-on-failure运行完整套件。
TDD 工作流
遵循 红 → 绿 → 重构 循环:
- 红:编写一个捕获新行为的失败测试
- 绿:实现通过测试的最小变更
- 重构:在测试保持绿色的情况下清理代码
// 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");
}
Mock(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 ¬ifier) : notifier_(notifier) {}
void Publish(const std::string &message) { notifier_.Send(message); }
private:
Notifier ¬ifier_;
};
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
兼容工具
Claude CodeCursor
标签
测试

