发布信息

软件测试之gRPC接口测试详解

作者:本站编辑      2024-02-21 12:25:43     39

来源:51CTO博客

gRPC是什么?

  gRPC是什么可以用官网的一句话来概括:

  A high-performance, open-source universal RPC framework

  所谓RPC(remote procedure call 远程过程调用)框架实际是提供了一套机制,使得应用程序之间可以进行通信,而且也遵从server/client模型。使用的时候客户端调用server端提供的接口就像是调用本地的函数一样。如下图所示就是一个典型的RPC结构图

  gRPC有什么好处以及在什么场景下需要用gRPC

  既然是server/client模型,那么我们直接用restful api不是也可以满足吗,为什么还需要RPC呢?下面我们就来看看RPC到底有哪些优势

  gRPC vs. Restful API

  gRPC和restful API都提供了一套通信机制,用于server/client模型通信,而且它们都使用http作为底层的传输协议(严格地说, gRPC使用的http2.0,而restful api则不一定)。不过gRPC还是有些特有的优势,如下:

  gRPC可以通过protobuf来定义接口,从而可以有更加严格的接口约束条件。关于protobuf可以参见笔者之前的小文Google Protobuf简明教程

  另外,通过protobuf可以将数据序列化为二进制编码,这会大幅减少需要传输的数据量,从而大幅提高性能。

  gRPC可以方便地支持流式通信(理论上通过http2.0就可以使用streaming模式, 但是通常web服务的restful api似乎很少这么用,通常的流式数据应用如视频流,一般都会使用专门的协议如HLS,RTMP等,这些就不是我们通常web服务了,而是有专门的服务器应用。)

  使用场景

  需要对接口进行严格约束的情况,比如我们提供了一个公共的服务,很多人,甚至公司外部的人也可以访问这个服务,这时对于接口我们希望有更加严格的约束,我们不希望客户端给我们传递任意的数据,尤其是考虑到安全性的因素,我们通常需要对接口进行更加严格的约束。这时gRPC就可以通过protobuf来提供严格的接口约束。

  对于性能有更高的要求时。有时我们的服务需要传递大量的数据,而又希望不影响我们的性能,这个时候也可以考虑gRPC服务,因为通过protobuf我们可以将数据压缩编码转化为二进制格式,通常传递的数据量要小得多,而且通过http2我们可以实现异步的请求,从而大大提高了通信效率。

  但是,通常我们不会去单独使用gRPC,而是将gRPC作为一个部件进行使用,这是因为在生产环境,我们面对大并发的情况下,需要使用分布式系统来去处理,而gRPC并没有提供分布式系统相关的一些必要组件。而且,真正的线上服务还需要提供包括负载均衡,限流熔断,监控报警,服务注册和发现等等必要的组件。不过,这就不属于本篇文章讨论的主题了,我们还是先继续看下如何使用gRPC。

  gRPC HelloWorld实例详解

  gRPC的使用通常包括如下几个步骤:

  1. 通过protobuf来定义接口和数据类型

  2. 编写gRPC server端代码

  3. 编写gRPC client端代码

  下面来通过一个实例来详细讲解上述的三步。

  下边的hello world实例完成之后,其目录结果如下:

  定义接口和数据类型

  通过protobuf定义接口和数据类型:

  syntax = "proto3";  package rpc_package;  // define a service  service HelloWorldService {      // define the interface and data type      rpc SayHello (HelloRequest) returns (HelloReply) {}  }  // define the data type of request  message HelloRequest {      string name = 1;  }  // define the data type of response  message HelloReply {      string message = 1;  }

  使用gRPC protobuf生成工具生成对应语言的库函数:

  python -m grpc_tools.protoc -I=./protos --python_out=./rpc_package --grpc_python_out=./rpc_package ./protos/user_info.proto

  这个指令会自动生成rpc_package文件夹中的helloworld_pb2.py和helloworld_pb2_grpc.py,但是不会自动生成__init__.py文件,需要我们手动添加。

  gRPC server端代码

  #!/usr/bin/env python  # -*-coding: utf-8 -*-  from concurrent import futures  import grpc  import logging  import time  from rpc_package.helloworld_pb2_grpc import add_HelloWorldServiceServicer_to_server, \       HelloWorldServiceServicer  from rpc_package.helloworld_pb2 import HelloRequest, HelloReply  class Hello(HelloWorldServiceServicer):      # 这里实现我们定义的接口      def SayHello(self, request, context):          return HelloReply(message='Hello, %s!' % request.name)  def serve():      # 这里通过thread pool来并发处理server的任务      server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))      # 将对应的任务处理函数添加到rpc server中      add_HelloWorldServiceServicer_to_server(Hello(), server)      # 这里使用的非安全接口,世界gRPC支持TLS/SSL安全连接,以及各种鉴权机制      server.add_insecure_port('[::]:50000')      server.start()      try:          while True:              time.sleep(60 * 60 * 24)      except KeyboardInterrupt:          server.stop(0)  if __name__ == "__main__":      logging.basicConfig()      serve()

  gRPC client端代码

  #!/usr/bin/env python  # -*- coding: utf-8 -*-  from __future__ import print_function  import logging  import grpc  from rpc_package.helloworld_pb2 import HelloRequest, HelloReply  from rpc_package.helloworld_pb2_grpc import HelloWorldServiceStub  def run():      # 使用with语法保证channel自动close      with grpc.insecure_channel('localhost:50000') as channel:          # 客户端通过stub来实现rpc通信          stub = HelloWorldServiceStub(channel)          # 客户端必须使用定义好的类型,这里是HelloRequest类型          response = stub.SayHello(HelloRequest(name='eric'))      print ("hello client received: " + response.message)  if __name__ == "__main__":      logging.basicConfig()      run()

  演示

  先执行server端代码:

  python hello_server.py

  接着执行client端代码如下:

 

    grpc_test python hello_client.py  hello client received: Hello, eric!

