用Python进行gRPC接口测试(三)

在近期的测试中,小编又遇到了一些关于grpc接口的测试,踩了一些坑,也总结了一些经验,想与大家分享交流一下。本期我们主要来谈谈有关protobuf中一些特殊数据类型在python中的处理方式。由于目前protobuf3已经成为主流,本文将直接以proto3进行探讨。

一、标量值类型

标量值类型与我们在编程语言使用的基本数据类型概念类似,用来携带的数据也大体相同。在python中,这些标量值类型都能找到与之对应的python数据类型,处理起来简单便捷。

图片

使用举例:


message Student {

  string name = 1;

  int32 age = 2;

  // true: male, false:female

  bool sex = 3;

}

Python实现代码:


name="小王"

age=15

sex=True


#方式1

student=Student(name=name,age=age,sex=sex)


#方式2

student=Student()

student.name=name

student.age=age

student.sex=sex

二、一些特殊类型

除了上面提到的标量值类型,proto3中还定义了其他一些特殊的数据类型,方便我们用来构造、传递各种复杂的数据结构。官方给出了一个关于这些类型的JSON映射表,可以直观地看到各种类型所含数据的基本结构。

图片

这些类型使得我们可以方便地构造出各种各样的数据形式。这其中有几个较为常用的类型,在小编进行的测试中经常遇到,下面我们就结合实际中的例子来为大家介绍一下。

1、message

message,根据映射表我们可以看到,它类似于我们在编程语言中所使用的类的对象(object)。在一个类中,我们可以添加各种其他类型的数据,也包括类本身。通过类比,message也有类似的概念,我们可以在里面添加各种proto类型的数据,也包括message。其实正如message的名字一样——消息,它是protobuf中的核心类型,在grpc接口中,我们正是通过发送和接收消息来完成数据交互,来实现对应的功能。

简单的message:


message Person {

   int32 id = 1;

   string name = 2;

   string email = 3;

}

含其他message的message:


message Point {

    int32 latitude = 1;

    int32 longitude = 2;

}


message Feature {

    string name = 1;

    Point location = 2;

}

在Python中的使用:


location=Point(latitude=5,longitude=10)

Feature=Feature(name="我是个名字",location=location)
2、Timestamp、Duration

这两种类型都是关于时间的,Timestamp是时间戳,Duration表示的时间长度。

在AI平台账号服务的测试中,某Account类型的message定义如下:


location=Point(latitude=5,longitude=10)

Feature=Feature(name="我是个名字",location=location)

在Python中的使用:


update_at=Timestamp()

#从字符串获取

update_at.FromJsonString("1970-01-01T00:00:00Z")

#获取当前时间

update_at.GetCurrentTime()


time_limit=Duration()

#从纳秒转换

time_limit.FromNanoseconds(1999999999)

#从秒转换

time_limit.FromSeconds(100)


account=Account(account_id="account1",update_at=update_at,time_limit=time_limit)
3、Any

Any类型比较特殊,它可以包含不同的message,结合pack和unpack,只需声明一个Any,即可传递各种类型的message而不用声明多个字段。

在大会同传项目中,某个请求的message中需要传递两种信息——图片和音频,于是通过Any类型来实现同一字段的复用:


message ImageData {

    string index = 1;

    bytes  image = 2;

}


message Data {

    string appid = 1;

    bytes payload = 2;

    string extra = 3;

}


message Request {

    google.protobuf.Any body = 1;

}

在Python中的使用:


imageData=msg_pb2.ImageData(index="001",image=open("1.jpg","rb").read())

req1=msg_pb2.Request()

req1.body.Pack(imageData)


data=msg_pb2.Data(name="no.1",payload=open("1.wav","rb").read(),extra="no use")

req=msg_pb2.Request()

req.body.Pack(data)
4、enum

enum枚举类型和其他大多数编程语言的枚举类型概念相同,主要是通过提前设定好一些固定的值来限定可以传递的内容。

在AI平台实名认证服务的测试中,需要一个认证人类型的字段,由于认证人类型收敛,于是使用enum类型来定义:


enum PersonType {

  PERSONTYPE_UNSPECIFIED = 0;

  INDIVIDUAL = 1;

  LEGAL = 2;

