delete httprunner
This commit is contained in:
parent
be0f2d388f
commit
9ff8cfc6b1
@ -1,11 +0,0 @@
|
|||||||
### http接口测试工具
|
|
||||||
|
|
||||||
该python脚本来源于公司内部的http测试工具:https://coding.jd.com/fangjiankang/python_httprunner.git
|
|
||||||
|
|
||||||
需安装的python依赖:pip install requests xlrd xlwt colorama
|
|
||||||
|
|
||||||
使用文档:https://cf.jd.com/pages/viewpage.action?pageId=478195770
|
|
||||||
|
|
||||||
开始执行测试的命令为:python start.py
|
|
||||||
|
|
||||||
测试结果在report目录
|
|
@ -1,22 +0,0 @@
|
|||||||
def check_options(case_options):
|
|
||||||
"""
|
|
||||||
检查post请求参数的合法性
|
|
||||||
:param case_options: 用例内容
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if 'url' not in case_options.keys():
|
|
||||||
print("url 参数未设置,跳过此调用例执行,参数为:%s" % case_options)
|
|
||||||
return False
|
|
||||||
if 'body' not in case_options.keys():
|
|
||||||
print("body 参数未设置,跳过此调用例执行,参数为:%s" % case_options)
|
|
||||||
return False
|
|
||||||
if 'headers' not in case_options.keys():
|
|
||||||
print("headers 参数未设置,跳过此调用例执行,参数为:%s" % case_options)
|
|
||||||
return False
|
|
||||||
if 'assert_type' not in case_options.keys():
|
|
||||||
print("assert_type 参数未设置,跳过此调用例执行,参数为:%s" % case_options)
|
|
||||||
return False
|
|
||||||
if 'assert_value' not in case_options.keys():
|
|
||||||
print("assert_value 参数未设置,跳过此调用例执行,参数为:%s" % case_options)
|
|
||||||
return False
|
|
||||||
return True
|
|
@ -1,5 +0,0 @@
|
|||||||
testcase_file_path = './myCase.xls' # 测试用例源文件地址
|
|
||||||
report_path = "./report" # 测试报告生成父级路径
|
|
||||||
xls_report = True # 是否生成测试报告,填写 True 或 False
|
|
||||||
output_model = "detail" # 定义命令行输出接口执行时输出内容的详细程度,传值要求:simple(简要) 或 detail(详细)
|
|
||||||
|
|
@ -1,148 +0,0 @@
|
|||||||
import net_request
|
|
||||||
import checker
|
|
||||||
import time
|
|
||||||
import json
|
|
||||||
import config
|
|
||||||
import colorama
|
|
||||||
from colorama import init, Fore, Back, Style
|
|
||||||
|
|
||||||
init(autoreset=True)
|
|
||||||
|
|
||||||
|
|
||||||
def run(testcase_list):
|
|
||||||
print('\n\033[1;33m========= 执行接口测试 ==========\033[0m')
|
|
||||||
result_list = []
|
|
||||||
i = 1
|
|
||||||
for testcase in testcase_list:
|
|
||||||
print('[测试接口%s]' % i)
|
|
||||||
result_list.append(run_case(testcase))
|
|
||||||
i += 1
|
|
||||||
return result_list
|
|
||||||
|
|
||||||
|
|
||||||
def run_case(case_options):
|
|
||||||
"""
|
|
||||||
运行测试用例
|
|
||||||
:param case_options: 测试用例执行所需要的相关参数字典
|
|
||||||
:return:返回空值
|
|
||||||
"""
|
|
||||||
# 如果从用例参数中不能获取request_type,则用例跳出,不做执行
|
|
||||||
if 'request_type' not in case_options.keys():
|
|
||||||
print("request_type 参数未设置,跳过此调用例执行,参数为:%s" % case_options)
|
|
||||||
return
|
|
||||||
|
|
||||||
request_type = case_options['request_type'] # 获得请求类型
|
|
||||||
response_result = '' # 请求返回后的存储变量
|
|
||||||
begin_time = time.time() # 记录请求前的时间
|
|
||||||
|
|
||||||
# 执行post类型的请求
|
|
||||||
if request_type.lower() == 'post':
|
|
||||||
# 对用例参数的完整请进行检测
|
|
||||||
if not checker.check_options(case_options):
|
|
||||||
return
|
|
||||||
# 发送post请求
|
|
||||||
response_result = net_request.post(case_options['url'], case_options['headers'], case_options['body'])
|
|
||||||
|
|
||||||
# 执行get类型的请求
|
|
||||||
if request_type.lower() == 'get':
|
|
||||||
if not checker.check_options(case_options):
|
|
||||||
return
|
|
||||||
# 发送get请求
|
|
||||||
response_result = net_request.get(case_options['url'], case_options['headers'], case_options['body'])
|
|
||||||
|
|
||||||
end_time = time.time() # 记录请求完成后的时间
|
|
||||||
# 对执行结果进行判断,检查是否用例的通过情况
|
|
||||||
check_result = analyse_result(response_result, case_options['assert_value'], case_options['assert_type'])
|
|
||||||
# 将执行信息输出到控制台
|
|
||||||
cost_time = round(end_time - begin_time, 3)
|
|
||||||
output_execute_info(case_options, response_result, check_result, cost_time)
|
|
||||||
# 将执行结果进行组装并返回给调用方
|
|
||||||
return {'case_options': case_options, 'response_result': response_result, 'check_result': check_result,
|
|
||||||
'cost_time': cost_time}
|
|
||||||
|
|
||||||
|
|
||||||
def analyse_result(real_result, assert_value, assert_type):
|
|
||||||
"""
|
|
||||||
分析请求返回的测试结果
|
|
||||||
:param real_result: 返回请求的结果,json串
|
|
||||||
:param assert_value: 期望结果字串,来自请求的case_options字典
|
|
||||||
:param assert_type: 断言的判断方式,来自请求的case_options字典(提供:包含、相等)
|
|
||||||
:return:返回判断的结果,通过未为True,失败为False
|
|
||||||
"""
|
|
||||||
|
|
||||||
# 处理包含的逻辑,如果请求返回结果包含断言值,则判断结果为True
|
|
||||||
if '包含' == assert_type:
|
|
||||||
if json.dumps(real_result, ensure_ascii=False).__contains__(str(assert_value)):
|
|
||||||
return True
|
|
||||||
# 处理相等的逻辑,如果请求返回结果与断言值相同,则判断结果为True
|
|
||||||
if '相等' == assert_type:
|
|
||||||
if str(assert_value) == json.dumps(real_result, ensure_ascii=False):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def output_execute_info(case_options, response_result, check_result, time_consuming):
|
|
||||||
"""
|
|
||||||
在命令行输出测试执行报告信息(支持简单模式和详细模式输出)
|
|
||||||
:param case_options: 原测试用例信息
|
|
||||||
:param response_result: 请求返回结果
|
|
||||||
:param check_result: 测试结果,True、False
|
|
||||||
:param time_consuming: 测试用例执行耗时
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if config.output_model.lower() == 'simple':
|
|
||||||
simple_output(case_options, response_result, check_result, time_consuming)
|
|
||||||
elif config.output_model.lower() == 'detail':
|
|
||||||
detail_output(case_options, response_result, check_result, time_consuming)
|
|
||||||
else:
|
|
||||||
print("请到config.py文件中配置输出模式(output_model)!")
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def detail_output(case_options, response_result, check_result, time_consuming):
|
|
||||||
"""
|
|
||||||
在命令行输出测试执行报告信息(详细模式)
|
|
||||||
:param case_options: 原测试用例信息
|
|
||||||
:param response_result: 请求返回结果
|
|
||||||
:param check_result: 测试结果,True、False
|
|
||||||
:param time_consuming: 测试用例执行耗时
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
print("请求接口:", case_options['url'])
|
|
||||||
print("接口名称:", case_options['interface_name'])
|
|
||||||
print("请求类型:", case_options['request_type'].upper())
|
|
||||||
print("请求参数:", case_options['body'])
|
|
||||||
if check_result: # 按测试结果对返回内容进行着色输出
|
|
||||||
print('返回结果: \033[1;32;40m' + json.dumps(response_result, ensure_ascii=False) + '\033[0m')
|
|
||||||
print('断言内容: \033[1;32;40m' + case_options['assert_value'] + '\033[0m')
|
|
||||||
else:
|
|
||||||
print('返回结果: \033[1;31;40m' + json.dumps(response_result, ensure_ascii=False) + '\033[0m')
|
|
||||||
print('断言内容: \033[1;31;40m' + case_options['assert_value'] + '\033[0m')
|
|
||||||
print('断言方式: %s' % case_options['assert_type'])
|
|
||||||
print("执行耗时:", time_consuming, '秒')
|
|
||||||
test_result = '\033[1;32;40m通过\033[0m' if check_result is True else '\033[1;31;40m失败\033[0m' # 按测试结果染色命令行输出
|
|
||||||
print('测试结果:', test_result) # 无高亮
|
|
||||||
print("\n")
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def simple_output(case_options, response_result, check_result, time_consuming):
|
|
||||||
"""
|
|
||||||
在命令行输出测试执行报告信息(简单模式)
|
|
||||||
:param case_options: 原测试用例信息
|
|
||||||
:param response_result: 请求返回结果
|
|
||||||
:param check_result: 测试结果,True、False
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
print("请求接口:", case_options['url'])
|
|
||||||
if check_result: # 按测试结果对返回内容进行着色输出
|
|
||||||
print('返回结果: \033[1;32;40m' + json.dumps(response_result, ensure_ascii=False)[0:120] + '......' + '\033[0m')
|
|
||||||
print('断言内容: \033[1;32;40m' + case_options['assert_value'] + '\033[0m')
|
|
||||||
else:
|
|
||||||
print('返回结果: \033[1;31;40m' + json.dumps(response_result, ensure_ascii=False)[0:120] + '......' + '\033[0m')
|
|
||||||
print('断言内容: \033[1;31;40m' + case_options['assert_value'] + '\033[0m')
|
|
||||||
print("执行耗时:", time_consuming, '秒')
|
|
||||||
test_result = '\033[1;32;40m通过\033[0m' if check_result is True else '\033[1;31;40m失败\033[0m' # 按测试结果染色命令行输出
|
|
||||||
print('测试结果:', test_result) # 无高亮
|
|
||||||
print("\n")
|
|
||||||
return
|
|
Binary file not shown.
@ -1,33 +0,0 @@
|
|||||||
import requests
|
|
||||||
import traceback
|
|
||||||
|
|
||||||
|
|
||||||
def post(url, headers=None, body=None):
|
|
||||||
"""
|
|
||||||
发送post请求
|
|
||||||
:param url:请求地址
|
|
||||||
:param headers:头部信息
|
|
||||||
:param body:请求入参
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
|
|
||||||
response_post = requests.post(url, json=body, headers=headers)
|
|
||||||
res = response_post.text
|
|
||||||
if res.__contains__('<title>登录页</title>'):
|
|
||||||
return {"错误": "cookie失效"}
|
|
||||||
return response_post.json()
|
|
||||||
|
|
||||||
|
|
||||||
def get(url, headers, body):
|
|
||||||
"""
|
|
||||||
发送get请求
|
|
||||||
:param headers: 头部信息
|
|
||||||
:param url:请求地址
|
|
||||||
:param body:请求入参
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
response_get = requests.get(url, params=body, headers=headers)
|
|
||||||
res = response_get.text
|
|
||||||
if res.__contains__('<title>登录页</title>'):
|
|
||||||
return {"错误": "cookie失效"}
|
|
||||||
return response_get.json()
|
|
@ -1,62 +0,0 @@
|
|||||||
import xlrd
|
|
||||||
import os
|
|
||||||
|
|
||||||
|
|
||||||
def read(testcase_file_path):
|
|
||||||
"""
|
|
||||||
读取接口测试用例源文件,将读取的有效用例写入字典
|
|
||||||
:param testcase_file_path: 读取用例文件的路径地址
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if not os.path.exists(testcase_file_path):
|
|
||||||
print("%s 文件不存在,无法读取到文件内容" % testcase_file_path)
|
|
||||||
return
|
|
||||||
# 在命令行打印提示信息
|
|
||||||
print('\n\033[1;33m====== 读取测试用例列表文件 ======\033[0m')
|
|
||||||
print("文件地址:%s" % testcase_file_path)
|
|
||||||
# 读取xls文件内容
|
|
||||||
xls = xlrd.open_workbook(testcase_file_path)
|
|
||||||
sh = xls.sheet_by_index(0)
|
|
||||||
# 获得公共的头部文本信息
|
|
||||||
common_header_text = sh.row_values(1)[2]
|
|
||||||
# 头部无效行数定义,文件头3行是描述文本和列表头部栏位,不作为测试用例内容
|
|
||||||
head_row_num = 3
|
|
||||||
# 头部无效行索引定义,索引从0开始,文件0~2索引是描述文本和列表头部栏位,不作为测试用例内容
|
|
||||||
head_row_index = head_row_num - 1
|
|
||||||
# 预判断有效测试用例行数(即处理头部定义外可以视为测试用例的行,但不一定准确,比如出现行乱填的情况,需要在程序中进行排除)
|
|
||||||
total_row_num = sh.nrows # 文件总行数
|
|
||||||
need_read_num = total_row_num - head_row_num # 需要读取的总行数
|
|
||||||
|
|
||||||
i = 1
|
|
||||||
testcase_list = []
|
|
||||||
print("读取到被测接口信息如下:")
|
|
||||||
while i <= need_read_num:
|
|
||||||
row_index = head_row_index + i # 获得需要读取的行索引
|
|
||||||
row_testcase_info = sh.row_values(row_index) # 获取到一行测试用例文本信息
|
|
||||||
|
|
||||||
is_execute = row_testcase_info[0]
|
|
||||||
if is_execute == '是': # 只有"是否执行"单元格为 是 时才将用例加入被执行序列
|
|
||||||
print(str(row_testcase_info)[0:120] + '......')
|
|
||||||
# 将每条测试用例组合为一个字典进行存储
|
|
||||||
testcase = {'interface_name': row_testcase_info[1], 'url': row_testcase_info[2],
|
|
||||||
'assert_type': row_testcase_info[6],
|
|
||||||
'assert_value': row_testcase_info[7]}
|
|
||||||
|
|
||||||
request_type = row_testcase_info[3]
|
|
||||||
testcase['request_type'] = request_type
|
|
||||||
|
|
||||||
body = row_testcase_info[5]
|
|
||||||
body.strip()
|
|
||||||
if len(body) > 0: # 如果body没有填值,则默认随便给一个任意值
|
|
||||||
testcase['body'] = eval(row_testcase_info[5])
|
|
||||||
else:
|
|
||||||
testcase['body'] = {"test": "test"}
|
|
||||||
headers = row_testcase_info[4] # 获得行中的headers文本
|
|
||||||
if headers == "公共头部": # 如果文本填写内文为 '公共头部',则取文件第二行的"公共头部信息"文本值
|
|
||||||
headers = common_header_text
|
|
||||||
testcase['headers'] = eval(headers)
|
|
||||||
testcase_list.append(testcase)
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
print('用例总数:\033[1;32;40m%s条\033[0m' % len(testcase_list))
|
|
||||||
return testcase_list
|
|
@ -1,21 +0,0 @@
|
|||||||
import colorama
|
|
||||||
from colorama import init, Fore, Back, Style
|
|
||||||
|
|
||||||
init(autoreset=True)
|
|
||||||
|
|
||||||
|
|
||||||
def output_report(result_list):
|
|
||||||
print('\033[1;33m========== 统计测试结果 ==========\033[0m')
|
|
||||||
print("执行总数: %s" % len(result_list))
|
|
||||||
success_count = 0
|
|
||||||
fail_count = 0
|
|
||||||
cost_time = 0
|
|
||||||
for result in result_list:
|
|
||||||
cost_time += result['cost_time']
|
|
||||||
if result['check_result']:
|
|
||||||
success_count += 1
|
|
||||||
else:
|
|
||||||
fail_count += 1
|
|
||||||
print('成功/失败:\033[1;32;40m%s\033[0m / \033[1;31;40m%s\033[0m' % (success_count, fail_count))
|
|
||||||
print("执行总时长:%s 秒\n" % round(cost_time, 3))
|
|
||||||
return
|
|
@ -1,17 +0,0 @@
|
|||||||
import executor
|
|
||||||
import read_testcase
|
|
||||||
import write_xls_report
|
|
||||||
import config
|
|
||||||
import reporter
|
|
||||||
|
|
||||||
# 1、读取测试用例列表文件
|
|
||||||
testcase_list = read_testcase.read(config.testcase_file_path)
|
|
||||||
|
|
||||||
# 2、执行用例列表中的用例
|
|
||||||
result_list = executor.run(testcase_list)
|
|
||||||
|
|
||||||
# 3、统计测试结果并在终端进行显示
|
|
||||||
reporter.output_report(result_list)
|
|
||||||
|
|
||||||
# 4、将测试结果写入xls文件中
|
|
||||||
write_xls_report.write(result_list)
|
|
@ -1,98 +0,0 @@
|
|||||||
import xlwt
|
|
||||||
import config
|
|
||||||
import time
|
|
||||||
import os
|
|
||||||
import json
|
|
||||||
import colorama
|
|
||||||
from colorama import init, Fore, Back, Style
|
|
||||||
|
|
||||||
init(autoreset=True)
|
|
||||||
|
|
||||||
|
|
||||||
def write(result_list):
|
|
||||||
"""
|
|
||||||
将执行测试结果的总汇内容写入xls文件中
|
|
||||||
:param result_list:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
# 读取配置文件,若开启xls报告,则进行xsl报告生成
|
|
||||||
if not config.xls_report:
|
|
||||||
return
|
|
||||||
if not os.path.exists(config.report_path): # 从配置文件中获取父目录路径,若目录不存在则进行创建
|
|
||||||
os.mkdir(config.report_path)
|
|
||||||
# 拼接生成的报告文件路径
|
|
||||||
report_path = os.path.join(config.report_path, time.strftime("%Y%m%d%H%M%S", time.localtime()) + '_report.xls')
|
|
||||||
print('\033[1;33m====== 生成xls格式的测试报告 ======\033[0m')
|
|
||||||
# 创建一个workbook 设置编码
|
|
||||||
workbook = xlwt.Workbook(encoding='utf-8')
|
|
||||||
# 创建一个worksheet
|
|
||||||
worksheet = workbook.add_sheet('测试结果')
|
|
||||||
# 设置列表头部样式
|
|
||||||
alignment = xlwt.Alignment()
|
|
||||||
alignment.horz = xlwt.Alignment.HORZ_CENTER
|
|
||||||
alignment.vert = xlwt.Alignment.VERT_CENTER
|
|
||||||
header_style = xlwt.XFStyle()
|
|
||||||
header_style.alignment = alignment
|
|
||||||
col1 = worksheet.col(0)
|
|
||||||
col1.width = 256 * 8
|
|
||||||
col2 = worksheet.col(1)
|
|
||||||
col2.width = 256 * 35
|
|
||||||
col3 = worksheet.col(2)
|
|
||||||
col3.width = 256 * 80
|
|
||||||
col4 = worksheet.col(3)
|
|
||||||
col4.width = 256 * 10
|
|
||||||
col5 = worksheet.col(4)
|
|
||||||
col5.width = 256 * 40
|
|
||||||
col6 = worksheet.col(5)
|
|
||||||
col6.width = 256 * 12
|
|
||||||
col7 = worksheet.col(6)
|
|
||||||
col7.width = 256 * 10
|
|
||||||
# 设置表头字体大小和颜色
|
|
||||||
font = xlwt.Font()
|
|
||||||
font.height = 20 * 12
|
|
||||||
font.colour_index = 17
|
|
||||||
header_style.font = font
|
|
||||||
# 设置头部第一行的行高
|
|
||||||
tall_style = xlwt.easyxf('font:height 480')
|
|
||||||
row1 = worksheet.row(0)
|
|
||||||
row1.set_style(tall_style)
|
|
||||||
|
|
||||||
# 定义表格头部栏文本
|
|
||||||
worksheet.write(0, 0, '序号', header_style)
|
|
||||||
worksheet.write(0, 1, '接口名称', header_style)
|
|
||||||
worksheet.write(0, 2, '被测接口', header_style)
|
|
||||||
worksheet.write(0, 3, '请求方式', header_style)
|
|
||||||
worksheet.write(0, 4, '请求参数', header_style)
|
|
||||||
worksheet.write(0, 5, '耗时(秒)', header_style)
|
|
||||||
worksheet.write(0, 6, '测试结果', header_style)
|
|
||||||
worksheet.write(0, 7, '失败备注', header_style)
|
|
||||||
|
|
||||||
# 结果单元格样式
|
|
||||||
col_style = xlwt.XFStyle()
|
|
||||||
col_style.alignment = alignment
|
|
||||||
style_success = xlwt.easyxf('pattern: pattern solid, fore_colour green')
|
|
||||||
style_success.alignment = alignment
|
|
||||||
style_fail = xlwt.easyxf('pattern: pattern solid, fore_colour red')
|
|
||||||
style_fail.alignment = alignment
|
|
||||||
|
|
||||||
index = 1 # 设置序号
|
|
||||||
for result in result_list: # 循环遍历出测试结果并按顺序写入xls文件中
|
|
||||||
worksheet.write(index, 0, index, col_style)
|
|
||||||
worksheet.write(index, 1, result['case_options']['interface_name'])
|
|
||||||
worksheet.write(index, 2, result['case_options']['url'])
|
|
||||||
worksheet.write(index, 3, str(result['case_options']['request_type']).upper(), col_style)
|
|
||||||
if result['case_options'].get("body", ) is not None: # 存在body参数时则输出到文件
|
|
||||||
worksheet.write(index, 4, json.dumps(result['case_options'].get('body', )))
|
|
||||||
worksheet.write(index, 5, result['cost_time'], col_style)
|
|
||||||
res = "通过" if result['check_result'] else '失败' # 通过检测结果True和False来重新设置结果文本问 通过和失败
|
|
||||||
|
|
||||||
if result['check_result']:
|
|
||||||
worksheet.write(index, 6, res, style_success) # 成功文本背景染色为绿色
|
|
||||||
else:
|
|
||||||
worksheet.write(index, 6, res, style_fail) # 成功文本背景染色为红色
|
|
||||||
worksheet.write(index, 7, '断言内容:' + str(result['case_options']['assert_value']) + "\n\r实际返回:" + str(
|
|
||||||
result['response_result'])[0:30000]) # 失败用例,将断言内容和实际结果进行输出,实际结果输出长度在30000以内
|
|
||||||
index += 1
|
|
||||||
workbook.save(report_path)
|
|
||||||
print("报告成功创建:" + str(report_path))
|
|
||||||
return
|
|
Loading…
Reference in New Issue
Block a user