动力学与控制系统测试框架指南 (Testing Framework Guide)
文档状态: Draft / Active 生成日期: 2026-03-27 主要作者: AI (Gemini)
1. 测试架构背景与策略
在本项目(FCC-Dynamics-C)中,我们采用了 “分层测试策略”(Two-Tier Testing Strategy) 来满足两种截然不同的测试需求:
- 代码重构与迁移验证(从
src_legacy到src):需要频繁、细粒度的数值和逻辑对比,确保新旧代码在物理和数学层面的严格等价。 - 多场景弹道仿真计算(系统级与集成测试):未来需要验证不同条件(标准弹道、零干扰、高空风等)下的全系统表现。
为此,我们引入了以下工具链:
- Google Test (GTest):作为核心的 C++ 单元测试框架,用于处理底层的函数逻辑测试,特别是其强大的浮点数断言宏(如
EXPECT_NEAR,EXPECT_DOUBLE_EQ)非常适合物理仿真的数值校验。 - CMake / CTest:作为统一的测试运行调度器。不仅可以管理 GTest 的单元测试,还能直接挂载带有不同配置参数的集成测试可执行文件。
项目通过 CMake 的 FetchContent 模块自动下载并编译 GTest,开发者无需在本地手动安装任何依赖环境。
2. 如何编写与配置单元测试 (Google Test)
2.1 编写测试代码 (.cpp)
测试代码统一存放在 Test/ 目录下。以 Test/io_types_test.cpp 为例,一个标准的单元测试如下:
cpp
#include <gtest/gtest.h>
#include "io/types/io_types.h"
// 使用 TEST 宏定义测试用例。第一个参数是测试套件名,第二个参数是测试名。
TEST(IOTypesTest, Constants) {
io::Constants c;
c["pi"] = 3.14159;
// 数值比较 (推荐使用 EXPECT_NEAR 处理浮点误差)
EXPECT_NEAR(io::get_constant(c, "pi", 0.0), 3.14159, 1e-5);
// 异常断言
EXPECT_THROW({
io::get_constant_or_throw(c, "nonexistent");
}, std::runtime_error);
}- 断言建议:
- 比较浮点数绝对优先使用
EXPECT_NEAR(val1, val2, abs_error)或EXPECT_DOUBLE_EQ(val1, val2)。 - 异常测试使用
EXPECT_THROW(statement, exception_type)和EXPECT_NO_THROW(statement)。 - 不需要手写
main()函数,CMake 会自动链接gtest_main。
- 比较浮点数绝对优先使用
2.2 配置 CMake (Test/CMakeLists.txt)
添加新的测试文件后,需要在 Test/CMakeLists.txt 中注册该测试。以下是标准模板:
cmake
# 1. 声明可执行文件
add_executable(my_new_module_test
my_new_module_test.cpp
)
# 2. 包含头文件路径
target_include_directories(my_new_module_test PRIVATE
${CMAKE_SOURCE_DIR}/src
)
# 3. 链接目标模块库与 GTest (gtest_main 是必须的)
target_link_libraries(my_new_module_test
my_target_module_lib
gtest_main
)
# 4. 自动将其注册到 CTest 中
gtest_discover_tests(my_new_module_test)
# 5. [可选] 设定输出路径保持整洁
set_target_properties(my_new_module_test PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/Test
)3. 如何运行测试 (CTest)
CTest 是 CMake 自带的测试执行工具,所有测试都应该通过 ctest 命令运行,不建议直接执行二进制文件或使用旧版的 .sh 脚本。
常规运行方式
在 build/ 目录下:
bash
# 1. 配置并编译项目及测试
cmake ..
make -j$(nproc)
# 2. 运行所有测试并仅在失败时输出详情 (推荐日常使用)
ctest --output-on-failure进阶 CTest 命令
- 按名称过滤运行:例如只运行包含
IO相关的测试。bashctest -R IO - 多线程并发运行测试(当测试用例增加后可大幅缩短时间):bash
ctest -j4 - 查看极详细的日志输出(即使测试通过也显示所有标准输出):bash
ctest -V
4. 进阶规划:集成与系统级测试
针对“将来需要运行不同的标准弹道、零干扰以及注入各种干扰的计算”这一需求,架构规划如下:
4.1 数据驱动的单一入口
系统应当摒弃“为每种场景写一个 main 函数”的模式,转而构建一个带有参数解析能力的统一仿真器程序(例如 sim_runner)。
通过命令行参数读取不同配置文件(JSON/YAML):
bash
./sim_runner --config=data/standard_trajectory.json
./sim_runner --config=data/zero_disturbance.json4.2 CTest 场景挂载
在 CMakeLists.txt 中,使用 add_test 指令将不同的配置文件运行定义为独立的测试用例:
cmake
# Test/CMakeLists.txt (示例规划)
# 测试标准弹道配置是否能正常执行并返回 0
add_test(NAME Integration_Standard_Trajectory
COMMAND sim_runner --config ${CMAKE_SOURCE_DIR}/data/standard.json)
# 测试零干扰配置
add_test(NAME Integration_Zero_Disturbance
COMMAND sim_runner --config ${CMAKE_SOURCE_DIR}/data/zero_dist.json)这样,每次只需执行 ctest,即可全自动验证系统在数十种不同干预/配置下的运行稳定性。如果需要对输出结果(如 CSV)进行落点分析,可配合 Python pytest 脚本调用该程序。