本书第1章与第2章介绍软件单元测试的概念和基础知识。

  • 第1章简单介绍软件单元测试所包含的概念,包括桩对象和测试驱动函数、测试驱动开发、软件测试贯彻始终、软件测试金字塔、单元测试在传统/敏捷开发模式中的地位、精准测试、单元测试和白盒测试,以及单元测试的FIRST原则和AIR原则。

  • 第2章介绍软件单元测试基础知识,包括动态自动化/手工单元测试、静态自动化/手工单元测试。在动态自动化单元测试中介绍了语句覆盖、分支覆盖、条件覆盖、条件/分支覆盖、MC/DC、路径覆盖和控制流覆盖。

第3章到第5章介绍C语言、Java语言和Python语言的单元测试框架。

  • 第3章介绍C语言动态自动化单元测试框架,包括在Windows下安装C语言运行环境、在Windows和Linux下安装编译CUnit、查看测试报告、CUnit介绍和案例。

  • 第4章介绍Java语言动态自动化单元测试框架,包括在Eclipse中创建Maven项目和配置JUnit与TestNG运行环境、JUnit 4测试框架、JUnit 5测试框架、TestNG测试框架、测试替身、变异测试、利用EvoSuite自动生成测试用例,以及在Jenkins中配置JUnit 4、JUnit 5、TestNG和Allure。

  • 第5章介绍Python语言动态自动化单元测试框架,包括unittest、Pytest及Python的模拟对象和变异测试工具mutpy。

第6章与第7章介绍代码覆盖率工具和代码语法规范检查工具。

  • 第6章介绍代码覆盖率工具,包括C语言覆盖率工具gcov和lcov、Java语言覆盖率工具JaCoCo,以及Python语言覆盖率工具Coverage和pytest-cov。

  • 第7章介绍代码语法规范检查工具,包括Java语言静态分析工具PMD、Python语言静态分析工具flake8和pylint,以及多代码语法规范检查平台SonarQube。

  • 第8章通过两个案例详细介绍TDD。

    读者可以根据自己的需求对以上内容进行选择性阅读或者全部阅读。另外,为了巩固大家的学习效果,每一章结尾都有相应的习题。

顾翔凡言:几年以后,测试工程师的工作主要集中在测试设计和分析上面,而测试的脚本编写和执行主要交给AI来实现。

相关内容 查看全部