hyload 编程接口
hyload 工具的加压模块做在hyload库中, 提供了一套Python编程接口 给大家开发。
可以通过命令 pip install hyload
安装这个库。
虽然大部分的功能,可以通过代码助手自动产生,但是要做到灵活的控制,大家需要了解详细的接口和参数。
本文给出了这些接口和参数的具体说明。
HttpClient 对象
HttpClient 对象模拟一个客户端,它的初始化方法定义如下
def __init__(self
timeout=None,
proxy=None
)
参数 依次为
-
timeout
指定网络操作(比如连接)超时时间,整数类型。
缺省值为操作系统默认设置
比如
# 超时时间设定为10秒 client = HttpClient(timeout=10)
-
proxy
指定代理
127.0.0.1:8888
通常不需要设置此参数
发送请求
发起请求可以使用 send方法,定义如下
def send(
self,
method,
url,
params=None,
headers=None,
data=None,
json=None,
debug:bool=False,
debug_body_print_max_len=4096,
request_body_encoding=None,
response_body_encoding=None
):
method 请求方法
发送HTTP请求的 方法
,由 method
参数指定,比如 GET、POST、PUT、DELETE、PATCH、HEAD 等等
client.send('GET', '/api/path1')
也可以更简单一些,直接使用对应名称(转化为小写字母)的函数方法,比如 get/post/put/delete/patch/head
client.get('/api/path1')
两种方法,效果是一样的。
url
发送HTTP请求的 URL
,由 url
参数指定。
第一次调用send 发送消息,必须指定 协议主机端口 前缀,比如
client.send(
'POST',
'http://127.0.0.1/api/mgr/signin',
data={
'username':'byhy',
'password':'88888888'
},
)
client.get('https://www.yourwebsite.com/your/url/path')
后续消息可以省略 协议主机端口 前缀
client.get('/api/path1')
hyload发现省略了, 默认会用 上次使用的 协议主机端口
URL参数
如果你要发送的HTTP请求 有URL参数,有如下两种方式指定:
-
直接在url中自己填入
url参数是问号后面的以&符隔开的,如下所示
client.get( 'http://127.0.0.1/api/path1?p1=value1&p2=value2' )
-
通过 params 参数指定
可以把url参数对应的键值对存入
字典
,传给params,如下所示client.get( 'http://127.0.0.1/api/path1' params={ 'p1':'value1', 'p2':'value2' } )
效果和上面的例子相同
消息体 - 概述
发送HTTP请求的消息体中的数据 由 data、json、encoding
这3个参数决定。
首先大家要了解一个基本常识:
不管你的消息体中的数据是字符串、图像、视频 或者是你们自定义的数据格式,最终HTTP请求发送的消息体,都是一个个字节组成的 字节串
。
大多数情况下,API接口消息的 消息体 都是字符串, 需要编码为字节串发送。
消息体 - 字符串数据
大多数情况下,API接口消息的 HTTP请求消息体 都是字符串数据。
根据接口设计,字符串消息体有不同的格式,比如 JSON、XML、UrlEncoded
json格式
如果消息体是json格式的字符串(目前非常普遍),可以使用 json 参数,直接把数据对象传递给json参数
比如一个添加朋友的API接口,可以像这样
client.post(
'/api/path1',
# 通过json传入指定json格式的消息体参数
json={
'action':'addfriends'
'userid': 3344,
'friends': [3242,234545,232]
})
消息体字符串最终编码为字节串的时候,使用encoding参数指定的编码方式,缺省是utf8编码
比如,你可以这样指定gbk编码方式
client.post(
'/api/path1',
# 通过json传入指定json格式的消息体参数
data={
'action':'addfriends'
'userid': 3344,
'friends': ['白月黑羽','紫气一元']
})
request_body_encoding = 'gbk'
UrlEncoded 格式
如果消息体是UrlEncoded 格式的字符串 ,可以使用 data 参数,直接把 数据对象
传递给data参数
比如一个添加朋友的API接口,可以像这样
client.post(
'/api/path1',
# 通过data传入指定urlencode格式的消息体参数
# urlencode格式所有参数键值对只能是字符串格式
data={
'action':'addfriends'
'userid': '3344',
'friends': '3242,234545,232'
})
同样的,消息体字符串最终编码为字节串的时候,使用encoding参数指定的编码方式,缺省是utf8编码
其他字符串格式
如果消息体是其他格式的字符串,比如 XML、YAML、 TOML 或者你们自己定义的字符串格式,还是可以使用 data 参数。
需要你们自己把最终的产生的 字符串
传递给data参数。
而且,要设定 相应的HTTP消息头 Content-Type
, 指定消息类型。
比如
client.post(
'/api/path1',
headers={
# 说明消息体是 xml格式
'Content-Type':'application/xml'
}
# 下面填写内容
data='''
<?xml version="1.0" encoding="UTF-8"?>
<CreateBucketConfiguration>
<StorageClass>Standard</StorageClass>
</CreateBucketConfiguration>
'''
)
前面的json格式 和 urlencoded 格式 不需要像这样指定消息头,我们的库会自动帮你指定为 application/json
和 application/x-www-form-urlencoded
同样的,消息体字符串最终编码为字节串的时候,使用encoding参数指定的编码方式,缺省是utf8编码
消息体 - 字节数据
如果你的消息体不是纯字符串,而是其他二进制数据,比如 图片、视频、或者你们自己定义的消息体格式,
还是可以使用 data 参数。
需要你们自己把最终的产生的 字节串bytes对象
传递给data参数。
比如
client.post(
'/api/path1',
headers={
# 说明消息体是哪种格式
'Content-Type':'application/3gpp'
}
# 下面填写bytes的内容,注意最后的编码格式
data=b'\x9f\x5c\x56\x90\xee\x34\x5c\x90\xee\x34\x56\x90'
)
消息头
发起的HTTP请求,如果有特殊消息头设置,可以使用 headers参数指定。
直接把消息头对应的 一个个键值对数据 放在 字典
中, 传递给headers参数
比如
client.get(
'/api/path1',
# 通过headers传入指定消息头
headers={
'header1':'value1',
'header2':'value2'
})
打印具体消息
可以在调用 send 方法时设置参数 debug=True
, 这样hyload库会打印出发送和接收消息的具体内容。
获取响应信息
调用对象的send方法发送请求后,接收到服务端的响应消息后,会返回一个 响应对象 HttpResponse
通过这个对象,我们可以获取一些信息,比如响应速度,HTTP响应 消息状态码、消息头、消息体等
响应速度
通过 HttpResponse 对象的 response_time
属性,可以获取 从发出请求 到 获取响应的 时间间隔。
比如
# 返回一个 HttpResponse 类型的 实例对象,赋值给变量res
res = client.get('/api/path1' )
print(f"响应时长为 {res.response_time} ms")
响应状态码
通过 HttpResponse 对象的 status_code
属性,可以获取 HTTP响应 消息状态码
比如
res = client.get('/api/path1' )
print(f"响应状态码为 {res.status_code} ")
响应消息头
HttpResponse 对象的 getheader
方法,,可以获取 指定
HTTP响应消息头的值
比如
client = HttpClient()
res = client.get('/api/path1' )
# 获取消息头Content-Type值
ct = res.getheader('Content-Type')
print(f"消息头Content-Type值为 {ct} ")
获取的消息头是大小写不敏感的,也可以这样获取
res.getheader('content-type')
如果你想打印出 所有
的响应头,可以使用 getheaders
方法,
这样
client = HttpClient()
res = client.get('https://www.163.com/api/path1' )
for header,value in res.getheaders() :
print(f"消息头 {header} 值为 {value} ")
运行结果类似
消息头 Date 值为 Tue, 28 Apr 2020 10:01:22 GMT
消息头 Content-Type 值为 text/html
消息头 Transfer-Encoding 值为 chunked
消息头 Connection 值为 keep-alive
消息头 Expires 值为 Tue, 28 Apr 2020 10:01:22 GMT
消息头 Server 值为 nginx
消息头 Location 值为 http://www.163.com
消息头 Cache-Control 值为 max-age=120
消息头 cdn-user-ip 值为 112.80.117.132
消息头 cdn-ip 值为 59.83.221.16
消息头 X-Cache-Remote 值为 MISS
消息头 cdn-source 值为 baishan
响应消息体 - 纯文本
如果你确定 返回响应消息体 是 纯文本字符串
,需要从字节串解码为字符串。
可以直接使用 返回的 HttpResponse 对象的 text 方法进行解码。
缺省的解码方式是utf8,你可以指定其他解码方式,比如gbk
比如
client = HttpClient()
res = client.get('https://www.163.com/' )
# 指定gbk解码
content = res.text('gbk')
print(f"消息体字符串为\n {content} ")
响应消息体 - json格式
如果你确定 返回响应消息体 是 json格式 纯文本字符串
,需要从字节串解码为字符串。
json格式字符串 当然 也还是字符串,你仍然可以先使用string方法获取json格式的字符串。
但是为了方便后续处理,通常我们获取json格式的字符串后 ,还需要 反序列化
为 Python中的数据对象进行处理。
这样,我们就需要再 调用 json库的loads 方法了。这样就比较麻烦了。
我们可以直接使用 返回的 HttpResponse 对象的 json 方法进行解码。
这个方法内部实现就是先解码为字符串,再调用 json库的loads反序列化。
json 方法 缺省的解码方式是utf8,你可以指定其他解码方式,比如gbk
比如
client = HttpClient()
res = client.get('http://127.0.0.1/api/students' )
# json方法自动把json格式的消息体
# 转化为 Python中的数据对象
studentsObj = res.json()
响应消息体 - 原始字节
如果你确定 返回响应消息体不是纯文本字符串数据,而是特殊格式的字节数据。
你要直接获取消息体中的原始字节 进行处理,可以直接使用 返回的 HttpResponse 对象的 raw 属性,得到一个Bytes对象。
比如
client = HttpClient()
res = client.get('http://127.0.0.1/api/3gpp/authinterface' )
# 返回一个bytes对象,保存了消息体中的字节串
body = res.raw
数据监测
内置功能
hyload 测试过程中,界面上会有 实时的性能数据显示。
而且性能测试的数据会实时保存在项目目录中,在测试完 性能场景后,可以根据这些数据绘制性能图表。
这些都是hyload 已经做好的功能。具体请参考这一章
错误汇报
有些业务错误,比如返回数据的格式和接口文档不一致,这种错误hyload 框架本身是没法检查的,只能通过你的代码检查。
如果你的代码判断响应消息有错误,可以使用 hyload 的内置类 Stats 的方法 one_error
汇报这个错误给 hyload 框架 ,这样统计错误的响应消息,就会计数+1。
代码示例,如下所示
# 检查状态码,必须是400
if (response.status_code != 400):
print('错误密码登录时,返回状态码不是400,测试不通过')
# 汇报错误,加入统计结果中
Stats.one_error()
这个方法可以接收一个字符串参数, 作为同时要写入日志文件的内容
比如
Stats.one_error('错误密码登录时,返回状态码不是400')
定制功能
如果你有更细致的性能数据要统计,可以使用 hyload 的内置类 TestLogger 的方法 write ,记录下任意你需要记录的信息
比如,要统计整个测试过程中 响应时长 的各种范围,以及各范围内 API请求数量和对应的用户
就可以自行添加如下代码:
response = client.get(
"http://127.0.0.1/api/mgr/signin")
rt = response.response_time # 获取响应时长
if rt > 1000: # 大于1秒
TestLogger.write(f'API list_order >1s|{username}')
elif rt > 500: # 大于0.5秒
TestLogger.write(f'API list_order >0.5s|{username}')
elif rt > 100: # 大于0.1秒
TestLogger.write(f'API list_order >0.1s|{username}')
elif rt > 50: # 大于0.05秒
TestLogger.write(f'API list_order >0.05s|{username}')
在测试结束后,就会产生时间戳日志文件名,比如
2020-04-28_22.01.08.log
我们分析测试日志,即可到这些统计数据信息。
如果有几百万条统计数据,怎么分析日志?
写Python程序啊,数据文件分析是Python最擅长的了,可以很方便的统计数据,并且使用matplotlib等库,做出统计图。