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/jsonapplication/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等库,做出统计图。

您需要高效学习,找工作? 点击咨询 报名实战班

点击查看学员就业情况

上一页
下一页