新闻详情

新闻详情

首页 / 资讯中心 / 详情

gRPC Python 测试实战:grpc_testing 模块 API 全解析与 Channel/Server 双打机制

发布时间:2026/9/10 9:48:08来源:尧图网络
gRPC Python 测试实战:grpc_testing 模块 API 全解析与 Channel/Server 双打机制
gRPC Python 测试实战grpc_testing 模块 API 全解析与 Channel/Server 双打机制【免费下载链接】grpcC based gRPC (C, Python, Ruby, Objective-C, PHP, C#)项目地址: https://gitcode.com/GitHub_Trending/gr/grpc本文是 gRPC Python 生态中官方测试库grpc_testing的深度指南。doc/python/sphinx/grpc_testing.rst通过 Sphinx.. automodule:: grpc_testing指令自动渲染该模块的 API 参考页面本文则以该模块源码位于 src/python/grpcio_testing/grpc_testing/init.py为骨架系统讲解其测试范式、全部公开类与工厂函数并结合仓库源码与官方单元测试说明如何用它在不启动真实服务器的情况下测试调用 RPC 的客户端代码与提供服务实现的服务器代码。读完本文你将掌握Channel/Server双打Test Double、四种 RPC 形态的 fixture 操作以及可控制的假时钟测试技术。一、文档定位一个由模块 docstring 自动生成的 API 参考页在 doc/python/sphinx/ 目录下grpc_testing.rst是整个 gRPC Python API 文档体系index.rst中的一个页面正文仅含一个 automodule 指令gRPC Testing Module Contents --------------- .. automodule:: grpc_testing这意味着该页面本身不书写代码而是由 Sphinx配置见 doc/python/sphinx/conf.py在构建时读取 Python 包grpc_testing中所有公开类、方法和函数的 docstring 生成 HTML 文档。因此这个 API 参考页的真实内容就是grpc_testing模块的公开接口定义它们全部集中在 src/python/grpcio_testing/grpc_testing/init.py约 700 行、每个成员都有完整 docstring并由 src/python/grpcio_testing/grpc_testing/ 下的_channel/、_server/、_time.py等内部模块实现。模块顶部的包说明点明了它的用途Objects for use in testing gRPC Python-using application code.即用于测试使用了 gRPC Python 的应用代码。grpc_testing在仓库里对应独立的 Python 发行包grpcio-testing见 pyproject.tomldescription 为 Testing utilities for gRPC Python仅动态依赖grpcio版本号来自 grpc_version.py。二、核心测试范式双向双打Test Double设计grpc_testing没有引入真实网络、没有启动真实进程而是在内存中模拟 gRPC 调用。它把被测系统system under test分成两类分别给出对应的替身double2.1 测试客户端侧Channel双打当被测对象是一个发起 RPC 的客户端应用时测试代码扮演服务器端。模块提供一个实现了grpc.Channel接口的Channel类签名见init.pyA grpc.Channel double with which to test a system that invokes RPCs.应用代码像使用普通 Channel 一样调用 stubUnaryUnaryStub等但真正的调用被拦截由测试线程通过Channel.take_*系列方法取出这个正在发生的 RPC再用返回的 RPC fixtureplay server扮演服务器去驱动它。2.2 测试服务器侧Server双打当被测对象是一个实现 gRPC 服务servicer的服务器端应用时测试代码扮演客户端。Server类A server with which to test a system that services RPCs.测试通过Server.invoke_*系列方法以客户端身份发起 RPC服务器端 servicer 会在后台线程被调度执行参见 src/python/grpcio_testing/grpc_testing/_server/_server.py 中_Serverish._invoke启动threading.Thread返回的 fixture 让测试play client扮演客户端逐条消费响应。2.3 时间抽象TimeRPC 存活性查询的统一入口两类双打都依赖一个抽象类TimeA simulation of time. Implementations neednt be connected with real time as provided by the Python interpreter, but as long as systems under test useRpcContext.is_activeandRpcContext.time_remainingfor querying RPC liveness implementations may be used to change passage of time in tests.即只要被测应用通过is_active()/time_remaining()判断 RPC 是否存活测试就可以通过替换Time实现来任意操控时间流逝从而稳定地测试 deadline/超时逻辑而无需真正 sleep。Time的抽象方法源码init.py包括方法语义time()返回当前测试时间该对象对此时间具有支配权call_in(behavior, delay)注册一个无参行为在delay秒后调用返回一个可取消的grpc.Futurecall_at(behavior, time)注册一个无参行为在指定的测试时间点调用返回可取消的grpc.Futuresleep_for(duration)阻塞duration秒测试时间sleep_until(time)阻塞直到指定的测试时间2.4 时间双实现真实时钟与假时钟模块顶层提供两个工厂函数创建Timestrict_real_time()以 Python 解释器真实时间为基准内部实现见 src/python/grpcio_testing/grpc_testing/_time.py 的StrictRealTime。其strict语义是注册在时刻 t 的所有回调被执行完毕之前它不会对外宣称时间已越过 t——回调由后台threading.Thread驱动_activitysleep_for/sleep_until结束后通过_ensure_called_through阻塞等待回调完成确保时序严格有序。strict_fake_time(now)完全独立于真实时钟的虚拟时间内部时间只会在测试代码调用sleep_for/sleep_until时前进实现见 src/python/grpcio_testing/grpc_testing/_time.py 的StrictFakeTime。例如sleep_for内部直接self._time duration并结算到期回调因此测试可在毫秒级真实耗时内跳过任意时长的 deadline。delay 0或目标时间早于当前时间的行为会立即在线程中执行。三、Channel 双打取走 RPC 并扮演服务器Channelgrpc_testing/init.py 中定义实现于 src/python/grpcio_testing/grpc_testing/_channel/_channel.py面向 gRPC 的四种 RPC 形态各提供一对 APItake_unary_unary(method_descriptor) # - (invocation_metadata, request, UnaryUnaryChannelRpc) take_unary_stream(method_descriptor) # - (invocation_metadata, request, UnaryStreamChannelRpc) take_stream_unary(method_descriptor) # - (invocation_metadata, StreamUnaryChannelRpc) take_stream_stream(method_descriptor)# - (invocation_metadata, StreamStreamChannelRpc)其中method_descriptor是descriptor.MethodDescriptor。若被测系统当前尚未发起该描述符对应的 RPCtake_*会阻塞等待直到被测系统发起若已被发起则立即返回。此后测试对该 RPC 拥有完全控制权。3.1 四种 play server fixture四种 channel RPC fixture 都提供send_initial_metadata(initial_metadata)把初始元数据发送给被测系统以及阻塞到被测系统取消 RPC 的cancelled()。按流式形态差异还分别提供UnaryUnaryChannelRpcterminate(response, trailing_metadata, code, details)—— 一次性给出响应、尾随元数据、状态码与详情并结束 RPC。UnaryStreamChannelRpcsend_response(response)可多次发送流式响应最后terminate(trailing_metadata, code, details)无 response 参数。StreamUnaryChannelRpctake_request()依次取出被测系统发来的请求阻塞直到有请求且保持被测系统添加的顺序、requests_closed()阻塞直到被测系统关闭请求流再terminate(response, ...)给出最终响应。StreamStreamChannelRpc同时拥有take_request()/requests_closed()收请求与send_response(response)发响应最后以terminate(trailing_metadata, code, details)收尾。3.2 实测官方测试中的 Channel 用法仓库自测用例 src/python/grpcio_tests/tests/testing/_client_test.py 完整演示了这一模式被测客户端应用被提交到独立线程执行测试线程保留用于扮演服务器self._real_time_channel grpc_testing.channel( services_pb2.DESCRIPTOR.services_by_name.values(), self._real_time) def test_successful_unary_unary(self): application_future self._client_execution_thread_pool.submit( _client_application.run, _client_application.Scenario.UNARY_UNARY, self._real_time_channel) (invocation_metadata, request, rpc) self._real_time_channel.take_unary_unary( _application_testing_common.FIRST_SERVICE_UNUN) rpc.send_initial_metadata(()) rpc.terminate(_application_common.UNARY_UNARY_RESPONSE, (), grpc.StatusCode.OK, ) application_return_value application_future.result() self.assertEqual(_application_common.UNARY_UNARY_REQUEST, request)流式一侧同理同文件test_successful_stream_unarytake_stream_unary后依次rpc.take_request()收取多份请求、rpc.requests_closed()确认客户端关闭请求流、最后rpc.terminate(response, (), grpc.StatusCode.OK, )。借助这种取出-断言-应答三步法客户端应用的状态转换Outcome与请求内容都能被精确验证。四、Server 双打扮演客户端驱动 servicer当被测对象是 servicer 实现时用顶层工厂server_from_dictionary(descriptors_to_servicers, time)构造Serverdescriptors_to_servicers: 一个从descriptor.ServiceDescriptor描述 RPC 服务到 servicer 对象通常是生成的_pb2_grpc模块中实现 Servicer 接口的类实例的字典。其实现src/python/grpcio_testing/grpc_testing/_server/_server.py通过_implementation()完成descriptor → servicer → 方法的映射servicer descriptors_to_servicers[method_descriptor.containing_service]再getattr(servicer, method_descriptor.name)取出对应处理器随后在独立线程中调用它并把一个封装了测试Time与 deadline 的ServicerContext传入 servicer。Server提供四个调用入口全部接收method_descriptor、invocation_metadata、可选的timeout秒传None表示无时限并返回对应的 play client fixtureinvoke_unary_unary(method_descriptor, invocation_metadata, request, timeout) # - UnaryUnaryServerRpc invoke_unary_stream(method_descriptor, invocation_metadata, request, timeout) # - UnaryStreamServerRpc invoke_stream_unary(method_descriptor, invocation_metadata, timeout) # - StreamUnaryServerRpc invoke_stream_stream(method_descriptor, invocation_metadata, timeout) # - StreamStreamServerRpc超时处理逻辑位于_deadline_and_handler同文件timeout is None时构造无 deadline 的 handler否则deadline time.time() timeout并构造带 deadline 的 handler —— 这正是Time抽象的价值使用strict_fake_time时deadline 同样基于可控的假时间计算。四种 server RPC fixture 的共同点是initial_metadata()阻塞获取被测服务器发出的初始元数据若服务器先给出响应或已结束 RPCgRPC Python 会为其合成初始元数据、cancel()取消 RPC与termination()阻塞至服务器结束返回(trailing_metadata, code, details)序列UnaryUnary与StreamUnary的termination()返回的元组还包含最终response。差异点Fixture额外方法用途UnaryUnaryServerRpc—单请求单响应UnaryStreamServerRpctake_response()逐条取走服务器推来的流式响应StreamUnaryServerRpcsend_request(request)、requests_closed()发送请求流并声明结束StreamStreamServerRpcsend_request(request)、requests_closed()、take_response()全双工边发请求边收响应对应源码的断言由 src/python/grpcio_tests/tests/testing/_server_test.py 覆盖该目录下的 src/python/grpcio_tests/tests/testing/proto/services.proto 与requests.proto提供测试用服务与消息定义。五、组装全套一个最小可用示例参考官方测试的编排方式下面给出同时覆盖服务端测试的骨架以_server_test.py的风格与init.py 公开 API 为准import time import unittest import grpc import grpc_testing # 假设以下来自你的 proto 生成代码 from helloworld import helloworld_pb2 from helloworld import helloworld_pb2_grpc class GreeterServicer(helloworld_pb2_grpc.GreeterServicer): def SayHello(self, request, context): return helloworld_pb2.HelloReply(messageHi request.name) class ServerSideTest(unittest.TestCase): def setUp(self): servicer GreeterServicer() # descriptor - servicer 字典 descriptors_to_servicers { helloworld_pb2.DESCRIPTOR.services_by_name[Greeter]: servicer, } # 假时间测试代码完全掌控时间推进 self._fake_time grpc_testing.strict_fake_time(time.time()) self._server grpc_testing.server_from_dictionary( descriptors_to_servicers, self._fake_time) self._method helloworld_pb2.DESCRIPTOR.services_by_name[ Greeter].methods_by_name[SayHello] def test_say_hello(self): rpc self._server.invoke_unary_unary( self._method, (), helloworld_pb2.HelloRequest(nameworld), None) response, trailing_metadata, code, details rpc.termination() self.assertEqual(response.message, Hi world) self.assertIs(code, grpc.StatusCode.OK)要点server_from_dictionary的键来自DESCRIPTOR.services_by_name值是对应的 servicer 实例方法描述符同样可经methods_by_name取出。客户端侧的对称写法是grpc_testing.channel(services_by_name.values(), time)配合take_unary_unary。六、模块结构与源码阅读路线grpc_testing公开表面很小全部定义于 src/python/grpcio_testing/grpc_testing/init.py内部按职责拆分src/python/grpcio_testing/ ├── grpc_testing/ │ ├── __init__.py # 全部公开 ABC 与工厂函数模块 docstring 即 Sphinx 页面内容 │ ├── _channel/ # Channel 双打_channel/_channel_rpc/_channel_state/ │ │ # _invocation/_multi_callable/_rpc_state │ ├── _server/ # Server 双打_server/_server_rpc/_service/_handler/ │ │ # _servicer_context │ ├── _common.py # 共享基类如 Serverish │ └── _time.py # StrictRealTime / StrictFakeTime ├── README.rst # 包说明依赖 grpcio ├── pyproject.toml # 发行包名 grpcio-testing └── setup.py想了解 Channel 双打如何拦截 stub 调用读 _channel/_multi_callable.py 与 _channel/_invocation.py。想了解状态流转与阻塞语义读 _channel/_channel_state.py基于threading.Condition管理每个 RPC 状态这解释了take_*为何能阻塞等待。想了解 servicer 侧调度与 deadline读 _server/_server.py线程调度 _deadline_and_handler与 _server/_servicer_context.py。想了解假时钟如何实现 strict 回调语义读 _time.py_process结算到期行为、_call_in_thread保证回调执行完毕才推进时间。端到端断言参考src/python/grpcio_tests/tests/testing/_client_test.py、_server_test.py 与 _time_test.py。七、安装与文档体系中的位置grpcio-testing是独立发行包按 README.rst 说明它依赖grpcio常规安装方式为pip install grpcio grpcio-testing两者版本由 pyproject.toml 统一从 grpc_version.py 动态派生保证与主库版本一致。使用前需先用grpcio-tools生成*_pb2.py与*_pb2_grpc.py。在文档树中本文所述 API 页面对应的 RST 源文件为 doc/python/sphinx/grpc_testing.rst与 grpc.rst核心grpc包、grpc_asyncio.rst异步 API、grpc_health_checking.rst 等页面共同构成完整的 Python API 参考。构建完整文档时Sphinxconf.py会为grpc_testing页面自动生成本文第三、四、五节所述的每一个类与方法的签名和说明这也解释了为何 RST 源文件如此精简——它把权威内容托管在源码 docstring 中保证 API 参考永不与实现脱节。八、适用边界与设计取舍grpc_testing面向单元/组件级测试它不做真实的网络 I/O、不验证传输层行为因此不适合替代端到端互操作测试。若需验证真实协议行为应转向仓库test/下的端到端用例或真实服务器集成测试。Channel/Server双打都是内存内且同步可控的天然适合把测试代码与被测应用放在不同线程由测试线程以阻塞式剧本推进交互如官方 _client_test.py 那样。测试 deadline 类行为时优先选用strict_fake_time调用sleep_for即可瞬间推进服务器可见的时钟让超时路径在毫秒级真实时间内被可靠触发需要贴近真实调度的场景再用strict_real_time。总而言之grpc_testing用一套小而美的抽象两类双打 一个可替换的时间源覆盖了 gRPC Python 应用测试的绝大部分需求。把握住谁是被测方、谁在扮演对端以及一切时序都以Time为准这两条主线再对照本文给出的 fixture 方法表即可写出确定性强、执行迅速且不依赖任何外部服务的 gRPC 单元测试。【免费下载链接】grpcC based gRPC (C, Python, Ruby, Objective-C, PHP, C#)项目地址: https://gitcode.com/GitHub_Trending/gr/grpc创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

OpenSSL 测试开发指南:为 test/recipes 编写 TAP 测试脚本与 C 测试可执行程序 2026/9/10 10:33:15

OpenSSL 测试开发指南:为 test/recipes 编写 TAP 测试脚本与 C 测试可执行程序

OpenSSL 测试开发指南:为 test/recipes 编写 TAP 测试脚本与 C 测试可执行程序 【免费下载链接】openssl General purpose TLS and crypto library 项目地址: https://gitcode.com/GitHub_Trending/ope/openssl 本文以 OpenSSL 仓库 test/README-dev.md 为核…

阅读更多 →
数字信号编码从NRZ到8B/10B:物理层比特映射与工程选型详解 2026/9/10 10:33:15

数字信号编码从NRZ到8B/10B:物理层比特映射与工程选型详解

做嵌入式、通信或者底层硬件开发的同行,应该都有过这种时刻:拿着示波器戳在芯片引脚上,明明协议栈里跑的全是0和1的逻辑,示波器上却是一串完全不认识的电平波形;翻了大半天手册,最后发现问题是出在物理层编…

阅读更多 →
【单片机毕业设计】基于 STM32 或 51 单片机人体感应节能台灯监测系统设计 基于 STM32 或 51 单片机的坐姿检测与灯光调控系统设计(021407) 2026/9/10 10:33:15

【单片机毕业设计】基于 STM32 或 51 单片机人体感应节能台灯监测系统设计 基于 STM32 或 51 单片机的坐姿检测与灯光调控系统设计(021407)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机,Java、小程序技术领域和毕业项目实战 ✌️…

阅读更多 →
CANN/GE图引擎设置图int64属性API 2026/9/10 10:33:15

CANN/GE图引擎设置图int64属性API

EsSetInt64AttrForGraph 【免费下载链接】ge GE(Graph Engine)是面向昇腾的图编译器和执行器,提供了计算图优化、多流并行、内存复用和模型下沉等技术手段,加速模型执行效率,减少模型内存占用。 GE 提供对 PyTorch、Te…

阅读更多 →
STM32F103C8T6智能小车测速与距离计算:编码器、定时器与单位换算调参指南 2026/9/10 10:33:15

STM32F103C8T6智能小车测速与距离计算:编码器、定时器与单位换算调参指南

简介:STM32F103C8T6智能小车测速与行驶距离显示实验的完整程序源码包,适合嵌入式入门学习者与小车DIY爱好者参考。程序基于Keil4环境编写,适配STM32F103C8T6主控,配合L293D电机驱动、TT直流减速电机、测速模块及OLED屏&#xff0c…

阅读更多 →
SEO优化预算全解析:从几千到几万,钱到底花在哪? 2026/9/10 10:30:15

SEO优化预算全解析:从几千到几万,钱到底花在哪?

1. 先搞懂预算差异的根源:同样叫SEO,报价为什么能差出百倍我做SEO这行十几年,每隔几天就会接到一次类似的咨询,开场白通常是这样:"我看网上有人做SEO两千块一个月,也有人说花了十几万没效果&#xff0…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