尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Robomongo 单元测试体系解析:Test-sibling 布局、GoogleTest 集成与 CMake 构建全解

Robomongo 单元测试体系解析:Test-sibling 布局、GoogleTest 集成与 CMake 构建全解 数据库客户端桌面应用【免费下载链接】robomongoNative cross-platform MongoDB management tool项目地址https://gitcode.com/gh_mirrors/ro/robomongo点击查看免费下载本篇文章以 RobomongoRobo 3T 的前身原生跨平台 MongoDB 管理工具源码仓库中的 src/robomongo-unit-tests/README.md 为骨架结合 src/robomongo-unit-tests/CMakeLists.txt 及三组真实测试源码系统讲解该项目的单元测试组织约定、GoogleTest 接入方式、robo_unit_tests目标的构建与链接细节以及现有测试用例的写法与可验证的底层实现。读完本文你将能快速定位 Robomongo 的测试文件、理解被测源码与测试文件同目录平级的独特约定并掌握在其上新增测试对Foo.cpp / Foo_test.cpp的正确姿势。一、测试模块的定位与目录约定1.1 一个为 CMake 占位的目录src/robomongo-unit-tests/README.md第一句便开宗明义This is just a placeholder forcmake.这句话包含两层信息该目录不是一个独立的测试源码树真正的测试代码并不存放在这里它存在的意义是承载 CMake 构建目标让robo_unit_tests可执行文件有一个明确的家。从根目录 CMakeLists.txt 可以看到add_subdirectory(src/robomongo-unit-tests)也就是说整个测试目标是由该子目录的 CMakeLists.txt 定义的。与此同时测试用例源码与待测源码同目录存放robomongo/src/robomongo/ ├── utils/ │ ├── RoboCrypt.cpp │ ├── RoboCrypt_test.cpp │ ├── StringOperations.cpp │ └── StringOperations_test.cpp └── core/ └── HexUtils.cpp └── HexUtils_test.cpp这正是 README 强调的惯例测试源文件与被测文件位于同一目录、同一层级。这一test-sibling测试与源码平级布局与许多项目单独划分tests/目录的做法不同其好处是显而易见的可发现性写代码和写测试的人处在同一目录随时能看到对应的_test.cpp降低只写实现、不写测试的概率就近引用测试可以直接以相对包含如#include HexUtils.h方式引入被测头文件不必绕行长长的include路径构建聚合CMake 里可以用list(FILTER ... INCLUDE REGEX cpp)等方式统一聚合源文件测试文件天然与源码文件混编在同一构建单元中。1.2 目录中的实际文件当前仓库src/robomongo-unit-tests/下只有两个文件文件作用README.md说明目录定位与测试文件放置约定CMakeLists.txt定义robo_unit_tests可执行目标、gtest 链接与平台差异化配置二、GoogleTest 接入与robo_unit_tests目标的构建机制2.1 测试框架选型GoogleTestsrc/robomongo-unit-tests/CMakeLists.txt顶部注释即写明Unit Testing with Google Test。仓库在 src/third-party/googletest-1.8.1/ 中随源码一同携带了 googletest 1.8.1含 googlemock并在 src/third-party/CMakeLists.txt 中作为第三方依赖引入因此无需系统级安装 gtest 即可构建测试。构建脚本中的关键配置enable_testing() include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR}) set(gtest_force_shared_crt ON CACHE BOOL FORCE)enable_testing()启用 CTest使ctest能够发现并运行robo_unit_tests中的用例include_directories把 googletest 的头文件目录加入编译搜索路径测试源码中可直接#include gtest/gtest.hgtest_force_shared_crt强制 gtest 使用共享 CRTWindows 场景下避免运行库冲突。2.2 测试源文件的登记方式CMakeLists 中对如何新增测试对给出了明确约定New test source file pairs MUST have the following format:Test file:/path/Foo_test.cppSource file:/path/Foo.cppor/path/Foo.h即凡新增测试必须遵循Foo_test.cpp对应Foo.cpp或Foo.h的命名对称然后把测试文件路径追加到SOURCES_TEST变量中。当前登记的三个测试文件为set(ROBO_SRC_DIR ${CMAKE_HOME_DIRECTORY}/src/robomongo) set(SOURCES_TEST ${ROBO_SRC_DIR}/utils/RoboCrypt_test.cpp ${ROBO_SRC_DIR}/utils/StringOperations_test.cpp ${ROBO_SRC_DIR}/core/HexUtils_test.cpp )ROBO_SRC_DIR指向src/robomongo这与 README 中测试文件位于 robomongo/src/robomongo/ 及其子目录的说明完全吻合。2.3 可执行目标与链接关系add_executable(robo_unit_tests ${SOURCES_TEST}) add_dependencies(robo_unit_tests robomongo) target_include_directories(robo_unit_tests PRIVATE ${CMAKE_HOME_DIRECTORY}/src)add_executable(robo_unit_tests ...)生成名为robo_unit_tests的测试可执行文件add_dependencies(robo_unit_tests robomongo)确保主程序robomongo目标先构建测试二进制随后链接其目标文件target_include_directories(..., src)把仓库根src加入测试目标私有头文件路径使测试代码能以robomongo/utils/RoboCrypt.h这种以 src 为根的路径引入头文件。链接阶段脚本先从robomongo目标取出全部源码剔除main.cpp、只保留.cppget_target_property(ROBO_SOURCES robomongo SOURCES) list(FILTER ROBO_SOURCES INCLUDE REGEX cpp) list(FILTER ROBO_SOURCES EXCLUDE REGEX main.cpp)随后按平台把每个源码文件翻译成目标文件路径Windows 为*.objmacOS 为*.cpp.o连同 Qt 自动生成的mocs_compilation、qrc_gui、qrc_robo等对象一并收集到ROBO_OBJ_FILES中最终与 gtest 及各类库一起链接target_link_libraries(robo_unit_tests gtest gtest_main Qt5::Widgets Qt5::Network Qt5::Xml ${WebEngineWidgets} qjson qscintilla mongodb ssh Threads::Threads ${ROBO_OBJ_FILES} )gtest与gtest_main提供了框架运行时与main入口使测试文件只需写TEST(...)宏、无需自带 mainqjson、qscintilla、mongodb、ssh等则是 Robomongo 主程序在解析 JSON、脚本编辑、MongoDB 客户端与 SSH 隧道等模块用到的内部/第三方库测试目标把它们全部链接进来意味着测试用例可以触及核心业务代码。2.4 平台差异与已知限制Linux 当前禁用脚本开头有一段醒目提示if (SYSTEM_LINUX) message(\n *Note: Currently unit testing is disabled for Linux due to MongoDB linking problems) return() endif()也就是说在 Linux 平台上单元测试目标目前被主动跳过README 中 placeholder for cmake 的说法也与这种仅保留构建占位的现状呼应Linux 分支的目标文件收集代码也整段处于注释状态。这一限制源于 MongoDB 客户端库在 Linux 下的链接问题属于当前仓库的实际状态说明。macOS 特殊处理额外链接Security、CoreFoundation与-lresolv以补全 macOS 下解析器与安全框架依赖。Windows DLL 部署Debug 构建时向文件名追加d后缀Qt5Cored.dll等并把 Qt5 系列 DLLCore/Gui/Network/PrintSupport/Widgets/Xml/Positioning/Qml/Quick/QuickWidgets/WebChannel/WebEngine*以及 OpenSSL 的libssl-1_1-x64.dll、libcrypto-1_1-x64.dll复制到测试二进制输出目录保证测试运行时 DLL 可达。三、现有测试用例逐条解析3.1 RoboCrypt加解密往返一致性RoboCrypt_test.cpp 是当前唯一一个实质性测试用例它验证Robomongo::RoboCrypt的加密与解密是互逆的TEST(RoboCrypt_CoreTests, encrypt_decrypt) { auto const pwds { Tyu_aBq, _?asdfghjkl;piop[.,/, .?/_~!#$%^^*)_)_-, ?/.,;:][p{}|\ }; for (auto const pwd : pwds) { const std::string encryptedPwd Robomongo::RoboCrypt::encrypt(pwd); const std::string decryptedPwd Robomongo::RoboCrypt::decrypt(encryptedPwd); EXPECT_EQ(pwd, decryptedPwd); } }用例选取了四类输入普通字母数字串、纯符号串、混合转义符号串与引号串覆盖了密码/凭据中常见字符集。其底层实现位于 RoboCrypt.cpp 与 RoboCrypt.hencrypt/decrypt本质是对SimpleCrypt的薄封装将std::string转成QString后调用encryptToString/decryptToString。而SimpleCryptSimpleCrypt.h是一个使用64 位密钥的简单加解密类其头文件注释明确警告The encryption provided by this class is NOT strong encryption. It may help to shield things from curious eyes, but it will NOT stand up to someone determined to break the encryption.因此 RoboCrypt 用于防止路过的好奇目光例如明文密码直接落盘而非对抗专业攻击者。RoboCrypt::initKey()的密钥管理策略也值得注意优先从~/.3T/robo-3t/robo3t.key读取已有密钥若不存在则用std::mt19937_64在2^61 ~ 2^62区间生成新密钥并写回该文件全程通过_roboCryptLogs记录日志与严重级别RoboCrypt.cpp。测试所依赖的SimpleCrypt静态实例正是以这把_KEY初始化的。3.2 StringOperations首字符大写化StringOperations_test.cpp 只有一个用例验证captilizeFirstCharTEST(StringOperationsTests, captilizeFirstChar) { // EXPECT_EQ(Abcc, Robomongo::captilizeFirstChar(abc)); // Simulating failing test EXPECT_EQ(Abc, Robomongo::captilizeFirstChar(abc)); // Simulating passing test }注释里同时保留了模拟失败用例与模拟通过用例两行可看作编写断言的示例。被测实现位于 StringOperations.cppstd::string captilizeFirstChar(std::string str) { if (!str.empty()) str[0] static_castchar(toupper(str[0])); return str; }即对非空字符串的首字符执行toupper。头文件 StringOperations.h 解释了该函数的动机Mongo errors often come all lower case——MongoDB 返回的错误信息常为全小写Robomongo 用它把错误提示的首字母大写改善 UI 展示。可见该工具函数服务于 Mongo 错误信息的格式化是 GUI 与底层 MongoDB 客户端之间的一层字符串规整逻辑。3.3 HexUtils十六进制判定HexUtils_test.cpp 验证Robomongo::HexUtils::isHexStringTEST(hex_utils_tests, test_1) { EXPECT_TRUE(Robomongo::HexUtils::isHexString(a)); }被测实现位于 HexUtils.cpp逐字符调用isxdigit检查任一字符非十六进制字符即返回false。同文件还提供toStdHexLower底层复用mongo::toHexLower与fromHex要求输入长度为偶数否则返回 NULL说明 HexUtils 是 Robomongo 与 MongoDB 驱动之间做二进制/十六进制互转的桥接工具其正确性直接影响 BSON 数据展示等核心功能。3.4 测试文件的通用写法范式三个测试文件头部都带有一段相同的注释模板实际起到了团队测试规范的作用TEST( [Test_Case_Name], [Test_Name] ) TEST( [Test_Case_Name], [UnitOfWorkName_ScenarioUnderTest_ExpectedBehavior] ) TEST( StringParserTests, NumberLeftOf_StringWithoutNumber_ReturnsFalse) { // ... }它提倡两级命名第一参数为测试套件名如RoboCrypt_CoreTests、StringOperationsTests、hex_utils_tests第二参数为具体行为描述推荐采用被测单元_场景_期望行为的句式让失败时gtest输出的用例名自带可读语义。这也解释了为什么断言宏优先使用EXPECT_EQ/EXPECT_TRUE非致命断言失败后继续执行本用例而不是ASSERT_*。四、与主程序测试入口的关联除了 gtest 体系仓库还保留了另一条轻量自检路线主程序目录下的 main_test.cpp 不依赖 gtest而是直接用assert检查 MongoDB 驱动的两个行为点HostAndPort的toString()验证 IPv4、IPv6含方括号包裹的边界行为的格式化输出例如断言HostAndPort(2a03:b0c0:3:d0::f3:1001, 20017)会序列化为[2a03:b0c0:3:d0::f3:1001]:20017并顺带记录了 MongoDB 3.2 中已含方括号仍会再次包裹的已知行为double的精度输出用std::numeric_limitsdouble::digits10控制流精度逐一断言-9.987654321、1.1、3.1415等值的字符串序列化结果。这与robo_unit_tests形成互补gtest 目标覆盖项目自身工具函数main_test.cpp则直接校验依赖的 MongoDB 客户端库在 Robomongo 使用方式下的行为是否符合预期。五、如何新增一个测试实操指南结合 README 约定与 CMake 脚本在 Robomongo 中新增一个单元测试需要三步写被测代码在src/robomongo/相应子目录如utils/、core/下放置Foo.cpp或仅Foo.h同目录新建Foo_test.cpp与Foo.cpp平级放置命名必须为Foo_test.cpp内容形如#include gtest/gtest.h #include Foo.h TEST(FooTests, Bar_Scenario_Expected) { EXPECT_EQ(/* 期望值 */, Robomongo::bar(/* 输入 */)); }头文件按 CMake 中target_include_directories(robo_unit_tests PRIVATE src)的配置既可写#include robomongo/utils/Foo.h也可按实际相对关系写#include Foo.h登记到SOURCES_TEST在 src/robomongo-unit-tests/CMakeLists.txt 的SOURCES_TEST列表中追加${ROBO_SRC_DIR}/子目录/Foo_test.cpp重新配置并构建后robo_unit_tests可执行文件即包含新用例。之后即可通过ctest或直接运行robo_unit_tests可执行文件执行测试。需要留意的是当前仓库在 Linux 平台下该目标会被 CMake 脚本提前return()跳过实测请优先在 Windows / macOS 环境下构建Linux 下如需验证相关工具函数可借助main_test.cpp这类不依赖 gtest 的自检入口或参照 docs/BuildRobo3TOnMacAndLinux.md、docs/BuildRobo3TOnWindows.md 了解完整的构建流程与平台前提。六、小结Robomongo 的单元测试体系可以用三句话概括布局约定测试文件与被测文件同目录平级命名严格遵循Foo_test.cpp↔Foo.cpp/Foo.h的对仗关系目录本身仅为 CMake 占位见 src/robomongo-unit-tests/README.md构建机制由 src/robomongo-unit-tests/CMakeLists.txt 基于 googletest 1.8.1 生成robo_unit_tests目标复用主程序robomongo的全部对象文件并针对 Windows/macOS 做了 DLL 部署与系统库链接的差异化处理Linux 平台因 MongoDB 链接问题暂时禁用现有覆盖三个 gtest 用例分别覆盖密码加解密往返RoboCrypt SimpleCrypt、Mongo 错误信息首字母大写化StringOperations与十六进制字符串判定HexUtils另有main_test.cpp承担 MongoDB 驱动HostAndPort/double精度输出的断言式自检。这套以源码树为骨架、就近测试的组织方式与 src/third-party/googletest-1.8.1/ 的随仓依赖策略相结合构成了一个对贡献者足够低门槛、对构建系统足够显式的测试基础设施是研究 Robomongo 内部质量保障机制的最佳切入点。赞分享数据库客户端桌面应用【免费下载链接】robomongoNative cross-platform MongoDB management tool项目地址https://gitcode.com/gh_mirrors/ro/robomongo点击查看免费下载相关推荐WeexCore 测试工程集成 Google Test 实战googletest 构建方式与 CMake 配置全解WeexCore 测试工程集成 Google Test 实战googletest 构建方式与 CMake 配置全解 导读 Google Testgoogle移动开发跨平台前端从 cargo test 看 Cargo 的测试体系单元测试、集成测试与文档测试全解析从 cargo test 看 Cargo 的测试体系单元测试、集成测试与文档测试全解析 cargo test 是 Cargo 提供的统一测试入口一条命令即可开发工具包管理器CLI构建工具Apache WeexCore 测试体系实战基于 Google Testgoogletest的 C 单元测试框架集成指南Apache WeexCore 测试体系实战基于 Google Testgoogletest的 C 单元测试框架集成指南 Google Test 是移动开发跨平台原生移动前端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表