
在 Xcode 中使用 Google Test Frameworkminiblink49 仓库 gtest Xcode 集成实战指南【免费下载链接】miniblink49a lighter, faster browser kernel of blink to integrate HTML UI in your app. 一个小巧、轻量的浏览器内核用来取代wke和libcef项目地址: https://gitcode.com/GitHub_Trending/mi/miniblink49导读本指南完整讲解如何在 Mac OS X 的 Xcode 工程中使用 Google Testgtest.framework编写与运行 C/C 单元测试覆盖从获取源码、构建 framework、创建测试 Target、配置动态链接运行环境到执行测试的完整链路。本文以 miniblink49 仓库中随 V8 一同携带的 gtest 官方文档 为主体骨架并对照仓库内 xcode 目录 下的真实工程配置与示例代码做源码级印证。读完本文你将能够独立地把 gtest 以 framework 形态接入任意 Xcode 项目并理解其动态链接与运行环境配置的底层原理。背景为什么 miniblink49 仓库里会有一份 Xcode 指南miniblink49 是一个跨平台的轻量浏览器内核项目其代码树中集成了多个版本的 V8如v8_4_5、v8_5_1、v8_7_5等以及配套的第三方库。V8 自身的测试体系依赖 Google Testgtest因此在 v8_7_5/testing/gtest 目录下可以看到完整的 gtest 源码树include/公共头文件、src/实现、samples/示例、msvc/与xcode/不同平台的工程文件以及docs/配套文档。本指南对应文档 V1_6_XcodeGuide.md 是 gtest 1.6 时代面向 Xcode 用户的官方集成手册它假定你工作在 Mac OS X Xcode 环境下并把 gtest 以Framework.framework束形式接入工程。虽然 miniblink49 的日常构建以 WindowsVS/VC6与 Linux 为主但这份文档连同xcode/目录中的工程文件是理解 gtest 构建形态、链接方式与动态库运行机制的重要参考。Quick Start七步集成速览对已有经验的用户官方给出了从零到跑通测试的七步快速上手流程使用 SVN 检出 gtest 源码详见下文获取源码一节。打开检出目录中xcode/目录下的gtest.xcodeproj构建出gtest.framework。在自己的 Xcode 工程中新建一个名为UnitTests或类似命名的Shell ToolTarget。将gtest.framework加入工程并把它挂到UnitTests的Link Binary with Libraries构建阶段。把单元测试源码加入UnitTests的Compile Sources构建阶段。编辑UnitTests可执行文件的配置添加名为DYLD_FRAMEWORK_PATH的环境变量其值为从编译产物可执行文件出发、到包含 gtest.framework 目录的相对路径。Build and Go直接运行测试。下文将逐一展开每个步骤的细节与变体。在 miniblink49 仓库中对应的gtest.xcodeproj工程文件位于 v8_7_5/testing/gtest/xcode/gtest.xcodeproj其工程描述文件为 project.pbxproj可供直接打开参考。获取源码当时 gtest.framework 尚未包含在 gtest 的正式 tag 发布中只能从 trunk主干获取。官方给出的匿名 SVN 检出命令为svn checkout http://googletest.googlecode.com/svn/trunk/ googletest-read-only检出完成后xcode/目录下即包含gtest.xcodeproj打开并构建即可得到gtest.framework。说明上述检出 URL 为文档撰写年代gtest 1.6 时期的历史地址如今 Google Test 已迁移到新的官方托管站点与 Git 工作流。若需获取本仓库中这份 gtest 1.6 的完整源码含xcode/工程直接查看仓库的 v8_7_5/testing/gtest 目录即可其目录结构与文档描述的 trunk 布局一致。通过 svn:externals 以外部依赖方式集成如果你自己的代码库本身使用 Subversion 管理可以不必把 gtest 源码复制进仓库而是通过svn:externals属性把它声明为外部依赖。这样任何检出你仓库的开发者都会自动连带取得一份指定版本的 gtest项目搭建更简单也避免源码重复入库。具体做法先决定外部源码的存放位置。可以把外部源码放进 trunk使其随分支一起发布也可以放在 trunk 之外的版本化目录例如third-party/googletest/1.0.1。用svn propedit svn:externals 目录在仓库的某个目录上设置svn:externals属性——该目录本身不含代码而是作为被声明外部依赖的版本化父目录。svn propedit会唤起 Subversion 编辑器便于编辑这种可能很长、跨多行的属性。svn:externals支持三种常见用法检出主干svn:externals的值形如externals/src/googletest http://googletest.googlecode.com/svn/trunk这会把 gtest 检出到trunk/externals/src/googletest/目录检出指定 tag 分支把 URL 换成对应 tag如.../svn/tags/release-1.0.1锁定指定版本通过-r版本号选项固定主干特定修订版本例如externals/src/googletest -r60 http://googletest.googlecode.com/svn/trunk。通过svn propget svn:externals trunk可以查看已设置的属性值示例输出为[Computer:svn] user$ svn propget svn:externals trunk externals/src/googletest http://googletest.googlecode.com/svn/trunk这一机制的价值在于它保证了团队内所有人使用完全一致的 gtest 版本必要时可锁定到具体 revision与把 gtest 目录直接放进仓库相比仓库体积更小、版本升级更可控。将 Framework 添加到你的工程获取源码并构建出gtest.framework后需要把它接入自己的工程。官方文档给出两种常见方式Option 1最简方式打开 gtest trunk 中xcode/目录下的gtest.xcodeproj手动构建 framework然后通过右键菜单的Add-Existing Framework...或主菜单的Project-Add...把构建产物加入工程。gtest.framework是可重定位的其中已经包含了编写测试所需的头文件与目标代码。这种方式每次升级 gtest 后都需要重新构建并重新添加一次。Option 2主干追随方式如果你长期跟随 gtest trunk想在单元测试中第一时间用上新特性或本身就是 gtest 开发者则应该把gtest.xcodeproj而非 framework 本身作为子工程加入自己的 Xcode 工程。这样在子工程展示三角形的构建产物节点里就能看到gtest.framework把它挂到你的 Target 上细节见下一节Xcode 会在每次构建时自动保证 framework 是最新的。仓库中的 xcode 工程结构印证在 miniblink49 的 v8_7_5/testing/gtest/xcode 目录下可以完整看到这套工程骨架xcode/ ├── Config/ # 基于 xcconfig 的构建配置 │ ├── DebugProject.xcconfig │ ├── FrameworkTarget.xcconfig │ ├── General.xcconfig │ ├── ReleaseProject.xcconfig │ ├── StaticLibraryTarget.xcconfig │ └── TestTarget.xcconfig ├── Resources/ │ └── Info.plist # framework 的 Info 清单 ├── Samples/ │ └── FrameworkSample/ # 可运行的示例工程 │ ├── WidgetFramework.xcodeproj/ │ │ └── project.pbxproj │ ├── Info.plist │ ├── runtests.sh │ ├── widget.cc / widget.h │ └── widget_test.cc ├── Scripts/ │ ├── runtests.sh │ └── versiongenerate.py └── gtest.xcodeproj/ └── project.pbxproj其中 FrameworkTarget.xcconfig 定义了 framework Target 的关键编译语义值得细读// Dynamic libs need to be position independent GCC_DYNAMIC_NO_PIC NO // Dynamic libs should not have their external symbols stripped. STRIP_STYLE non-global // Let the user install by specifying the $DSTROOT with xcodebuild SKIP_INSTALL NO这三项的含义分别是动态库需要位置无关代码动态库不应剥离外部符号保证测试链接时符号可解析允许通过xcodebuild的$DSTROOT指定安装路径。而 DebugProject.xcconfig 则为调试构建关闭了优化与死代码剥离、开启调试符号并注入-DDEBUG1宏同时刻意关闭 STL 调试检查以避免与客户端代码的 STL 不兼容——这些都是在与第三方框架如本仓库中大量使用的 STL 依赖集成时非常实用的工程经验。创建测试 Target开始写测试之前先新建一个Shell ToolTarget。该模板在 BSD、Cocoa、Carbon 应用类型下均可使用。把你的单元测试源码加入该 Target 的Compile Sources构建阶段。随后根据上一节选择的接入方式用对应的方法把gtest.framework链接进 TargetOption 1在编译期Xcode 需要知道你要链接gtest.framework。把它加入测试 Target 的Link Binary with Libraries构建阶段即可——这一步既会把 gtest 头文件加入头文件搜索路径也会告诉链接器去哪里找库。Option 2如果工作于 trunk同样要把gtest.framework加入Link Binary with Libraries此外还应把gtest.framework声明为单元测试 Target 的依赖这样每次构建你的 Target 时 Xcode 都会先确保 framework 是最新的。最后如果你们不共享构建目录还需要用一个Run Script构建阶段把gtest.framework复制进你自己的构建产物目录。测试代码长什么样仓库示例实证仓库 FrameworkSample 给出了完整的落地示例。被测对象 widget.h 是一个极简的Widget类内部保存float number_与std::string name_通过GetFloatValue()、GetIntValue()、GetStringValue()、GetCharPtrValue()等多个访问器以不同形态返回数据class Widget { public: Widget(int number, const std::string name); ~Widget(); // Public accessors to number data float GetFloatValue() const; int GetIntValue() const; // Public accessors to the string data std::string GetStringValue() const; void GetCharPtrValue(char* buffer, size_t max_size) const; private: float number_; std::string name_; };对应的测试文件 widget_test.cc 展示了 gtest 测试的典型写法——包含头文件、使用TEST()宏声明用例、用EXPECT_*断言#include string #include gtest/gtest.h #include Widget/widget.h // This test verifies that the constructor sets the internal state of the // Widget class correctly. TEST(WidgetInitializerTest, TestConstructor) { Widget widget(1.0f, name); EXPECT_FLOAT_EQ(1.0f, widget.GetFloatValue()); EXPECT_EQ(std::string(name), widget.GetStringValue()); } // This test verifies the conversion of the float and string values to int and // char*, respectively. TEST(WidgetInitializerTest, TestConversion) { Widget widget(1.0f, name); EXPECT_EQ(1, widget.GetIntValue()); size_t max_size 128; char buffer[max_size]; widget.GetCharPtrValue(buffer, max_size); EXPECT_STREQ(name, buffer); }从中可以看到 gtest 的三个基础要点TEST(TestCaseName, TestName)宏声明一条用例两个参数构成层级命名EXPECT_*家族断言EXPECT_FLOAT_EQ用于浮点比较自带容差、EXPECT_EQ用于整型/字符串对象比较、EXPECT_STREQ用于 C 字符串比较——三者恰好对应了Widget三种返回值形态的验证文件末尾的注释点明了 framework 的便捷性gtest 的 main 已链接进 framework等价于替你写好了testing::InitGoogleTest(argc, argv); return RUN_ALL_TESTS();因此测试文件本身无需再写main函数。在 TestTarget.xcconfig 中可以看到测试 Target 的配套设置PRODUCT_NAME $(TARGET_NAME) HEADER_SEARCH_PATHS ../includeHEADER_SEARCH_PATHS ../include使得#include gtest/gtest.h可以直接命中 gtest 源码树中的 include/gtest/gtest.h这也是上面示例代码第一行包含语句能够编译通过的配置前提。配置可执行程序的运行环境由于单元测试可执行文件是 Shell Tool它没有 bundle 那样的Contents/Frameworks目录来存放gtest.framework。因此必须在运行时告诉动态链接器去哪里搜索 framework——方法是在Edit Active Executable ...的 Arguments 页签、Variables to be set in the environment:中设置DYLD_FRAMEWORK_PATH环境变量。该变量的值是从可执行文件出发相对或绝对的、包含gtest.framework的目录路径。典型的运行失败与修复如果DYLD_FRAMEWORK_PATH没有正确设置运行时会出现如下dyld报错[Session started at 2008-08-15 06:23:57 -0600.] dyld: Library not loaded: loader_path/../Frameworks/gtest.framework/Versions/A/gtest Referenced from: /Users/username/Documents/Sandbox/gtestSample/build/Debug/WidgetFrameworkTest Reason: image not found修复步骤进入报错信息中Referenced from:所指可执行文件所在的目录然后在终端中计算从该目录到包含gtest.framework目录的相对路径把它设为DYLD_FRAMEWORK_PATH的值即可。报错中的loader_path/../Frameworks/...恰好说明了 framework 的安装约定它期望被放在可执行文件同级的Frameworks目录下或通过环境变量显式指定搜索位置。脚本化的环境配置runtests.sh仓库的 Scripts/runtests.sh 把这一步做成了可直接复用的脚本其核心两行正是对上述机制的程序化表达# Help the dynamic linker find the path to the libraries. export DYLD_FRAMEWORK_PATH$BUILT_PRODUCTS_DIR export DYLD_LIBRARY_PATH$BUILT_PRODUCTS_DIR$BUILT_PRODUCTS_DIR是 Xcode 构建产物目录脚本把 framework 与动态库搜索路径都指向它随后依次执行若干测试可执行文件统计成功/失败数量并以退出码$failed汇总结果test_executables($BUILT_PRODUCTS_DIR/gtest_unittest-framework $BUILT_PRODUCTS_DIR/gtest_unittest $BUILT_PRODUCTS_DIR/sample1_unittest-framework $BUILT_PRODUCTS_DIR/sample1_unittest-static) succeeded0 failed0 failed_list() for test in ${test_executables[*]}; do $test result$? ... done echo Tests complete with $succeeded successes and $failed failures. exit $failed示例工程 FrameworkSample/runtests.sh 是同款脚本的变体它从命令行参数$接收待执行的测试列表便于你在自己的工程里按需传入多个测试二进制。这两份脚本组合起来可以进一步接入 CI 或作为 Xcode 的 Run Script 构建阶段实现构建即测试。Build and Go运行测试一切就绪后点击Build and Go测试随即执行。控制台会输出 gtest 的经典报告格式[Session started at 2008-08-06 06:36:13 -0600.] [] Running 2 tests from 1 test case. [----------] Global test environment set-up. [----------] 2 tests from WidgetInitializerTest [ RUN ] WidgetInitializerTest.TestConstructor [ OK ] WidgetInitializerTest.TestConstructor [ RUN ] WidgetInitializerTest.TestConversion [ OK ] WidgetInitializerTest.TestConversion [----------] Global test environment tear-down [] 2 tests from 1 test case ran. [ PASSED ] 2 tests. The Debugger has exited with status 0.这份输出与仓库示例 widget_test.cc 中定义的两个用例TestConstructor、TestConversion一一对应[ PASSED ] 2 tests.与exited with status 0表明全部通过。这套输出格式是可解析的CI 系统可以依据[ PASSED ]、[ FAILED ]及进程退出码判断测试结果也可以配合runtests.sh中的循环自动收集失败列表。小结单元测试是在快速迭代与大规模重构期间保证数据模型/核心逻辑始终有效的重要手段。Google Test 是面向 C/C 的优秀测试框架与 Xcode 开发环境配合良好。从本仓库携带的 V1_6_XcodeGuide.md 及其配套 xcode 工程可以看到一套完整闭环gtest.xcodeproj构建 framework → Shell Tool 测试 Target 链接框架 →DYLD_FRAMEWORK_PATH解决运行时动态库定位 →TEST/EXPECT_*编写用例 → 标准输出报告与退出码驱动 CI。适用前提提示本指南描述的是 gtest 1.6 时代 Xcode含 Shell Tool 模板、Edit Active Executable 界面的集成流程相关界面在如今的 Xcode 版本中可能已改名或迁移但链接 framework、运行时通过DYLD_FRAMEWORK_PATH指定框架搜索路径、以 gtest 标准输出与退出码判定结果这一机制至今仍是理解 Apple 平台动态框架集成的通用原理。若要在现代 macOS 上重现建议同时参考 Primer 与 AdvancedGuide 了解最新的构建方式与断言能力。【免费下载链接】miniblink49a lighter, faster browser kernel of blink to integrate HTML UI in your app. 一个小巧、轻量的浏览器内核用来取代wke和libcef项目地址: https://gitcode.com/GitHub_Trending/mi/miniblink49创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考