# WhuCPPTestProject01 **Repository Path**: liufumore/whu-cpptest-project01 ## Basic Information - **Project Name**: WhuCPPTestProject01 - **Description**: 武汉大学计算机学院-大一-devops实训案例: 测试相关: 集成测试、性能测试技术; * 测试文档规范 * 使用mock进行测试数据模拟 * 使用curl和swagger进行Restful接口测试 * 使用JMeter进行接口性能测试 * 使用puppeteer进行前端功能、性能测试 - **Primary Language**: C++ - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 1 - **Created**: 2026-07-12 - **Last Updated**: 2026-07-15 ## Categories & Tags **Categories**: Uncategorized **Tags**: 武汉大学暑期实训 ## README # HelloCrow — C++ Web 服务 + 全链路自动化测试 教学案例 一个麻雀虽小五脏俱全的 C++ Web 后端教学项目,覆盖 **vcpkg 依赖管理 → 编码实现 → GMock 单元测试 → httplib 集成测试 → Puppeteer 前端功能/性能测试 → Swagger/OpenAPI 交互式文档** 全流程。 ## 项目结构 ``` CPPTestProject01/ ├── CMakeLists.txt # 构建配置(find_package + vcpkg) ├── CMakePresets.json # cmake --preset default 一键配置 ├── vcpkg.json # 依赖声明(crow, gtest, cpp-httplib) ├── Agent.md # 项目驾驭指南(环境配置 + 开发实操手册) ├── src/ │ └── main.cpp # 服务器全部代码(~200 行) ├── tests/ │ └── test_basic.cpp # 单元测试(GMock)+ 集成测试(httplib) ├── scripts/ │ ├── package.json # Puppeteer 依赖 │ └── test_frontend.js # 前端功能 + 性能测试 ├── static/ │ ├── index.html # 前端页面(可视化操作全部 HTTP 方法) │ ├── swagger.html # Swagger UI(交互式 API 文档) │ └── openapi.yaml # OpenAPI 3.0 规范文件 ├── Playwright讲义/ # Playwright 浏览器自动化讲义 ├── RESTful-API讲义/ # RESTful API 设计讲义 ├── curl命令/ # curl 命令行工具指南 ├── mock测试/ # GMock/GTest 单元测试讲义 + 完整 Demo ├── swagger讲义/ # Swagger/OpenAPI 实战教程 ├── jmeter讲义/ # JMeter 性能测试脚本 + HTML 报告 └── README.md ``` ## 技术栈 | 组件 | 用途 | | ---------------------------------- | ----------------------------------------------------------- | | **Crow** | C++ 微 Web 框架(路由 + JSON + 中间件 + 静态文件) | | **GTest/GMock** | 单元测试框架(`MOCK_METHOD` + `EXPECT_CALL` 模拟依赖) | | **cpp-httplib** | 单头文件 HTTP 客户端(集成测试发真实请求) | | **Puppeteer** | 无头浏览器(前端功能验证 + 性能指标采集) | | **Swagger UI / OpenAPI 3.0** | 交互式 API 文档(`static/openapi.yaml` 驱动) | | **JMeter** | 性能/压力测试(并发压测、稳定性测试、混合场景 + HTML 报告) | | **vcpkg** | C++ 包管理器(清单模式,一条命令安装所有依赖) | | **CMake** | 跨平台构建系统 | ## 快速开始 ### 前提条件 - CMake ≥ 3.20 - C++17 编译器(MSVC 2019+ / GCC 9+ / Clang 10+) - [vcpkg](https://github.com/microsoft/vcpkg)(本项目默认使用 `F:/vcpkg`,若路径不同,修改 [CMakePresets.json](CMakePresets.json) 中的 `toolchainFile`) - Node.js(仅前端测试需要) ### 1. 安装 C++ 依赖 ```bash # vcpkg 自动读取 vcpkg.json,首次会下载编译,之后秒级完成 vcpkg install ``` ### 2. 编译 ```bash # 预设已配置 vcpkg 路径,无需手动指定 -DCMAKE_TOOLCHAIN_FILE=... cmake --preset default cmake --build build ``` ### 3. 启动服务器 ```bash # 必须从 build/Debug 启动 — 服务器从当前目录读取 static/ 静态文件 cd build/Debug ./hello_crow.exe ``` 启动后会看到: ``` (2026-07-13 08:59:00) [INFO ] Crow/master server is running at http://0.0.0.0:18080 using 32 threads (2026-07-13 08:59:00) [INFO ] Call `app.loglevel(crow::LogLevel::Warning)` to hide Info level logs. ``` 打开浏览器访问: - 前端页面:`http://localhost:18080` - Swagger UI:`http://localhost:18080/swagger.html`(交互式 API 文档) 按 `Ctrl+C` 停止服务器。 #### 快速验证 服务启动后,用 curl 确认各端点正常: ```bash # 首页 curl -s -o /dev/null -w "首页: HTTP %{http_code}\n" http://localhost:18080/ # 列表(带分页) curl -s "http://localhost:18080/api/items?page=1&limit=10" # 创建 curl -s -X POST http://localhost:18080/api/items \ -H "Content-Type: application/json" \ -d '{"name":"测试项目"}' # 请求统计 curl -s http://localhost:18080/api/count ``` ### 4. 运行 C++ 测试 ```bash # 直接运行 ./build/Debug/hello_test.exe # 或通过 CTest ctest --test-dir build --output-on-failure ``` 预期输出: ``` [==========] Running 15 tests from 2 test suites. [----------] 3 tests from GreeterServiceTest ← GMock 单元测试 [ OK ] GreeterServiceTest.SayHello_ReturnsGreeting [ OK ] GreeterServiceTest.SayHello_EmptyName_DefaultsToWorld [ OK ] GreeterServiceTest.SayHello_CallsGreetExactlyOnce [----------] 12 tests from IntegrationTest ← httplib 集成测试 [ OK ] IntegrationTest.GET_List_ReturnsEmptyArray [ OK ] IntegrationTest.GET_ById_Returns404ForMissing [ OK ] IntegrationTest.POST_Create_Returns201 [ OK ] IntegrationTest.POST_InvalidJson_Returns400 [ OK ] IntegrationTest.CreateThenRead [ OK ] IntegrationTest.PUT_Update_Returns200 [ OK ] IntegrationTest.PUT_MissingItem_Returns404 [ OK ] IntegrationTest.PATCH_PartialUpdate_Returns200 [ OK ] IntegrationTest.DELETE_ExistingItem_Returns200 [ OK ] IntegrationTest.DELETE_MissingItem_Returns404 [ OK ] IntegrationTest.HEAD_ReturnsHeadersNoBody [ OK ] IntegrationTest.OPTIONS_Returns204 [==========] 15 tests from 2 test suites ran. (3828 ms total) [ PASSED ] 15 tests. ``` ### 5. 运行前端测试(Puppeteer) ```bash cd scripts npm install # 首次执行 node test_frontend.js # 全部测试(功能 + 性能) node test_frontend.js --functional # 仅功能测试 node test_frontend.js --performance # 仅性能测试 ``` 预期输出: ``` ============================================================ 功能测试 (Functional Tests) 11/11 ✓ ============================================================ [Test 1] 页面加载 PASS 标题正确 [Test 2] GET /api/items PASS 返回 JSON 列表 [Test 3] POST /api/items PASS 201 + id [Test 4] GET /api/items/:id PASS 200 + JSON [Test 5] PUT /api/items/:id PASS 200 + 更新后数据 [Test 6] PATCH /api/items/:id PASS 200 + 部分更新 [Test 7] DELETE /api/items/:id PASS 200 + deleted [Test 8] HEAD /api/items PASS 200(无 body) [Test 9] OPTIONS /api/items PASS 204 + Allow [Test 10] GET /api/count PASS 请求统计 [Test 11] 404 错误处理 PASS 404 ============================================================ 性能测试 (Performance Tests) 3/3 ✓ ============================================================ [Perf 1] 页面加载性能 PASS TTFB=1ms, Load=50ms [Perf 2] API 响应时间 PASS GET /api/items avg=14ms [Perf 3] 截图保存 PASS test_result.png ``` ## 测试全景图 ``` ┌─────────────────────────────────────────────────────────┐ │ 全链路测试矩阵 │ ├──────────────┬──────────────┬──────────────┬────────────┤ │ 测试层级 │ 工具 │ 测试数量 │ 耗时 │ ├──────────────┼──────────────┼──────────────┼────────────┤ │ 单元测试 │ GMock │ 3 个 │ < 5ms │ │ 集成测试 │ httplib │ 12 个 │ ~3800ms │ │ 前端功能测试 │ Puppeteer │ 11 个 │ ~1500ms │ │ 前端性能测试 │ Puppeteer │ 3 个 │ ~1200ms │ │ 压力/性能测试 │ JMeter │ 4 个 │ 可配置 │ ├──────────────┼──────────────┼──────────────┼────────────┤ │ 总计 │ │ 33 个 │ 全部通过 │ └──────────────┴──────────────┴──────────────┴────────────┘ ``` ## API 端点 | 方法 | 路径 | 说明 | 状态码 | | ----------------- | ------------------ | ----------------------------------------------------- | --------- | | **GET** | `/api/items` | 列出所有条目(支持分页`?page=1&limit=20`) | 200 | | **GET** | `/api/items/:id` | 读取单条(含`created_at` / `updated_at`) | 200 / 404 | | **POST** | `/api/items` | 创建条目`{"name":"xxx"}` → 自动添加 `created_at` | 201 / 400 | | **PUT** | `/api/items/:id` | 全量替换 → 自动添加`updated_at` | 200 / 404 | | **PATCH** | `/api/items/:id` | 部分更新(只传要改的字段)→ 自动添加`updated_at` | 200 / 404 | | **DELETE** | `/api/items/:id` | 删除条目 | 200 / 404 | | **HEAD** | `/api/items` | 只返回头(`X-Total-Count`),无 body | 200 | | **OPTIONS** | `/api/items` | CORS 预检,返回`Allow` 头 | 204 | | **GET** | `/api/count` | 请求统计(含`server_time`) | 200 | ```bash # 创建 curl -X POST -H "Content-Type: application/json" \ -d '{"name":"C++ Primer"}' http://localhost:18080/api/items # → 201 {"id":1,"name":"C++ Primer","created_at":"2025-03-15T08:30:00Z"} # 列表(支持分页) curl "http://localhost:18080/api/items?page=1&limit=10" # → 200 {"items":[...],"total":1,"page":1,"limit":10} # 读取单条 curl http://localhost:18080/api/items/1 # → 200 {"id":1,"name":"C++ Primer","created_at":"2025-03-15T08:30:00Z"} # 全量替换 (PUT) curl -X PUT -H "Content-Type: application/json" \ -d '{"name":"Effective C++"}' http://localhost:18080/api/items/1 # → 200 {"id":1,"name":"Effective C++","updated_at":"2025-03-15T08:31:00Z"} # 部分更新 (PATCH) curl -X PATCH -H "Content-Type: application/json" \ -d '{"name":"More Effective C++"}' http://localhost:18080/api/items/1 # → 200 {"id":1,"name":"More Effective C++","updated_at":"2025-03-15T08:32:00Z"} # 删除 curl -X DELETE http://localhost:18080/api/items/1 # → 200 {"deleted":1} # HEAD — 只返回头 curl -I http://localhost:18080/api/items # → HTTP/1.1 200 OK | X-Total-Count: 0 # OPTIONS — CORS 预检 curl -X OPTIONS -v http://localhost:18080/api/items 2>&1 | grep -i allow # → Allow: GET, POST, HEAD, OPTIONS ``` ## Swagger / OpenAPI 交互式文档 启动服务器后,访问 **`http://localhost:18080/swagger.html`** 即可打开 Swagger UI: - **在线调试**:直接在页面上填入参数并发起 API 请求,实时查看响应 - **Schema 驱动**:所有 API 定义集中在 [static/openapi.yaml](static/openapi.yaml)(OpenAPI 3.0 规范) - **零配置**:Swagger UI 通过 CDN 加载,无需额外安装 ``` http://localhost:18080/swagger.html → Swagger UI(交互式文档) http://localhost:18080/openapi.yaml → OpenAPI 规范源文件 ``` ## 配套讲义 | 目录 | 内容 | | ----------------------------------- | ------------------------------------------------------- | | [mock测试/](mock测试/) | GMock/GTest 单元测试完整教学 + Crow 集成最小可运行 Demo | | [Playwright讲义/](Playwright讲义/) | Playwright 浏览器自动化测试框架教程 | | [RESTful-API讲义/](RESTful-API讲义/) | RESTful API 设计原则与最佳实践 | | [swagger讲义/](swagger讲义/) | Swagger / OpenAPI 规范实战教程 | | [curl命令/](curl命令/) | curl 命令行 HTTP 工具使用指南 | | [jmeter讲义/](jmeter讲义/) | JMeter 性能测试:压力/稳定性/混合场景 + HTML 报告 | ## 核心概念解析 ### 1. 为什么需要 Mock? ``` 没有 Mock: 测试 → Service → 数据库(慢、状态污染) 用 Mock: 测试 → Service → Mock对象(快、完全可控) ``` Mock 把"依赖"替换成"假对象",让单元测试只测当前层的逻辑,不受外部系统影响。 ### 2. GMock 三步法 ```cpp // ① 定义 Mock 类(一行搞定 — MOCK_METHOD 宏自动生成所有脚手架代码) class MockGreeter : public IGreeter { public: MOCK_METHOD(std::string, greet, (const std::string&), (const, override)); }; // ② 设定期望:当 greet("Alice") 被调用时,返回 "Hello, Alice!" MockGreeter mock; EXPECT_CALL(mock, greet("Alice")).WillOnce(Return("Hello, Alice!")); // ③ 依赖注入 → 调用被测方法 → 断言结果 GreeterService service(&mock); EXPECT_EQ(service.sayHello("Alice"), "Hello, Alice!"); // GMock 在测试结束时自动验证 greet("Alice") 确实被调用了 1 次 ``` ### 3. 依赖注入(Dependency Injection) ```cpp // 高层模块不依赖低层实现,两者都依赖抽象接口 class GreeterService { const IGreeter* greeter_; // 只依赖接口,不依赖具体实现 public: explicit GreeterService(const IGreeter* g) : greeter_(g) {} // ... }; // 生产环境注入真实实现 GreeterService service(new RealGreeter()); // 测试环境注入 Mock GreeterService service(new MockGreeter()); ``` ### 4. 测试金字塔 ``` /\ /PP\ Puppeteer(少量,端到端验证) /────\ / 集成 \ httplib(中等,组件协作验证) /────────\ / 单元测试 \ GMock(大量,快速、精准定位) /────────────\ ``` ## 文件说明 | 文件 | 内容 | | --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [src/main.cpp](src/main.cpp) | 服务器全部代码:内存数据库 + 8 个 HTTP 方法路由 + 静态文件服务(含 Swagger UI) | | [tests/test_basic.cpp](tests/test_basic.cpp) | C++ 测试:Part 1 GMock 演示(接口→Mock→注入→验证),Part 2 TestServerHelper(注册全部 REST 路由),Part 3 集成测试(覆盖 GET/POST/PUT/PATCH/DELETE/HEAD/OPTIONS) | | [scripts/test_frontend.js](scripts/test_frontend.js) | Puppeteer 测试:功能验证(11 项)+ 性能采集(TTFB/FCP/API 延迟/截图) | | [static/index.html](static/index.html) | 前端页面:可视化操作全部 HTTP 方法,实时显示请求/响应 | | [static/swagger.html](static/swagger.html) | Swagger UI 页面:交互式浏览和调试全部 API | | [static/openapi.yaml](static/openapi.yaml) | OpenAPI 3.0 规范:API 结构定义(路径、参数、响应 Schema) | | [vcpkg.json](vcpkg.json) | vcpkg 清单模式依赖声明 | | [CMakePresets.json](CMakePresets.json) | CMake 预设,固化 vcpkg toolchain 路径 |