背景
在微服务架构下,进行核心接口质量保障是非常重要的,当下比较流行的方式是契约测试,会使我们的测试效率变得更高。
另外一种方式,也可以通过解析Nginx网关日志日志拿到里面关于接口调用的信息。
最后一种极端但是常见的情况,在没有文档的情况下,可以利用mitmproxy的录制功能去解决快速的接口录制和与其他工具集成的回放。
本文仅提供一个公共解决思路,可以根据业务特性去进行进一步的定制,源码会放到结尾。
思路
- 基于mitmproxy的mitmdump工具的扩展脚本功能作为录制端。
- 基于requests作为回放端并且生成报告。
录制生成接口用例
我们在本地编写一个cli_replay.py的脚本,使用CSV文件地址的地址作为入参。
主要思路,在response方法处拦截请求地址、请求状态码、请求头等字段,收集完这次字段后,就可以进行回放接口测试。
录制代码:
代码语言:javascript复制def response(flow: http.HTTPFlow):
# 加上过滤条件
if "igetcool-gateway.igetcool.com" in str(flow.request.pretty_url) and 'GET' in str(flow.request.method):
# 打开保存在本地的数据文件
#print(flow.request.get_text())
requestInfo = {}
requestInfo['request_url'] = str(flow.request.pretty_url)
data = json.loads(flow.response.content)
requestInfo['request_headers'] = create_headers(flow.request.headers)
requestInfo['request_method'] = flow.request.method
requestInfo['status_code'] = flow.response.status_code
requestInfo['reason'] = flow.response.reason
requestInfo['response_data'] = data
requestInfo['response_headers'] = create_headers(flow.response.headers)
requestInfo['request_time_start'] = flow.request.timestamp_start
requestInfo['request_time_end'] = flow.request.timestamp_end
requestInfo['response_time_start'] = flow.response.timestamp_start
requestInfo['response_time_end'] = flow.response.timestamp_end
requestInfo['response_time'] = requestInfo['response_time_end'] - requestInfo['request_time_start'] # 响应时间
然后保存到本地csv文件中,为了保障每次执行录制脚步的cvs文件名字是唯一的。每次启动 脚本使用当前时间戳(%Y%m%d%H%M%S)创建CSV文件。
因为CSV文件是用过,行、列保存的,所以需要把字段放到列表中。
代码语言:javascript复制print(requestInfo)
with open(savePath, 'a ') as csvfile:
writer = csv.writer(csvfile)
writer.writerows(
[[requestInfo['request_url'], requestInfo['request_headers'], requestInfo['request_method'],
requestInfo['status_code'], requestInfo['response_data'], requestInfo['response_time']]])
录制命令:
代码语言:javascript复制mitmdump -s cli_record.py
操作app后,在控制台看到日志标记说明写入文件成功。
录制完成并且结束终端,会在本地生成20220525213209-case.csv这种文件,然后打开以后,就是刚才发送接口请求的数据。
回放生成接口用例
主要思路是解析刚才录制的CSV文件中数据,然后循环发送请求。使用requests网路库,简单封装了一个base_requests方法进行接口请求。因为一些POST接口有幂等性逻辑,所以本次只考虑GET接口请求。
我们在本地编写一个cli_replay.py的脚本,使用CSV文件地址的地址作为入参。
回放执行命令:
代码语言:javascript复制python3 cli_replay.py /Users/xinxi/Documents/zhihu/mitmproxyRecode/20220524230852-case.csv
base_requests代码如下:
代码语言:javascript复制def base_requests():
"""
基础请求
:return:
"""
caseList = read_case()
apiNameList = []
apiTimeList = []
successes = 0
failures = 0
skipped = 0
if len(caseList) > 0:
for case in caseList:
request_url = case[0]
request_headers = eval(case[1])
request_method = case[2]
old_response_data = case[4]
if request_method == 'GET':
r = requests.request(method=request_method, url=request_url, headers=request_headers)
对于请求结果验证使用diff方式验证,录制的接口返回数据作为预期结果,回放生成的接口返回数据作为实际结果。
diff代码如下:
代码语言:javascript复制now_response_data = r.json()
print('********************* Requests URL: {} *********************'.format(r.url))
diff_data = DeepDiff(now_response_data, eval(old_response_data), ignore_order=True) # diff 返回数据
case.append(json.dumps(eval(old_response_data), indent=4, ensure_ascii=False))
case.append(json.dumps(r.json(), indent=4, ensure_ascii=False))
case.append(json.dumps(diff_data, indent=4, ensure_ascii=False))
apiNameList.append(r.url)
生成报告
使用jinja2库生成测试报告,首先需要本地准备一个html报告模版,放到/resources/templates/目录下。这里需要懂一点前端html css js的知识,然后通过jinja2来给html报告模版放数据,最终生成html报告。
jinja2先从本地使用loader方法加载一个模版,然后调用render方法,渲染成最终的html报告。
生成代码方法:
代码语言:javascript复制def create_report(records, apiNameList, apiTimeList, successes, failures, skipped):
"""
生成测试报告
:return:
"""
reportFolder = os.path.join(currentPath, 'reports')
if not os.path.exists(reportFolder):
os.makedirs(reportFolder)
report_path = os.path.join(reportFolder, "CaseReport{}.html".format(time.strftime("%Y%m%d%H%M%S")))
try:
env = Environment(loader=PackageLoader('resources', 'templates'))
template = env.get_template("template.html")
html_content = template.render(html_report_name="接口测试报告", records=records, apiNameList=apiNameList,
apiTimeList=apiTimeList,successes=successes,failures=failures,skipped=skipped)
with open(report_path, "wb") as f:
f.write(html_content.encode("utf-8"))
print('报告地址: {}'.format(report_path))
except Exception as e:
print(e)
报告设计从四部分组成:
- 通过率: 判断接口状态是200为成功,否则认识不通过,当然这里只是演示而已,可以根据实际业务逻辑自行判断。
- 接口响应时间: 记录每个接口的响应时间,使用柱状图表示结果。
- 接口列表: 按照请求的顺序展示,包含字段: 请求地址、请求方法、状态码。
- diff结果
在接口列表中,点击Detail按钮,可以看到三段结构。在对比结果展示的数据是预期结果和实际数据进行对比。
如果出现diff差异说明,存在一定的差异性。但是不一定是有问题,比如下面的diff的差异在参与过学习的人数,本来就是动态变化的,所以diff出现不一样是符合业务需要的。
diff结果如下:
代码语言:javascript复制{
"values_changed": {
"root['data']['studyNum']": {
"new_value": 202223,
"old_value": 202337
},
"root['data']['studyNumCopy']": {
"new_value": "202223人参与过学习",
"old_value": "202337人参与过学习"
}
}
结语
本文就简单介绍了,基于mitmproxy的录制回放接口测试工具。在实际工作中,也可以快速开发一些小工具提高工作效率和快速验证结果。
工具地址:
https://github.com/xinxi1990/mitmproxyRecode