  AUTHORIZE = 3;

}


message Person {

  string real_name = 1;               

  PersonType person_type = 2;

}

在Python中的应用:


person_type=PersonType.Value("INDIVIDUAL")

Person(real_name="小王",person_type=person_type)
5、map

map相当于json中的键值对,在Python中类似于字典(dict),我们可以利用Python的dict类型数据来对map进行设置。map在proto中声明时一般会带有尖括号,来指定key和value的具体类型,如map就表示键值对的key、value都为string类型。

在AI平台鉴权相关的测试中,需要为用户创建的应用绑定若干个不同的特殊属性,每个特殊属性对应着一个属性值,此处采用了map类型:


message App {

  string appid = 1;

  map<string, string> extra_informations = 2;

}

在Python中的应用:


extra_informations={"name":"app1","expired":"no"}

app=App(appid="1234567", extra_informations=extra_informations)
6、repeated

repeated相当于json中的list,在Python中类似于列表(list),我们可以利用Python的list类型数据来对repeated进行设置。

在AI平台账号服务的测试中,需要为账号添加各种不同的能力,每个能力有多个属性,而每个能力属性的种类和数据类型一致。此处采用了repeated类型:


message Audience {

  string name = 1;

  string tier = 2;

}


message Account {

  string account_id = 1;

  repeated Audience audience = 2;

}

在Python中的应用:


audience=[{"name":"ASR","tier":"stand"},{"name":"TTS","tier":"free"},{"name":"MT","tier":"stand"}]

account=Account(account_id="account1",audience=audience)

三、实际应用中的问题与技巧

1、repeated类型赋值问题

如果把上面所讲repeated类型例子中的Python代码改成如下形式,那么在运行时会报错:


audience=[{"name":"ASR","tier":"stand"},{"name":"TTS","tier":"free"},{"name":"MT","tier":"stand"}]

account=Account(account_id="account1")

account.audience=audience

错误信息:

AttributeError: Assignment not allowed to repeated field "name" in protocol message object.

这与我们上面所说的message的两种赋值方式似乎有所出入,但事实是因为protobuf中的repeated类型并不是我们想象的那样与python中的list完全对应,因此在这里会出现问题。所以在实际应用中,我们应避免这种写法,尽量采用上面例子中的方式。另外我们还可以采用另外一种方式来达到同样的效果:


audience=[{"name":"ASR","tier":"stand"},{"name":"TTS","tier":"free"},{"name":"MT","tier":"stand"}]

for audience1 in audience:

    a=account.audience.add()

    a.name=audience1['name']

    a.tier=audience1['tier']

2、复杂message的数据构造问题

在实际测试的接口中,有时某个message的结构可能会非常复杂,比如像语音识别服务一些接口,协议里包含很多不同的message和repeated类型,这样对于我们编写测试客户端代码以及构造case、解析case都会有一些影响。之前我们介绍过使用命令行的方式传递参数的方式显然难以满足这种情景下的需求,手动拼message的方式也显得十分不便。

经过一番调研发现,对于这种情况,我们可以使用protobuf库中json_format里面的Parse、MessageToJson两个方法来有效解决,这两个方法可以实现protobuf message和json的互转。因为处理json的方式有很多,也很灵活,因此我们在构造case时可以使用json的方式,通过Parse方法直接将json转换成message。在收到返回结果之后,可以使用MessageToJson方法将message转换成json,这样对于我们测试人员来说,发送和接收的数据看起来都是json,无论是准备测试数据还检验结果都会轻松不少。

示例:


from google.protobuf import json_format

json_obj='{"a1":1,"a2":2}'

request = json_format.Parse(json_obj,MessageName())

json_result = json_format.MessageToJson(request)

print (json_result)

其中MessageName为message的名称,json_result为转为json后的返回结果。

小结

本文介绍了protobuf数据类型与Python数据类型的一些联系以及构造方法。结合前面两篇所介绍的四种gRPC接口测试请求方法,我们就可以构造各种类型的数据、对各种不同的gRPC接口进行测试了。

