之前的框架中存在的问题:
1、太多重复代码
2、可以将token关联写入yaml
因此我们需要对yaml进行规范
在根目录下创建“接口自动化测试框架YAML测试用例规范.txt”文件
接口自动化测试YAML测试用例规范: 1、一级关键字必须包含name、request、validate 2、在request下必须包含method、url 3、传参方式: 1.get请求,必须通过params传参 2.post请求 传json格式,需要使用json 传表单格式,需要使用data传参 3.文件上传,使用files传参 4、接口关联 提取: 1.正则表达式&jsonpath表达式 extract: token1: '"token":"(.*?)"' ##正则 expires_in:$.expires_in ##jsonpath 取值方式:${token}
get_token.yaml
-
name: 登录接口,获取接口统一鉴权码token接口
request:
method: post
url: /jlcloud/api/login
headers:
'Content-Type': 'application/json'
json: {"account": "admin","password": "123456","project": "DEFAULT",
"teacherLogin":false,"clientId": "1","secret": "joylink"}
extract: #这部分是提取token值,提取数据的方法需要写入提取该数据的接口yaml文件中,这里使用的是正则表达式的提取方法,如果接口的返回值是json,也可以使用jsonpath,将提取的值赋值给token,后续调用的时候使用${token}即可,其它的数据提取同理
token: '"data":"(.*?)"'
validate: None
-
name: 登录接口,获取接口统一鉴权码token接口
request:
method: post
url: /jlcloud/api/login
headers:
'Content-Type': 'application/json'
json: {"account": "admin","password": " ","project": "DEFAULT",
"teacherLogin":false,"clientId": "1","secret": "joylink"}
extract:
token: '"data":"(.*?)"' #这部分是提取token值,提取数据的方法需要写入提取该数据的接口yaml文件中,这里使用的是正则表达式的提取方法,如果接口的返回值是json,也可以使用jsonpath,将提取的值赋值给token,后续调用的时候使用${token}即可,其它的数据提取同理
validate: None
userinfo.yaml
-
name: 获取用户信息接口
request:
method: get
url: /jlcloud/api/login/getUserInfo
params:
token: ${token}
headers:
'Content-Type': 'application/json'
validate: None
我们按照这样的规范,在request_util.py中写入规范yaml的方法,替换值的方法,统一请求的封装
我们直接上代码:
import jsonpath
import requests
import json
from common.yaml_util import YamlUtil
from builtins import str
import re
class RequestUtil:
def __init__(self,two_node):
self.base_url=YamlUtil().read_config('base',two_node)
#替换值的方法
# #(替换url,params,data,json,headers)
# #(string,int,float,list,dict)
def replace_value(self, data):
if data:
# 保存数据类型
data_type = type(data)
# 判断数据类型转换成str
if isinstance(data, dict) or isinstance(data, list):
str_data = json.dumps(data)
else:
str_data = str(data)
for cs in range(1, str_data.count('${') + 1):
# 替换
if "${" in str_data and "}" in str_data:
start_index = str_data.index("${")
end_index = str_data.index("}", start_index)
old_value = str_data[start_index:end_index + 1]
new_value = YamlUtil().read_yaml(old_value[2:-1])
str_data = str_data.replace(old_value, new_value)
# 还原数据类型
if isinstance(data, dict) or isinstance(data, list):
data = json.loads(str_data)
else:
data = data_type(str_data)
return data
#规范yaml测试用例
def standard_yaml(self,caseinfo):
caseinfo_keys= caseinfo.keys()
#判断一级关键字是否包含:name,request,validate
if "name" in caseinfo_keys and "request" in caseinfo_keys and "validate" in caseinfo_keys:
#判断request下面是否包含:method、url
request_keys=caseinfo["request"].keys()
if "method" in request_keys and "url" in request_keys:
print("yaml基本架构检查通过")
method = caseinfo['request'].pop("method") #pop() 函数用于移除列表中的一个元素,并且返回该元素的值。
url= caseinfo['request'].pop("url")
res = self.send_request(method,url,**caseinfo['request']) #caseinfo需要解包加**
return_text=res.text
# 提取值并写入extract.yaml文件
if "extract" in caseinfo.keys():
for key, value in caseinfo["extract"].items():
if "(.*?)" in value or "(.+?)" in value: # 正则表达式
zz_value = re.search(value, return_text)
if zz_value:
extract_value = {key: zz_value.group(1)}
YamlUtil().write_yaml(extract_value)
else: # jsonpath
try:
resturn_json = res.json()
js_value = jsonpath.jsonpath(resturn_json, value)
if js_value:
extract_value = {key: js_value[0]}
YamlUtil().write_yaml(extract_value)
except Exception as e:
print("extract返回的结果不是JSON格式,不能使用jsonpath提取")
return res
else:
print("在request下必须包含method,url")
else:
print("一级关键字必须包含name,request,validate")
sess= requests.session()
# 统一请求封装
def send_request(self,method,url,**kwargs):
method=str(method).lower() #转换小写
#基础路径的拼接和替换
url= self.base_url + self.replace_value(url)
print(url)
#参数替换
for key,value in kwargs.items():
if key in ['params','data','json','headers']:
kwargs[key]=self.replace_value(value)
elif key == "files":
for file_key, file_path in value.items():
value[file_key] = open(file_path, 'rb')
res = RequestUtil.sess.request(method, url, **kwargs)
print(res.text)
return res
基于我们对框架的改造升级,接下来就可以省去用例中重复的代码,我们的用例被简化,每个用例只需要更换yaml数据的读取名称即可,test_login.py代码如下:
import pytest
import requests
import json
from common.request_util import RequestUtil
from common.yaml_util import YamlUtil
class TestRequest:
pass
@pytest.mark.parametrize("caseinfo",YamlUtil().read_testcase('get_token.yaml'))
def test_login(self,caseinfo):
res = RequestUtil("base_test_url").standard_yaml(caseinfo)
#
@pytest.mark.parametrize("caseinfo", YamlUtil().read_testcase('userinfo.yaml'))
def test_userinfo(self, caseinfo):
res = RequestUtil("base_test_url").standard_yaml(caseinfo)
# print(res.text)
#
@pytest.mark.parametrize("caseinfo", YamlUtil().read_testcase('city_type.yaml'))
def test_simulation(self, caseinfo):
res = RequestUtil("base_test_url").standard_yaml(caseinfo)