拓冰建站拓冰建站
首页 / 资讯中心 / 正文

gRPC C++ 测试在 iOS 上的移植指南:GTMGoogleTestRunner 桥接、测试改造与限制解析

gRPC C 测试在 iOS 上的移植指南GTMGoogleTestRunner 桥接、测试改造与限制解析【免费下载链接】grpcC based gRPC (C, Python, Ruby, Objective-C, PHP, C#)项目地址: https://gitcode.com/GitHub_Trending/gr/grpc导读本文面向在 iOS 平台上运行 gRPC C 测试的开发者聚焦于 gRPC 仓库中 C 测试如何通过 GTMGoogleTestRunner 桥接到 XCTest、如何在保持 googletest 语义的同时完成测试用例改造以及这一方案固有的行为限制。读完本文你将掌握将仓库现有 C 测试移植到 iOS 的标准步骤理解main函数、SetUpTestCase/TearDownTestCase与 gRPC 初始化/销毁在 iOS 环境下的正确组织方式并能在移植时规避 Death Tests 不支持等常见坑点。本文主体内容整理自仓库文档 test/cpp/README-iOS.md并以仓库中真实存在的测试代码与源码实现作为佐证。背景为什么 iOS 上的 C 测试需要特殊处理gRPC 仓库中的 C 测试大量基于 googletest 编写例如 test/cpp/util/cli_call_test.cc、test/cpp/util/byte_buffer_test.cc 等其惯用结构是在main函数中依次完成 gRPC 测试环境初始化、googletest 初始化然后调用RUN_ALL_TESTS()运行全部用例。但在 iOS 平台上测试是通过 XCTest 框架运行的普通的可执行文件入口main并不会被直接执行。为此gRPC 项目采用GTMGoogleTestRunnerGoogle Toolbox for Mac 中的UnitTesting/GTMGoogleTestRunner.mm将 googletest 用例转换为可在 iOS 上运行的 XCTest。这一桥接机制决定了 iOS 上 C 测试代码的写法与桌面平台有显著差异main不会被真正执行GTMGoogleTestRunner 负责发现并驱动 googletest 用例因此任何放在main里的测试逻辑都无法生效。::testing::InitGoogleTest仍可安全调用GTMGoogleTestRunner 内部本身会调用InitGoogleTest因此在main中调用它不会产生冲突。grpc::testing::TestEnvironment也可在main中创建它执行的是锦上添花式的测试初始化安装崩溃处理器、以进程 PID 为随机数种子等对 iOS 上运行用例并非严格必需。认识grpc::testing::TestEnvironment文档中反复提及的grpc::testing::TestEnvironment定义于 test/core/test_util/test_config.h// A TestEnvironment object should be alive in the main function of a test. It // provides test init and shutdown inside. class TestEnvironment { public: TestEnvironment(int* argc, char** argv); ~TestEnvironment(); };其构造与析构实现位于 test/core/test_util/test_config.ccTestEnvironment::TestEnvironment(int* argc, char** argv) { grpc_test_init(argc, argv); } TestEnvironment::~TestEnvironment() { // This will wait until gRPC shutdown has actually happened to make sure // no gRPC resources (such as thread) are active. (timeout 10s) if (!grpc_wait_until_shutdown(10)) { LOG(ERROR) Timeout in waiting for gRPC shutdown; } ... }从源码可以看到它实际完成的工作构造时调用grpc_test_inittest/core/test_util/test_config.cc#L144-L168后者依次完成初始化 absl 日志、ParseTestArgs解析测试参数、初始化栈追踪器、安装FailureSignalHandler崩溃信号处理器对应文档所说的 install crash handler、以及srand(seed())用进程 PID 作为随机数种子对应文档所说的 seed RNG。析构时调用grpc_wait_until_shutdown(10)等待 gRPC 完全关闭最多 10 秒确保没有 gRPC 资源如线程残留。仓库中大量测试的main都遵循这一标准写法例如 test/cpp/util/grpc_tool_test.cc#L1452-L1456int main(int argc, char** argv) { grpc::testing::TestEnvironment env(argc, argv); ::testing::InitGoogleTest(argc, argv); GTEST_FLAG_SET(death_test_style, threadsafe); return RUN_ALL_TESTS(); }将既有 C 测试移植到 iOS 的改造指南按照 test/cpp/README-iOS.md 的说明移植现有 C 测试到 iOS 需遵循以下三条准则测试必须使用 googletest 框架这是 GTMGoogleTestRunner 能够识别与桥接的前提。main中的 setup/teardown 逻辑必须迁移任何初始化/清理代码都要从main移到SetUpTestCase/TearDownTestCase同时将TEST改为TEST_F即从独立测试宏改为 fixture 测试宏。Death Tests 在 iOS 上不受支持应使用*_IF_SUPPORTED()系列宏如ASSERT_DEATH_IF_SUPPORTED确保代码在 iOS 上能够编译通过。改造示例从TESTmain到TEST_F fixture文档给出了一个完整的改造前后对照。改造前的典型写法如下TEST(MyTest, TestOne) { ASSERT_DEATH(ThisShouldDie(), ); } int main(int argc, char** argv) { grpc::testing::TestEnvironment env(argc, argv); ::testing::InitGoogleTest(argc, argv); grpc_init(); return RUN_ALL_TESTS(); grpc_shutdown(); // 注意这行永远不会执行到 }这段代码存在两个 iOS 问题grpc_init()放在main中不会被 GTMGoogleTestRunner 执行grpc_shutdown()写在return之后属于不可达代码且即便可达在 iOS 桥接下也无从保证。改造后的正确写法如下class MyTest : public ::testing::Test { protected: static void SetUpTestCase() { grpc_init(); } static void TearDownTestCase() { grpc_shutdown(); } }; TEST_F(MyTest, TestOne) { ASSERT_DEATH_IF_SUPPORTED(ThisShouldDie(), ); } int main(int argc, char** argv) { grpc::testing::TestEnvironment env(argc, argv); ::testing::InitGoogleTest(argc, argv); return RUN_ALL_TESTS(); }改造要点将grpc_init()/grpc_shutdown()从main移入静态成员函数SetUpTestCase/TearDownTestCase由 googletest 框架按 fixture 生命周期调用将TEST改为TEST_F并让测试类继承::testing::Test将ASSERT_DEATH替换为ASSERT_DEATH_IF_SUPPORTED保证在不支持 Death Tests 的平台如 iOS上仍能编译。gRPC 仓库自身也大量使用SetUpTestCase/TearDownTestCase模式组织 fixture 生命周期这与文档给出的改造方向一致。已知限制fixture 静态方法按每个用例调用文档最后明确指出一个 GTMGoogleTestRunner 的已知限制由于 GTMGoogleTestRunner.mm#L48-L56 的实现方式SetUpTestCase/TearDownTestCase会在每一个独立测试用例前后被调用其行为与SetUp/TearDown类似而不是按 googletest 语义中每个 fixture 类只调用一次。这一差异的实践含义是在 iOS 上编写 fixture 的初始化/清理逻辑时不能假设SetUpTestCase只执行一次。如果初始化逻辑有副作用例如grpc_init()这类全局状态操作或对性能敏感例如建立重量级资源需要意识到它会被反复执行。从仓库源码看grpc_init/grpc_shutdown配对在测试代码中频繁出现如 test/core/test_util/test_config.cc#L235-L242 中的TestGrpcScope封装了同样的配对逻辑在 iOS 的反复调用场景下更要确保其可重入、无累积副作用。移植实践建议结合文档与仓库现状移植 C 测试到 iOS 时可参考以下清单确认测试基于 googletest确保测试文件包含 googletest 头文件并使用TEST/TEST_F宏。收敛main的职责main中只保留grpc::testing::TestEnvironment、::testing::InitGoogleTest和RUN_ALL_TESTS()三件套其余初始化逻辑全部迁移至 fixture。用*_IF_SUPPORTED()包裹 Death Test 断言如ASSERT_DEATH_IF_SUPPORTED、EXPECT_DEATH_IF_SUPPORTED确保 iOS 编译通过。注意SetUpTestCase/TearDownTestCase的反复调用语义初始化逻辑应幂等且轻量避免依赖只执行一次的假设。善用仓库现有工具TestEnvironmenttest/core/test_util/test_config.h与TestGrpcScopetest/core/test_util/test_config.cc#L235-L242封装了 gRPC 测试初始化与关闭的标准逻辑移植时可复用其模式。小结gRPC 仓库通过 GTMGoogleTestRunner 将 googletest 桥接为 iOS 上的 XCTest这决定了 iOS 测试代码必须遵循main只做环境初始化、业务 setup/teardown 全部下沉到 fixture、Death Tests 用兼容宏的改造范式。grpc::testing::TestEnvironment提供的崩溃处理器安装、RNG 播种与关闭等待能力见 test/core/test_util/test_config.cc在 iOS 上虽非严格必需但依然是保持跨平台行为一致性的推荐做法。与此同时务必牢记 GTMGoogleTestRunner 将SetUpTestCase/TearDownTestCase按单个用例反复调用的限制并在编写 fixture 时做出相应设计。这套方法论同样适用于其他以 XCTest 承载 googletest的 Apple 平台测试场景。【免费下载链接】grpcC based gRPC (C, Python, Ruby, Objective-C, PHP, C#)项目地址: https://gitcode.com/GitHub_Trending/gr/grpc创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门