行动吧,在路上总比一直观望的要好,未来的你肯定会感 谢现在拼搏的自己!如果想学习提升找不到资料,没人答疑解惑时,请及时加入扣群: 320231853,里面有各种软件测试+开发资料和技术可以一起交流学习哦。

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!

  • 28
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: GRPC是一种高性能、开源的远程过程调用(RPC)框架。在Python中使用GRPC可以在服务器之间传输信息。首先需要安装GRPC库,然后使用Protocol Buffer编写服务器和客户端之间的接口文件。最后在代码中使用GRPC API来连接服务器并进行信息传输。 ### 回答2: 在python编程中通过gRPC协议在服务器之间传输信息,可以按照以下步骤进行: 1. 安装gRPC库:首先需要在Python环境中安装gRPC库,可以通过执行命令`pip install grpcio`来完成。 2. 定义gRPC服务接口:使用Protocol Buffers(protobuf)语言来定义gRPC服务接口。protobuf是一种用于序列化结构化数据的语言,它将消息和服务定义为.proto文件。在.proto文件中,可以定义服务的请求和响应消息以及服务接口。例如,可以定义一个简单的消息类型和一个接口: ```proto syntax = "proto3"; message Request { string message = 1; } message Response { string message = 1; } service MyService { rpc SendMessage(Request) returns (Response) {} } ``` 3. 实现gRPC服务:根据定义的服务接口,编写服务器端和客户端的实现代码。服务器端需要继承自服务接口定义,并实现其中的方法。以下是一个简单的服务器端实现的示例代码: ```python import grpc from concurrent import futures import myservice_pb2 import myservice_pb2_grpc class MyServiceServicer(myservice_pb2_grpc.MyServiceServicer): def SendMessage(self, request, context): response = myservice_pb2.Response() response.message = 'Hello, ' + request.message return response def serve(): server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) myservice_pb2_grpc.add_MyServiceServicer_to_server(MyServiceServicer(), server) server.add_insecure_port('[::]:50051') server.start() server.wait_for_termination() if __name__ == '__main__': serve() ``` 4. 创建gRPC客户端:使用gRPC库创建一个客户端,用于向服务器发送请求并接收响应。以下是一个简单的客户端实现的示例代码: ```python import grpc import myservice_pb2 import myservice_pb2_grpc def run(): channel = grpc.insecure_channel('localhost:50051') stub = myservice_pb2_grpc.MyServiceStub(channel) request = myservice_pb2.Request() request.message = 'World' response = stub.SendMessage(request) print(response.message) if __name__ == '__main__': run() ``` 5. 启动服务器和客户端:可以分别在不同的终端或不同的服务器上分别启动服务器和客户端。服务器端会监听指定的端口,等待客户端的连接请求。客户端会向服务器发送请求,并接收服务器的响应。 通过以上步骤,便可以在Python编程中使用gRPC协议在服务器之间传输信息。 ### 回答3: 在Python编程中使用gRPC协议在服务器之间传输信息有以下几个步骤。 1. 定义gRPC服务和消息类型:首先需要在.proto文件中定义gRPC服务和消息类型。服务定义了支持的RPC方法,而消息类型定义了传输的数据结构。这个.proto文件需要通过编译器生成相应的Python代码。 2. 编写服务器代码:在服务器端,我们需要实现定义的gRPC服务接口,并提供相应的功能。首先需要创建一个服务器对象,然后将定义的gRPC服务实现添加到服务器对象中。在gRPC中,服务器可以同时监听多个端口。 3. 编写客户端代码:在客户端,我们可以通过生成的Python代码创建一个gRPC通道。通道可以用来连接服务器,并调用服务器提供的RPC方法。客户端可以通过调用方法将请求发送到服务器,并接收服务器返回的结果。 4. 编译和运行代码:在完成服务器和客户端代码的编写后,我们需要分别编译生成的.proto文件和Python代码。编译命令会生成相应的Python文件和其他必要的文件。最后,我们可以启动服务器和客户端以进行通信。 5. 测试和调试:在完成代码的编写和编译后,我们可以使用各种测试工具和方法来测试和调试服务器和客户端之间的通信。可以使用Mock数据和单元测试框架来验证服务器和客户端的行为是否符合预期。 在以上步骤中,.proto文件的定义、服务器和客户端的代码编写、编译和运行是关键。通过这些步骤,我们可以在Python编程中使用gRPC协议在服务器之间有效地传输信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值