框架的最终归宿往往是领域语言+模板解析。
首先先约定一种所要执行操作的表述格式。然后通过模板解析将描述语言转化为代码进行执行。例如,我们可以使用以下yaml文件描述多个步骤并且需要关联的接口:
apis.yaml
:
- name: 获取百度token接口 # 接口名称
request: # 请求报文
url: https://aip.baidubce.com/oauth/2.0/token
method: get
params:
grant_type: client_credentials
client_id: kPoFYw85FXsnojsy5bB9hu6x
client_secret: l7SuGBkDQHkjiTPU3m6NaNddD6SCvDMC
extract: # 提取变量, 字典格式
token: RESPONSE.json()['access_token'] # RESPONSE系统变量,代表响应对象
- name: 百度ORC接口 # 第二个接口
request:
url: https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic?access_token=${token} # 使用变量
method: post
data: # 请求体(表单格式)
url: //upload-images.jianshu.io/upload_images/7575721-40c847532432e852.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240
verify: # 断言, 列表格式
- RESPONSE.json()['words_result_num'] == 6
其中,name
为该接口或步骤的名称描述,request
段是接口的信息,对应requests.request()
的每一个参数,url
和method
是必要参数,params
,headers
,cookies
,data
, json
,files
,timeout
等,并使用对应格式。extract用于提取值, token: RESPONSE.json()['access_token'] ,表示提取该接口响应字典中的access_token字段的值保存为名为token的变量。
在第二个接口的url中通过使用${token},引用该变量。
verify段类似与extract, 计算表达式的值,通过结果的True/False判断该条断言是否通过。
上面我们定义了一套接口关联的描述及规则,下面我们要对我们的规则进行解析,并加载运行,主要分为以下几步:
- 读取yaml文件并使用
yaml.safe_load(f)
转为列表/字典 - 遍历列表,每个列表项是一个接口
- 读取当前列表项(接口)的request段信息,处理${变量}
- 将request段(字典格式)重新转会yaml字符串
- 如果包含
$
使用string.Template('字符串').safe_subtitute(locals())
,从locals()当前所有局部变量中找到$表示的同名变量,如token,并替换。 - 重新将替换后变量的字符串转化为字典
- 字典拆包,发送request请求
- 如果请求中有extract字段,使用
eval()
计算表达式的值并保存到局部变量locals()
中。 - 如果请求中有verify字段,使用
eval()
计算表达式的值,并判断真假。
实现代码:
需要安装pyyaml:
pip install pyyaml
apis_parser.py
import yaml
import requests
from string import Template
with open('apis.yaml', encoding='utf-8') as f:
apis = yaml.safe_load(f)
for api in apis:
print("处理请求:", api.get('name'))
request = api.get('request', {}) # 请求报文,默认值为{}
# 处理参数化请求中的${变量}
request_str = yaml.dump(request) # 先转为字符串
if '$' in request_str:
request_str = Template(request_str).safe_substitute(locals()) # 替换${变量}为局部变量中的同名变量
request = yaml.safe_load(request_str) # 重新转为字典
# 发送请求
res = requests.request(**request) # 字典解包,发送接口
# 提取变量
extract = api.get('extract')
if extract is not None: # 如果存在extract
for key, value in extract.items():
# 计算value表达式,可使用的全局变量为空,可使用的局部变量为RESPONSE(响应对象)
# 保存变量结果到局部变量中
print("提取变量:", key, value)
locals()[key] = eval(value, {}, {'RESPONSE': res})
# 处理断言
verify = api.get('verify')
if verify is not None:
for line in verify:
result = eval(line, {}, {'RESPONSE': res}) # 计算断言表达式,True代表成功,False代表失败
print("断言:", line, "结果:", "PASS" if result else "FAIL")
执行结果:
处理请求: 获取百度token接口
提取变量: token RESPONSE.json()['access_token']
处理请求: 百度ORC接口
断言: RESPONSE.json()['words_result_num'] == 6 结果: PASS