@@ -0,0 +1,2 @@ | |||||
# Default ignored files | |||||
/workspace.xml |
@@ -0,0 +1,6 @@ | |||||
<component name="InspectionProjectProfileManager"> | |||||
<settings> | |||||
<option name="USE_PROJECT_PROFILE" value="false" /> | |||||
<version value="1.0" /> | |||||
</settings> | |||||
</component> |
@@ -0,0 +1,15 @@ | |||||
<?xml version="1.0" encoding="UTF-8"?> | |||||
<module type="PYTHON_MODULE" version="4"> | |||||
<component name="NewModuleRootManager"> | |||||
<content url="file://$MODULE_DIR$" /> | |||||
<orderEntry type="inheritedJdk" /> | |||||
<orderEntry type="sourceFolder" forTests="false" /> | |||||
</component> | |||||
<component name="PyDocumentationSettings"> | |||||
<option name="format" value="PLAIN" /> | |||||
<option name="myDocStringFormat" value="Plain" /> | |||||
</component> | |||||
<component name="TestRunnerService"> | |||||
<option name="PROJECT_TEST_RUNNER" value="pytest" /> | |||||
</component> | |||||
</module> |
@@ -0,0 +1,7 @@ | |||||
<?xml version="1.0" encoding="UTF-8"?> | |||||
<project version="4"> | |||||
<component name="JavaScriptSettings"> | |||||
<option name="languageLevel" value="ES6" /> | |||||
</component> | |||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10" project-jdk-type="Python SDK" /> | |||||
</project> |
@@ -0,0 +1,8 @@ | |||||
<?xml version="1.0" encoding="UTF-8"?> | |||||
<project version="4"> | |||||
<component name="ProjectModuleManager"> | |||||
<modules> | |||||
<module fileurl="file://$PROJECT_DIR$/.idea/jiekou-python3.iml" filepath="$PROJECT_DIR$/.idea/jiekou-python3.iml" /> | |||||
</modules> | |||||
</component> | |||||
</project> |
@@ -0,0 +1,6 @@ | |||||
<?xml version="1.0" encoding="UTF-8"?> | |||||
<project version="4"> | |||||
<component name="VcsDirectoryMappings"> | |||||
<mapping directory="$PROJECT_DIR$" vcs="Git" /> | |||||
</component> | |||||
</project> |
@@ -0,0 +1,29 @@ | |||||
""" | |||||
@author: lileilei | |||||
@file: dubbo_feng.py | |||||
@time: 2018/3/29 12:26 | |||||
""" | |||||
from pyhessian.client import HessianProxy | |||||
from pyhessian import protocol | |||||
from public.log import LOG, logger | |||||
@logger('dubbo接口') | |||||
class DubboInterface: | |||||
def __init__(self, url, interface, method, param, **kwargs): | |||||
self.url = url | |||||
self.interface = interface | |||||
self.method = method | |||||
self.param = param | |||||
self.interfaceparam = protocol.object_factory(self.param, **kwargs) | |||||
def getresult(self): | |||||
try: | |||||
result = HessianProxy(self.url + self.interface) | |||||
return_result = getattr(result, self.method)(self.interfaceparam) | |||||
LOG.info('测试返回结果:%s' % return_result) | |||||
res = {'code': 0, 'result': return_result} | |||||
except Exception as e: | |||||
LOG.info('测试失败,原因:%s' % e) | |||||
res = {'code': 1, 'result': e} | |||||
return res |
@@ -0,0 +1,29 @@ | |||||
# -*- coding: utf-8 -*- | |||||
# @Time : 2017/6/4 20:36 | |||||
# @Author : lileilei | |||||
# @Site : | |||||
# @File : testFengzhuang.py | |||||
from Public.test_requests import requ | |||||
class TestApi(object): | |||||
def __init__(self, url, parame, method): | |||||
self.url = url | |||||
self.parame = parame | |||||
self.method = method | |||||
self.reques = requ() | |||||
def testapi(self): | |||||
if self.method == 'POST': | |||||
self.response = self.reques.post(self.url, self.parame) | |||||
elif self.method == "GET": | |||||
self.response = self.reques.get(url=self.url, params=self.parame) | |||||
elif self.method == "PUT": | |||||
self.response = self.reques.putparams(url=self.url, params=self.parame) | |||||
elif self.method == "DELETE": | |||||
self.response = self.reques.delparams(url=self.url, params=self.parame) | |||||
return self.response | |||||
def getJson(self): | |||||
json_data = self.testapi() | |||||
return json_data |
@@ -0,0 +1 @@ | |||||
# -*- coding: utf-8 -*- # @Author : leizi import requests, json from public.log import LOG, logger @logger('requests封装') class requ(): def __init__(self): self.headers = { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:51.0) Gecko/20100101 Firefox/51.0"} def get(self, url): # get消息 try: r = requests.get(url, headers=self.headers) r.encoding = 'UTF-8' json_response = json.loads(r.text) return json_response except Exception as e: LOG.info('get请求出错,出错原因:%s' % e) print('get请求出错,出错原因:%s' % e) return {} def post(self, url, params): # post消息 data = json.dumps(params) try: r = requests.post(url, params=params, headers=self.headers) json_response = json.loads(r.text) return json_response except Exception as e: LOG.info('post请求出错,出错原因:%s' % e) print('post请求出错,原因:%s' % e) def delfile(self, url, params): # 删除的请求 try: del_word = requests.delete(url, params, headers=self.headers) json_response = json.loads(del_word.text) return json_response except Exception as e: LOG.info('del请求出错,出错原因:%s' % e) print('del请求出错,原因:%s' % e) return {} def putfile(self, url, params): # put请求 try: data = json.dumps(params) me = requests.put(url, data) json_response = json.loads(me.text) return json_response except Exception as e: LOG.info('put请求出错,出错原因:%s' % e) print('put请求出错,原因:%s' % e) return json_response |
@@ -0,0 +1,27 @@ | |||||
""" | |||||
@author: lileilei | |||||
@file: Dingtalk.py | |||||
@time: 2017/12/26 17:34 | |||||
""" | |||||
'''封装钉钉群发消息''' | |||||
import requests, json | |||||
from config.config import Dingtalk_access_token | |||||
def send_ding(content): | |||||
url = Dingtalk_access_token | |||||
pagrem = { | |||||
"msgtype": "text", | |||||
"text": { | |||||
"content": content | |||||
}, | |||||
"isAtAll": True | |||||
} | |||||
headers = { | |||||
'Content-Type': 'application/json' | |||||
} | |||||
f = requests.post(url, data=json.dumps(pagrem), headers=headers) | |||||
if f.status_code == 200: | |||||
return True | |||||
else: | |||||
return False |
@@ -0,0 +1,6 @@ | |||||
# -*- coding: utf-8 -*- | |||||
# @Time : 2017/6/4 17:34 | |||||
# @Author : lileilei | |||||
# @Site : | |||||
# @File : __init__.py.py | |||||
# @Software: PyCharm |
@@ -0,0 +1,18 @@ | |||||
# encoding: utf-8 | |||||
""" | |||||
@author: lileilei | |||||
@file: create_report.py | |||||
@time: 2017/8/3 12:27 | |||||
""" | |||||
from Public.log import LOG, logger | |||||
@logger('保存测试结果') | |||||
def save_result(testtime, toial, passnum, fail): | |||||
try: | |||||
f = open('result.txt', 'a') | |||||
f.write("%s=%s=%s=%s \n" % (testtime, toial, passnum, fail)) | |||||
f.close() | |||||
except: | |||||
LOG.info('保存测试结果出错,原因:%s' % Exception) | |||||
print('记录测试结果失败') |
@@ -0,0 +1,35 @@ | |||||
# -*- coding: utf-8 -*- | |||||
# @Author : leizi | |||||
import smtplib, time, os | |||||
from email.mime.text import MIMEText | |||||
from email.mime.multipart import MIMEMultipart | |||||
import yaml | |||||
def load_emil_setting(): # 从配置文件中加载获取email的相关信息 | |||||
filepath = os.path.join(os.path.join(os.getcwd(), 'config'), 'email.yaml') | |||||
data_file = open(filepath, "r") | |||||
datas = yaml.load(data_file, Loader=yaml.FullLoader) | |||||
data_file.close() | |||||
return (datas['foremail'], datas['password'], datas['toeamil'], datas['title']) | |||||
def sendemali(filepath): # 发送email | |||||
from_addr, password, mail_to, mail_body = load_emil_setting() | |||||
msg = MIMEMultipart() | |||||
msg['Subject'] = '接口自动化测试报告' | |||||
msg['From'] = '自动化测试平台' | |||||
msg['To'] = mail_to | |||||
msg['Date'] = time.strftime('%a, %d %b %Y %H:%M:%S %z') | |||||
att = MIMEText(open(r'%s' % filepath, 'rb').read(), 'base64', 'utf-8') | |||||
att["Content-Type"] = 'application/octet-stream' | |||||
att["Content-Disposition"] = 'attachment; filename="pyresult.html"' | |||||
txt = MIMEText("这是测试报告的邮件,详情见附件", 'plain', 'gb2312') | |||||
msg.attach(txt) | |||||
msg.attach(att) | |||||
smtp = smtplib.SMTP() | |||||
server = smtplib.SMTP_SSL("smtp.qq.com", 465) | |||||
server.login(from_addr, password) | |||||
server.sendmail(from_addr, mail_to, msg.as_string()) | |||||
server.quit() |
@@ -0,0 +1,36 @@ | |||||
""" | |||||
@author: lileilei | |||||
@file: python_dict.py | |||||
@time: 2018/6/15 13:54 | |||||
""" | |||||
'''字典取值''' | |||||
def res(d, code): | |||||
result = [] | |||||
if isinstance(d, dict) and code in d.keys(): | |||||
value = d[code] | |||||
result.append(value) | |||||
return result | |||||
elif isinstance(d, (list, tuple)): | |||||
for item in d: | |||||
value = res(item, code) | |||||
if value == "None" or value is None: | |||||
pass | |||||
elif len(value) == 0: | |||||
pass | |||||
else: | |||||
result.append(value) | |||||
return result | |||||
else: | |||||
if isinstance(d, dict): | |||||
for k in d: | |||||
value = res(d[k], code) | |||||
if value == "None" or value is None: | |||||
pass | |||||
elif len(value) == 0: | |||||
pass | |||||
else: | |||||
for item in value: | |||||
result.append(item) | |||||
return result |
@@ -0,0 +1,50 @@ | |||||
# -*- coding: utf-8 -*- | |||||
# @Time : 2017/6/4 20:35 | |||||
# @Author : lileilei | |||||
# @File : get_excel.py | |||||
import xlrd, os | |||||
from Public.log import LOG, logger | |||||
@logger('解析测试用例文件') | |||||
def datacel(filepath): | |||||
try: | |||||
file = xlrd.open_workbook(filepath) | |||||
print(file) | |||||
rslut = file.sheets()[0] | |||||
nrows = rslut.nrows | |||||
listid = [] | |||||
listkey = [] | |||||
listconeent = [] | |||||
listurl = [] | |||||
listmethod = [] | |||||
listassert = [] | |||||
listname = [] | |||||
for i in range(1, nrows): | |||||
listid.append(rslut.cell(i, 0).value) | |||||
listkey.append(rslut.cell(i, 2).value) | |||||
listconeent.append(rslut.cell(i, 3).value) | |||||
listurl.append(rslut.cell(i, 4).value) | |||||
listname.append(rslut.cell(i, 1).value) | |||||
listmethod.append((rslut.cell(i, 5).value)) | |||||
listassert.append((rslut.cell(i, 6).value)) | |||||
return listid, listkey, listconeent, listurl, listmethod, listassert, listname | |||||
except Exception as e: | |||||
print(e) | |||||
LOG.info('打开测试用例失败,原因是:%s' % e) | |||||
return | |||||
@logger('生成数据驱动所用数据') | |||||
def makedata(): | |||||
path = os.path.join(os.path.join(os.getcwd(), 'test_case_data'), 'case.xlsx') | |||||
listid, listkey, listconeent, listurl, listmethod, listassert, listname = datacel(path) | |||||
make_data = [] | |||||
for i in range(len(listid)): | |||||
make_data.append({'url': listurl[i], 'key': listkey[i], | |||||
'coneent': listconeent[i], 'method': listmethod[i], | |||||
'assertconnect': listassert[i], | |||||
'id': listid[i]}, | |||||
) | |||||
i += 1 | |||||
return make_data |
@@ -0,0 +1,20 @@ | |||||
""" | |||||
@author: lileilei | |||||
@file: get_excel_new.py | |||||
@time: 2018/4/30 11:04 | |||||
""" | |||||
'''读取Excel''' | |||||
import xlrd | |||||
def datacel(filrpath): | |||||
all_case = [] | |||||
file = xlrd.open_workbook(filrpath) | |||||
me = file.sheets()[0] | |||||
nrows = me.nrows | |||||
for i in range(1, nrows): | |||||
all_case.append({"id": me.cell(i, 0).value, 'key': me.cell(i, 2).value, | |||||
'coneent': me.cell(i, 3).value, 'url': me.cell(i, 4).value, | |||||
'name': me.cell(i, 1).value, 'fangshi': me.cell(i, 5).value, | |||||
'assert': me.cell(i, 6).value}) | |||||
return all_case |
@@ -0,0 +1,47 @@ | |||||
# -*- coding: utf-8 -*- | |||||
# @Date : 2017-10-14 15:35:17 | |||||
# @Author : leizi | |||||
'''日志模块''' | |||||
import os | |||||
import logbook | |||||
from logbook.more import ColorizedStderrHandler | |||||
from functools import wraps | |||||
check_path = '.' | |||||
LOG_DIR = os.path.join(check_path, 'log') | |||||
file_stream = False | |||||
if not os.path.exists(LOG_DIR): | |||||
os.makedirs(LOG_DIR) | |||||
file_stream = True | |||||
def get_logger(name='interface_case_run', file_log=file_stream, level=''): | |||||
""" get logger Factory function """ | |||||
logbook.set_datetime_format('local') | |||||
ColorizedStderrHandler(bubble=False, level=level).push_thread() | |||||
logbook.TimedRotatingFileHandler( | |||||
os.path.join(LOG_DIR, '%s.log' % name), | |||||
date_format='%Y_%m_%d_%H', bubble=True, encoding='utf-8').push_thread() | |||||
return logbook.Logger(name) | |||||
LOG = get_logger(file_log=file_stream, level='INFO') | |||||
def logger(param): | |||||
""" fcuntion from logger meta """ | |||||
def wrap(function): | |||||
""" logger wrapper """ | |||||
@wraps(function) | |||||
def _wrap(*args, **kwargs): | |||||
""" wrap tool """ | |||||
LOG.info("当前模块 {}".format(param)) | |||||
LOG.info("全部args参数参数信息 , {}".format(str(args))) | |||||
LOG.info("全部kwargs参数信息 , {}".format(str(kwargs))) | |||||
return function(*args, **kwargs) | |||||
return _wrap | |||||
return wrap |
@@ -0,0 +1,32 @@ | |||||
# -*- coding: utf-8 -*- | |||||
# @Date : 2017-08-02 21:54:08 | |||||
# @Author : lileilei | |||||
from Public.fengzhuang_dict import res | |||||
from .log import LOG, logger | |||||
@logger('断言测试结果') | |||||
def assert_in(asserassert, returnjson): | |||||
if len(asserassert.split('=')) > 1: | |||||
data = asserassert.split('&') | |||||
result = dict([(item.split('=')) for item in data]) | |||||
value1 = ([(str(res(returnjson, key))) for key in result.keys()]) | |||||
value2 = ([(str(value)) for value in result.values()]) | |||||
if value1 == value2: | |||||
return {'code': 0, "result": 'pass'} | |||||
else: | |||||
return {'code': 1, 'result': 'fail'} | |||||
else: | |||||
LOG.info('填写测试预期值') | |||||
return {"code": 2, 'result': '填写测试预期值'} | |||||
@logger('断言测试结果') | |||||
def assertre(asserassert): | |||||
if len(asserassert.split('=')) > 1: | |||||
data = asserassert.split('&') | |||||
result = dict([(item.split('=')) for item in data]) | |||||
return result | |||||
else: | |||||
LOG.info('填写测试预期值') | |||||
raise {"code": 1, 'result': '填写测试预期值'} |
@@ -0,0 +1,180 @@ | |||||
# encoding: utf-8 | |||||
""" | |||||
@author: lileilei | |||||
@file: py_Html.py | |||||
@time: 2017/6/5 17:04 | |||||
""" | |||||
titles = '接口测试' | |||||
def title(titles): | |||||
title = '''<!DOCTYPE html> | |||||
<html> | |||||
<head> | |||||
<title>%s</title> | |||||
<meta charset="UTF-8"> | |||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |||||
<!-- 引入 Bootstrap --> | |||||
<link href="https://cdn.bootcss.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"> | |||||
<!-- HTML5 Shim 和 Respond.js 用于让 IE8 支持 HTML5元素和媒体查询 --> | |||||
<!-- 注意: 如果通过 file:// 引入 Respond.js 文件,则该文件无法起效果 --> | |||||
<!--[if lt IE 9]> | |||||
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script> | |||||
<script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script> | |||||
<![endif]--> | |||||
<style type="text/css"> | |||||
.hidden-detail,.hidden-tr{ | |||||
display:none; | |||||
} | |||||
</style> | |||||
</head> | |||||
<body> | |||||
''' % (titles) | |||||
return title | |||||
connent = ''' | |||||
<div class='col-md-4 col-md-offset-4' style='margin-left:3%;'> | |||||
<h1>接口测试的结果</h1>''' | |||||
def shouye(starttime, endtime, passge, fail, excepthions, weizhicuowu): | |||||
beijing = ''' | |||||
<table class="table table-hover table-condensed"> | |||||
<tbody> | |||||
<tr> | |||||
<td><strong>开始时间:</strong> %s</td> | |||||
</tr> | |||||
<td><strong>结束时间:</strong> %s</td></tr> | |||||
<td><strong>耗时:</strong> %s</td></tr> | |||||
<td><strong>结果:</strong> | |||||
<span >Pass: <strong >%s</strong> | |||||
Fail: <strong >%s</strong> | |||||
exception: <strong >%s</strong> | |||||
weizhicuowu : <strong >%s</strong></span></td> | |||||
</tr> | |||||
</tbody></table> | |||||
</div> ''' % (starttime, endtime, (endtime - starttime), passge, fail, excepthions, weizhicuowu) | |||||
return beijing | |||||
shanghai = '''<div class="row " style="margin:60px"> | |||||
<div style=' margin-top: 18%;' > | |||||
<div class="btn-group" role="group" aria-label="..."> | |||||
<button type="button" id="check-all" class="btn btn-primary">所有用例</button> | |||||
<button type="button" id="check-success" class="btn btn-success">成功用例</button> | |||||
<button type="button" id="check-danger" class="btn btn-danger">失败用例</button> | |||||
<button type="button" id="check-warning" class="btn btn-warning">错误用例</button> | |||||
<button type="button" id="check-except" class="btn btn-defult">异常用例</button> | |||||
</div> | |||||
<div class="btn-group" role="group" aria-label="..."> | |||||
</div> | |||||
<table class="table table-hover table-condensed table-bordered" style="word-wrap:break-word; word-break:break-all; margin-top: 7px;"> | |||||
<tr > | |||||
<td ><strong>用例ID </strong></td> | |||||
<td><strong>用例名字</strong></td> | |||||
<td><strong>key</strong></td> | |||||
<td><strong>请求内容</strong></td> | |||||
<td><strong>url</strong></td> | |||||
<td><strong>请求方式</strong></td> | |||||
<td><strong>预期</strong></td> | |||||
<td><strong>实际返回</strong></td> | |||||
<td><strong>结果</strong></td> | |||||
</tr> | |||||
''' | |||||
def passfail(tend): | |||||
if tend == 'pass': | |||||
htl = '''<td bgcolor="green">pass</td>''' | |||||
elif tend == 'fail': | |||||
htl = '''<td bgcolor="fail">fail</td>''' | |||||
elif tend == 'weizhi': | |||||
htl = '''<td bgcolor="red">error</td>''' | |||||
else: | |||||
htl = '<td bgcolor="crimson">exect</td>' | |||||
return htl | |||||
def ceshixiangqing(reslt, id, name, key, coneent, url, meth, yuqi, json, relust): | |||||
xiangqing = ''' | |||||
<tr class="case-tr %s"> | |||||
<td>%s</td> | |||||
<td>%s</td> | |||||
<td>%s</td> | |||||
<td>%s</td> | |||||
<td>%s</td> | |||||
<td>%s</td> | |||||
<td>%s</td> | |||||
<td>%s</td> | |||||
%s | |||||
</tr> | |||||
''' % (reslt, id, name, key, coneent, url, meth, yuqi, json, passfail(relust)) | |||||
return xiangqing | |||||
weibu = '''</div></div></table><script src="https://code.jquery.com/jquery.js"></script> | |||||
<script src="https://cdn.bootcss.com/bootstrap/3.3.6/js/bootstrap.min.js"></script> | |||||
<script type="text/javascript"> | |||||
$("#check-danger").click(function(e){ | |||||
$(".case-tr").removeClass("hidden-tr"); | |||||
$(".success").addClass("hidden-tr"); | |||||
$(".warning").addClass("hidden-tr"); | |||||
$(".error").addClass("hidden-tr"); | |||||
}); | |||||
$("#check-warning").click(function(e){ | |||||
$(".case-tr").removeClass("hidden-tr"); | |||||
$(".success").addClass("hidden-tr"); | |||||
$(".danger").addClass("hidden-tr"); | |||||
$(".error").addClass("hidden-tr"); | |||||
}); | |||||
$("#check-success").click(function(e){ | |||||
$(".case-tr").removeClass("hidden-tr"); | |||||
$(".warning").addClass("hidden-tr"); | |||||
$(".danger").addClass("hidden-tr"); | |||||
$(".error").addClass("hidden-tr"); | |||||
}); | |||||
$("#check-except").click(function(e){ | |||||
$(".case-tr").removeClass("hidden-tr"); | |||||
$(".warning").addClass("hidden-tr"); | |||||
$(".danger").addClass("hidden-tr"); | |||||
$(".success").addClass("hidden-tr"); | |||||
}); | |||||
$("#check-all").click(function(e){ | |||||
$(".case-tr").removeClass("hidden-tr"); | |||||
}); | |||||
</script> | |||||
</body></html>''' | |||||
def relust(titles, starttime, endtime, passge, fail, id, name, key, coneent, url, meth, yuqi, json, relust, exceptions, | |||||
weizhi): | |||||
if type(name) == list: | |||||
relus = ' ' | |||||
for i in range(len(name)): | |||||
if relust[i] == "pass": | |||||
clazz = "success" | |||||
elif relust[i] == "fail": | |||||
clazz = "warning" | |||||
elif relust[i] == "weizhi": | |||||
clazz = "danger" | |||||
else: | |||||
clazz = 'error' | |||||
relus += ( | |||||
ceshixiangqing(clazz, id[i], name[i], key[i], coneent[i], url[i], meth[i], yuqi[i], json[i], relust[i])) | |||||
text = title(titles) + connent + shouye(starttime, endtime, passge, fail, exceptions, | |||||
weizhi) + shanghai + relus + weibu | |||||
else: | |||||
text = title(titles) + connent + shouye(starttime, endtime, passge, fail, exceptions, | |||||
weizhi) + shanghai + ceshixiangqing(id, name, key, coneent, url, meth, | |||||
yuqi, json, relust) + weibu | |||||
return text | |||||
def createHtml(filepath, titles, starttime, endtime, passge, fail, id, name, key, coneent, url, meth, yuqi, json, | |||||
relusts, exceptions, weizhi): | |||||
texts = relust(titles, starttime, endtime, passge, fail, id, name, key, coneent, url, meth, yuqi, json, relusts, | |||||
exceptions, weizhi) | |||||
with open(filepath, 'wb') as f: | |||||
f.write(texts.encode('utf-8')) |
@@ -0,0 +1,113 @@ | |||||
# encoding: utf-8 | |||||
""" | |||||
@author: lileilei | |||||
@file: pyreport_excel.py | |||||
@time: 2017/6/7 8:47 | |||||
""" | |||||
import os, xlwt, yaml | |||||
from xlwt import * | |||||
def yangshi1(): | |||||
style = XFStyle() | |||||
fnt = Font() | |||||
fnt.name = u'微软雅黑' | |||||
fnt.bold = True | |||||
style.font = fnt | |||||
alignment = xlwt.Alignment() | |||||
alignment.horz = xlwt.Alignment.HORZ_CENTER | |||||
alignment.vert = xlwt.Alignment.VERT_CENTER | |||||
style.alignment = alignment # 给样式添加文字居中属性 | |||||
style.font.height = 430 # 设置字体大小 | |||||
return style | |||||
def yangshi2(): | |||||
style1 = XFStyle() | |||||
alignment = xlwt.Alignment() | |||||
alignment.horz = xlwt.Alignment.HORZ_CENTER | |||||
alignment.vert = xlwt.Alignment.VERT_CENTER | |||||
style1.alignment = alignment # 给样式添加文字居中属性 | |||||
style1.font.height = 330 # 设置字体大小 | |||||
return style1 | |||||
def yangshi3(): | |||||
style1 = XFStyle() | |||||
style1.font.height = 330 # 设置字体大小 | |||||
return style1 | |||||
def yangshique(me): | |||||
if me == 'pass': | |||||
style = yangshi1() | |||||
Pattern = xlwt.Pattern() | |||||
Pattern.pattern = xlwt.Pattern.SOLID_PATTERN | |||||
Pattern.pattern_fore_colour = xlwt.Style.colour_map['green'] | |||||
style.pattern = Pattern | |||||
else: | |||||
style = yangshi2() | |||||
Pattern = xlwt.Pattern() | |||||
Pattern.pattern = xlwt.Pattern.SOLID_PATTERN | |||||
Pattern.pattern_fore_colour = xlwt.Style.colour_map['red'] | |||||
style.pattern = Pattern | |||||
return style | |||||
def create(filename, list_pass, list_fail, listids, listnames, listkeys, listconeents, listurls, listfangshis, | |||||
listqiwangs, list_json, listrelust): | |||||
filepath = open(os.path.join(os.path.join(os.getcwd(), 'config'), 'test_report.yaml'), encoding='utf-8') | |||||
file_config = yaml.load(filepath, Loader=yaml.FullLoader) | |||||
file = Workbook(filename) | |||||
table = file.add_sheet('测试结果', cell_overwrite_ok=True) | |||||
style = yangshi1() | |||||
for i in range(0, 7): | |||||
table.col(i).width = 380 * 20 | |||||
style1 = yangshi2() | |||||
table.write_merge(0, 0, 0, 6, '测试报告', style=style) | |||||
table.write_merge(1, 1, 0, 6, '', style=style) | |||||
table.write_merge(2, 3, 0, 6, '测试详情', style=style1) | |||||
table.write(4, 0, '项目名称', style=style1) | |||||
table.write(5, 0, '接口版本', style=style1) | |||||
table.write(6, 0, '提测时间', style=style1) | |||||
table.write(7, 0, '提测人', style=style1) | |||||
table.write(4, 2, '测试人', style=style1) | |||||
table.write(5, 2, '测试时间', style=style1) | |||||
table.write(6, 2, '审核人', style=style1) | |||||
table.write(4, 4, '通过', style=style1) | |||||
table.write(5, 4, '失败', style=style1) | |||||
table.write(6, 4, '成功率', style=style1) | |||||
table.write(4, 1, (file_config['projectname']), style=style1) | |||||
table.write(5, 1, file_config['interfaceVersion'], style=style1) | |||||
table.write(6, 1, file_config['tijiao_time'], style=style1) | |||||
table.write(7, 1, file_config['tijiao_person'], style=style1) | |||||
table.write(4, 3, file_config['ceshi_person'], style=style1) | |||||
table.write(5, 3, file_config['ceshi_time'], style=style1) | |||||
table.write(6, 3, file_config['shenhename'], style=style1) | |||||
table.write(4, 5, (list_pass), style=style1) | |||||
table.write(5, 5, (list_fail), style=style1) | |||||
table.write(6, 5, ('%.2f%%' % ((list_pass) / (len(listrelust)))), style=style1) | |||||
table1 = file.add_sheet('测试详情', cell_overwrite_ok=True) | |||||
table1.write_merge(0, 0, 0, 8, '测试详情', style=style) | |||||
for i in range(0, 8): | |||||
table1.col(i).width = 400 * 20 | |||||
table1.write(1, 0, '用例ID', style=yangshi3()) | |||||
table1.write(1, 1, '用例名字', style=yangshi3()) | |||||
table1.write(1, 2, 'key', style=yangshi3()) | |||||
table1.write(1, 3, '请求内容', style=yangshi3()) | |||||
table1.write(1, 4, ' url', style=yangshi3()) | |||||
table1.write(1, 5, '请求方式', style=yangshi3()) | |||||
table1.write(1, 6, '预期', style=yangshi3()) | |||||
table1.write(1, 7, '实际返回', style=yangshi3()) | |||||
table1.write(1, 8, '结果', style=yangshi3()) | |||||
for i in range(len(listids)): | |||||
table1.write(i + 1, 0, listids[i], style=yangshi3()) | |||||
table1.write(i + 1, 1, listnames[i], style=yangshi3()) | |||||
table1.write(i + 1, 2, listkeys[i], style=yangshi3()) | |||||
table1.write(i + 1, 3, listconeents[i], style=yangshi3()) | |||||
table1.write(i + 1, 4, listurls[i], style=yangshi3()) | |||||
table1.write(i + 1, 5, listfangshis[i], style=yangshi3()) | |||||
table1.write(i + 1, 6, listqiwangs[i], style=yangshi3()) | |||||
table1.write(i + 1, 7, str(list_json[i]), style=yangshi3()) | |||||
table1.write(i + 1, 8, listrelust[i], style=yangshique(listrelust[i])) | |||||
file.save(filename) |
@@ -0,0 +1 @@ | |||||
# -*- coding: utf-8 -*- # @Author : leizi import requests, json from requests import Timeout, RequestException class requ(): def __init__(self): self.headers = { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:51.0) Gecko/20100101 Firefox/51.0"} def get(self, url, params): # get消息 try: r = requests.get(url, params=params, headers=self.headers) r.encoding = 'UTF-8' if r.status_code == 200: json_response = json.loads(r.text) return {'code': 0, 'result': json_response} else: return {'code': 1, 'result': '接口请求失败,返回状态码:%s' % str(r.status_code)} except Timeout as e: return {'code': 1, 'result': '请求超时:%s' % e} except RequestException as e: return {'code': 1, 'result': '请求异常:%s' % e} except Exception as e: return {'code': 1, 'result': 'get请求出错,出错原因:%s' % e} def post(self, url, params): # post消息 data = json.dumps(params) try: r = requests.post(url, params=data, headers=self.headers) if r.status_code == 200: json_response = json.loads(r.text) return {'code': 0, 'result': json_response} else: return {'code': 1, 'result': '接口请求失败,返回状态码:%s' % str(r.status_code)} except Timeout as e: return {'code': 1, 'result': '请求超时:%s' % e} except RequestException as e: return {'code': 1, 'result': '请求异常:%s' % e} except Exception as e: return {'code': 1, 'result': 'post请求出错,出错原因:%s' % e} def delparams(self, url, params): # 删除的请求 try: del_word = requests.delete(url, params=params, headers=self.headers) if del_word.status_code == 200: json_response = json.loads(del_word.text) return {'code': 0, 'result': json_response} else: return {'code': 1, 'result': '接口请求失败,返回状态码:%s' % str(del_word.status_code)} except Timeout as e: return {'code': 1, 'result': '请求超时:%s' % e} except RequestException as e: return {'code': 1, 'result': '请求异常:%s' % e} except Exception as e: return {'code': 1, 'result': 'del请求出错,出错原因:%s' % e} def putparams(self, url, params): # put请求 try: data = json.dumps(params) result = requests.put(url, data) if result.status_code == 200: json_response = json.loads(result.text) return {'code': 0, 'result': json_response} else: return {'code': 1, 'result': '接口请求失败,返回状态码:%s' % str(result.status_code)} except Timeout as e: return {'code': 1, 'result': '请求超时:%s' % e} except RequestException as e: return {'code': 1, 'result': '请求异常:%s' % e} except Exception as e: return {'code': 1, 'result': 'put请求出错,出错原因:%s' % e} |
@@ -0,0 +1,37 @@ | |||||
# 接口测试框架(基于json格式、http请求,python3,不兼容python2.x版本) | |||||
## 注:现在基于Excel文件管理测试用例基本实现,) | |||||
## 备注:大家在运行的时候,如果参数不需要key,只需要字典,可以在ddt_case.py和case.py改造parame,注释掉现在的parem,启用新的即可 | |||||
## 依赖用例支持用例执行,在testCase的ddt_case.py有实现,逻辑在代码中有写,参数的格式{"name":"$case1=data"}即代表name的值是case1的data字段,简单的实现。 | |||||
## 依赖用例是简单的实现,具体在业务上面还有很多复杂的要处理,知识实现了,部分的思路。 | |||||
## (目前在部分window上会出现FileNotFoundError [Errno 2] No such file or directory,这个bug是路径过长,解决方案为吧log日志放在当前目录,或者修改动态生成的文件的名字,给了第一种方式,测试日志放在当前目录) | |||||
## qq交流群:194704520 | |||||
### 使用的库 requests,绝大部分是基于Python原有的库进行的,这样简单方便, | |||||
### 使用脚本参数分离等思想,尽可能降低代码的耦合度。 | |||||
### 如果你不配置钉钉机器人,注释到机器人相关的代码 | |||||
# 首先我们来看下我们的目录 | |||||
## | |||||
![Alt text](https://github.com/liwanlei/jiekou-python3/blob/master/img/xiangmujiegoutu.png) | |||||
## | |||||
### 1.Case文件夹用来存放我们的测试用例相关的, | |||||
### 2.test_case用来存储我们的测试数据,Excel管理测试用例,yaml文件管理测试用例,后续要把yaml管理测试用例的也封装出来。 | |||||
### 3.Interface对测试接口相关的封装,包括requests库,发送测试报告的email的封装,从Excel取测试数据的封装 | |||||
### 4.Public 展示测试报告相关的脚本,这里可以自己封装,也可以使用现成的,我这里是基于我自己封装的,最后生成的测试报告更加易懂,出错可以尽快排查相关原因 | |||||
### 5.report 存放测试报告, | |||||
### 6.run_excel_re.py/run_html.py 主运行文件。运行后可以生成相应的测试报告 | |||||
### 7.run_new新版执行方式,重写了unittest方法,利用ddt驱动,生成漂亮的测试报告 | |||||
## | |||||
## 除了在github的开源项目的分享,我也运营了自己的公众号,欢迎大家关注我的公众号 | |||||
![Alt text](https://github.com/liwanlei/jiekou-python3/blob/master/img/%E5%85%AC%E4%BC%97%E5%8F%B7%E6%B5%B7%E6%8A%A5.jpeg) | |||||
## 产生的html测试报告如下 | |||||
![Alt text](https://github.com/liwanlei/jiekou/blob/master/img/cebaogaotu.png) | |||||
## | |||||
### 增加了Excel管理测试报告的功能,目前在继续优化功能,增加了config目录,一些配置文件的目录, | |||||
## | |||||
## 产生的Excel测试报告如下 | |||||
![Alt text](https://github.com/liwanlei/jiekou/blob/master/img/excel.png) | |||||
![Alt text](https://github.com/liwanlei/jiekou/blob/master/img/excel2.png) | |||||
### 现在的测试结构更加完整,最新的一次提交增加了log日志的展示,使功能更加完善,log日志在控制台展示如下,对目录进行优化 | |||||
![Alt text](https://github.com/liwanlei/jiekou/blob/master/img/log.png) | |||||
@@ -0,0 +1,5 @@ | |||||
""" | |||||
@author: lileilei | |||||
@file: __init__.py | |||||
@time: 2018/4/12 14:17 | |||||
""" |
@@ -0,0 +1,8 @@ | |||||
""" | |||||
@author: lileilei | |||||
@file: config.py | |||||
@time: 2018/4/12 14:17 | |||||
""" | |||||
Dingtalk_access_token = "" # 钉钉配置 | |||||
TestPlanUrl = 'http://localhost:8881' # 基础url | |||||
Config_Try_Num = 1 # 失败重试 |
@@ -0,0 +1,4 @@ | |||||
#foremail: '952943386@qq.com' | |||||
#password: "zzaikjtenujtbaif" | |||||
#toeamil: "leileili126@163.com,952943386@qq.com" | |||||
title: "测试报告" |
@@ -0,0 +1,7 @@ | |||||
projectname: '图灵' | |||||
interfaceVersion: '1.0.1' | |||||
tijiao_time: 2023-1-28 | |||||
tijiao_person: testTJ | |||||
ceshi_person: test1,test2 | |||||
ceshi_time: 2023-2-28 | |||||
shenhename: shenhe1 |
@@ -0,0 +1 @@ | |||||
2_0_0 |
@@ -0,0 +1 @@ | |||||
0_2_0 |
@@ -0,0 +1 @@ | |||||
0_2_0 |
@@ -0,0 +1 @@ | |||||
0_2_0 |
@@ -0,0 +1 @@ | |||||
0_2_0 |
@@ -0,0 +1 @@ | |||||
0_2_0 |
@@ -0,0 +1 @@ | |||||
0_2_0 |
@@ -0,0 +1 @@ | |||||
2_0_0 |
@@ -0,0 +1 @@ | |||||
2_0_0 |
@@ -0,0 +1 @@ | |||||
2_0_0 |
@@ -0,0 +1 @@ | |||||
2_0_0 |
@@ -0,0 +1 @@ | |||||
2_0_0 |
@@ -0,0 +1 @@ | |||||
2_0_0 |
@@ -0,0 +1 @@ | |||||
2_0_0 |
@@ -0,0 +1 @@ | |||||
2_0_0 |
@@ -0,0 +1 @@ | |||||
2_0_0 |
@@ -0,0 +1 @@ | |||||
2_0_0 |
@@ -0,0 +1 @@ | |||||
2_0_0 |
@@ -0,0 +1 @@ | |||||
2_0_0 |
@@ -0,0 +1 @@ | |||||
2_0_0 |
@@ -0,0 +1 @@ | |||||
2_0_0 |
@@ -0,0 +1 @@ | |||||
2_0_0 |
@@ -0,0 +1 @@ | |||||
2_0_0 |
@@ -0,0 +1 @@ | |||||
2_0_0 |
@@ -0,0 +1 @@ | |||||
2_0_0 |
@@ -0,0 +1,48 @@ | |||||
[2023-02-19 18:10:29.859856] INFO: interface_case_run: 当前模块 生成数据驱动所用数据 | |||||
[2023-02-19 18:10:29.860589] INFO: interface_case_run: 全部args参数参数信息 , () | |||||
[2023-02-19 18:10:29.860726] INFO: interface_case_run: 全部kwargs参数信息 , {} | |||||
[2023-02-19 18:10:29.860902] INFO: interface_case_run: 当前模块 解析测试用例文件 | |||||
[2023-02-19 18:10:29.861022] INFO: interface_case_run: 全部args参数参数信息 , ('/Users/lileilei/Desktop/testplan/jiekou-python3/test_case_data/case.xlsx',) | |||||
[2023-02-19 18:10:29.861131] INFO: interface_case_run: 全部kwargs参数信息 , {} | |||||
[2023-02-19 18:10:29.890171] INFO: interface_case_run: 测试用例开始执行 | |||||
[2023-02-19 18:10:29.890499] INFO: interface_case_run: {'key': 'aaaa', 'info': {'password': '1222'}} | |||||
[2023-02-19 18:10:29.890675] INFO: interface_case_run: 输入参数:url:/openapi/api,key:aaaa,参数:{'password':'1222'},请求方式:POST | |||||
[2023-02-19 18:10:29.890808] INFO: interface_case_run: 输入参数:url:/openapi/api,key:aaaa,参数:{'password':'1222'},请求方式:None | |||||
[2023-02-19 18:10:29.963764] INFO: interface_case_run: 返回结果:{'code': 0, 'result': {'code': 40007, 'text': '您的请求内容为空。'}} | |||||
[2023-02-19 18:10:29.964209] INFO: interface_case_run: 当前模块 断言测试结果 | |||||
[2023-02-19 18:10:29.964440] INFO: interface_case_run: 全部args参数参数信息 , () | |||||
[2023-02-19 18:10:29.964621] INFO: interface_case_run: 全部kwargs参数信息 , {'asserassert': 'code=40001'} | |||||
[2023-02-19 18:10:29.964853] INFO: interface_case_run: 测试用例执行完毕 | |||||
[2023-02-19 18:10:29.965177] INFO: interface_case_run: 测试用例开始执行 | |||||
[2023-02-19 18:10:29.965522] INFO: interface_case_run: {'key': 'dfeb1cc8125943d29764a2f2f5c33739', 'info': {'password': '1222'}} | |||||
[2023-02-19 18:10:29.965771] INFO: interface_case_run: 输入参数:url:/openapi/api,key:dfeb1cc8125943d29764a2f2f5c33739,参数:{'password':'1222'},请求方式:POST | |||||
[2023-02-19 18:10:29.965956] INFO: interface_case_run: 输入参数:url:/openapi/api,key:dfeb1cc8125943d29764a2f2f5c33739,参数:{'password':'1222'},请求方式:None | |||||
[2023-02-19 18:10:30.008491] INFO: interface_case_run: 返回结果:{'code': 0, 'result': {'code': 40007, 'text': '您的请求内容为空。'}} | |||||
[2023-02-19 18:10:30.008802] INFO: interface_case_run: 当前模块 断言测试结果 | |||||
[2023-02-19 18:10:30.009003] INFO: interface_case_run: 全部args参数参数信息 , () | |||||
[2023-02-19 18:10:30.009179] INFO: interface_case_run: 全部kwargs参数信息 , {'asserassert': 'code=40002'} | |||||
[2023-02-19 18:10:30.009398] INFO: interface_case_run: 测试用例执行完毕 | |||||
[2023-02-19 18:10:47.409761] INFO: interface_case_run: 当前模块 生成数据驱动所用数据 | |||||
[2023-02-19 18:10:47.410094] INFO: interface_case_run: 全部args参数参数信息 , () | |||||
[2023-02-19 18:10:47.410218] INFO: interface_case_run: 全部kwargs参数信息 , {} | |||||
[2023-02-19 18:10:47.410376] INFO: interface_case_run: 当前模块 解析测试用例文件 | |||||
[2023-02-19 18:10:47.410492] INFO: interface_case_run: 全部args参数参数信息 , ('/Users/lileilei/Desktop/testplan/jiekou-python3/test_case_data/case.xlsx',) | |||||
[2023-02-19 18:10:47.410600] INFO: interface_case_run: 全部kwargs参数信息 , {} | |||||
[2023-02-19 18:10:47.430403] INFO: interface_case_run: 测试用例开始执行 | |||||
[2023-02-19 18:10:47.430650] INFO: interface_case_run: {'key': 'aaaa', 'info': {'password': '1222'}} | |||||
[2023-02-19 18:10:47.430796] INFO: interface_case_run: 输入参数:url:/openapi/api,key:aaaa,参数:{'password':'1222'},请求方式:POST | |||||
[2023-02-19 18:10:47.430936] INFO: interface_case_run: 输入参数:url:/openapi/api,key:aaaa,参数:{'password':'1222'},请求方式:None | |||||
[2023-02-19 18:10:47.481670] INFO: interface_case_run: 返回结果:{'code': 0, 'result': {'code': 40007, 'text': '您的请求内容为空。'}} | |||||
[2023-02-19 18:10:47.482034] INFO: interface_case_run: 当前模块 断言测试结果 | |||||
[2023-02-19 18:10:47.482468] INFO: interface_case_run: 全部args参数参数信息 , () | |||||
[2023-02-19 18:10:47.482886] INFO: interface_case_run: 全部kwargs参数信息 , {'asserassert': 'code=40001'} | |||||
[2023-02-19 18:10:47.483244] INFO: interface_case_run: 测试用例执行完毕 | |||||
[2023-02-19 18:10:47.483554] INFO: interface_case_run: 测试用例开始执行 | |||||
[2023-02-19 18:10:47.483789] INFO: interface_case_run: {'key': 'dfeb1cc8125943d29764a2f2f5c33739', 'info': {'password': '1222'}} | |||||
[2023-02-19 18:10:47.483958] INFO: interface_case_run: 输入参数:url:/openapi/api,key:dfeb1cc8125943d29764a2f2f5c33739,参数:{'password':'1222'},请求方式:POST | |||||
[2023-02-19 18:10:47.484095] INFO: interface_case_run: 输入参数:url:/openapi/api,key:dfeb1cc8125943d29764a2f2f5c33739,参数:{'password':'1222'},请求方式:None | |||||
[2023-02-19 18:10:47.527872] INFO: interface_case_run: 返回结果:{'code': 0, 'result': {'code': 40007, 'text': '您的请求内容为空。'}} | |||||
[2023-02-19 18:10:47.528236] INFO: interface_case_run: 当前模块 断言测试结果 | |||||
[2023-02-19 18:10:47.528482] INFO: interface_case_run: 全部args参数参数信息 , () | |||||
[2023-02-19 18:10:47.528716] INFO: interface_case_run: 全部kwargs参数信息 , {'asserassert': 'code=40002'} | |||||
[2023-02-19 18:10:47.528998] INFO: interface_case_run: 测试用例执行完毕 |
@@ -0,0 +1,44 @@ | |||||
[2023-02-28 15:45:50.574267] INFO: interface_case_run: 当前模块 解析测试用例文件 | |||||
[2023-02-28 15:45:50.577260] INFO: interface_case_run: 全部args参数参数信息 , ('E:\\zq\\project\\liwanlei\\jiekou-python3\\test_case_data\\case.xlsx',) | |||||
[2023-02-28 15:45:50.578256] INFO: interface_case_run: 全部kwargs参数信息 , {} | |||||
[2023-02-28 15:45:50.617180] INFO: interface_case_run: 当前模块 解析测试用例文件 | |||||
[2023-02-28 15:45:50.619180] INFO: interface_case_run: 全部args参数参数信息 , ('E:\\zq\\project\\liwanlei\\jiekou-python3\\test_case_data\\case.xlsx',) | |||||
[2023-02-28 15:45:50.623139] INFO: interface_case_run: 全部kwargs参数信息 , {} | |||||
[2023-02-28 15:45:50.631140] INFO: interface_case_run: 当前模块 测试 | |||||
[2023-02-28 15:45:50.633135] INFO: interface_case_run: 全部args参数参数信息 , () | |||||
[2023-02-28 15:45:50.635128] INFO: interface_case_run: 全部kwargs参数信息 , {} | |||||
[2023-02-28 15:45:50.658045] INFO: interface_case_run: inputdata> 参数:{"password":"1222"}, url:/ ,返回:{'code': 0, 'result': {'code': '400', 'msg': 'success', 'data': '123123'}},预期:code=400 | |||||
[2023-02-28 15:45:50.660072] INFO: interface_case_run: 当前模块 断言测试结果 | |||||
[2023-02-28 15:45:50.662033] INFO: interface_case_run: 全部args参数参数信息 , () | |||||
[2023-02-28 15:45:50.664060] INFO: interface_case_run: 全部kwargs参数信息 , {'asserassert': 'code=400', 'returnjson': {'code': 0, 'result': {'code': '400', 'msg': 'success', 'data': '123123'}}} | |||||
[2023-02-28 15:45:50.666055] INFO: interface_case_run: 失败重试中 | |||||
[2023-02-28 15:45:50.676990] INFO: interface_case_run: inputdata> 参数:{"password":"1222"}, url:/ ,返回:{'code': 0, 'result': {'code': '400', 'msg': 'success', 'data': '123123'}},预期:code=400 | |||||
[2023-02-28 15:45:50.679987] INFO: interface_case_run: 当前模块 断言测试结果 | |||||
[2023-02-28 15:45:50.681981] INFO: interface_case_run: 全部args参数参数信息 , () | |||||
[2023-02-28 15:45:50.683976] INFO: interface_case_run: 全部kwargs参数信息 , {'asserassert': 'code=400', 'returnjson': {'code': 0, 'result': {'code': '400', 'msg': 'success', 'data': '123123'}}} | |||||
[2023-02-28 15:45:50.685968] INFO: interface_case_run: 失败重试中 | |||||
[2023-02-28 15:45:50.694946] INFO: interface_case_run: inputdata> 参数:{"password":"1222"}, url:/ ,返回:{'code': 0, 'result': {'code': '400', 'msg': 'success', 'data': '123123'}},预期:code=400 | |||||
[2023-02-28 15:45:50.696968] INFO: interface_case_run: 当前模块 断言测试结果 | |||||
[2023-02-28 15:45:50.698963] INFO: interface_case_run: 全部args参数参数信息 , () | |||||
[2023-02-28 15:45:50.700926] INFO: interface_case_run: 全部kwargs参数信息 , {'asserassert': 'code=400', 'returnjson': {'code': 0, 'result': {'code': '400', 'msg': 'success', 'data': '123123'}}} | |||||
[2023-02-28 15:45:50.702924] INFO: interface_case_run: 失败重试中次数用完,最后结果 | |||||
[2023-02-28 15:45:50.713897] INFO: interface_case_run: inputdata> 参数:{"password":"1222"}, url:/ ,返回:{'code': 0, 'result': {'code': '400', 'msg': 'success', 'data': '123123'}},预期:code=400 | |||||
[2023-02-28 15:45:50.716886] INFO: interface_case_run: 当前模块 断言测试结果 | |||||
[2023-02-28 15:45:50.718882] INFO: interface_case_run: 全部args参数参数信息 , () | |||||
[2023-02-28 15:45:50.721871] INFO: interface_case_run: 全部kwargs参数信息 , {'asserassert': 'code=400', 'returnjson': {'code': 0, 'result': {'code': '400', 'msg': 'success', 'data': '123123'}}} | |||||
[2023-02-28 15:45:50.723900] INFO: interface_case_run: 失败重试中 | |||||
[2023-02-28 15:45:50.731844] INFO: interface_case_run: inputdata> 参数:{"password":"1222"}, url:/ ,返回:{'code': 0, 'result': {'code': '400', 'msg': 'success', 'data': '123123'}},预期:code=400 | |||||
[2023-02-28 15:45:50.733862] INFO: interface_case_run: 当前模块 断言测试结果 | |||||
[2023-02-28 15:45:50.735865] INFO: interface_case_run: 全部args参数参数信息 , () | |||||
[2023-02-28 15:45:50.737826] INFO: interface_case_run: 全部kwargs参数信息 , {'asserassert': 'code=400', 'returnjson': {'code': 0, 'result': {'code': '400', 'msg': 'success', 'data': '123123'}}} | |||||
[2023-02-28 15:45:50.739853] INFO: interface_case_run: 失败重试中 | |||||
[2023-02-28 15:45:50.748798] INFO: interface_case_run: inputdata> 参数:{"password":"1222"}, url:/ ,返回:{'code': 0, 'result': {'code': '400', 'msg': 'success', 'data': '123123'}},预期:code=400 | |||||
[2023-02-28 15:45:50.750793] INFO: interface_case_run: 当前模块 断言测试结果 | |||||
[2023-02-28 15:45:50.752813] INFO: interface_case_run: 全部args参数参数信息 , () | |||||
[2023-02-28 15:45:50.754784] INFO: interface_case_run: 全部kwargs参数信息 , {'asserassert': 'code=400', 'returnjson': {'code': 0, 'result': {'code': '400', 'msg': 'success', 'data': '123123'}}} | |||||
[2023-02-28 15:45:50.756776] INFO: interface_case_run: 失败重试中次数用完,最后结果 | |||||
[2023-02-28 15:45:50.767752] INFO: interface_case_run: 失败重试中 | |||||
[2023-02-28 15:45:50.784705] INFO: interface_case_run: 失败重试中次数用完,最后结果 | |||||
[2023-02-28 15:45:50.787698] INFO: interface_case_run: 当前模块 保存测试结果 | |||||
[2023-02-28 15:45:50.789692] INFO: interface_case_run: 全部args参数参数信息 , (datetime.datetime(2023, 2, 28, 15, 45, 50, 617180), 3, 0, 2) | |||||
[2023-02-28 15:45:50.791719] INFO: interface_case_run: 全部kwargs参数信息 , {} |
@@ -0,0 +1,27 @@ | |||||
记录测试时间,测试总数,pass数量,失败数量 用‘=’拼接 | |||||
2017-10-16 20:54:56.323951=3=3=0 | |||||
2020-11-22 11:19:17.653613=2=0=2 | |||||
2020-11-22 11:19:55.276935=2=0=2 | |||||
2020-11-22 11:20:03.408231=2=0=2 | |||||
2020-11-22 11:20:22.107504=2=0=2 | |||||
2022-01-15 13:37:10.453363=2=0=2 | |||||
2022-01-15 13:37:53.945016=2=0=2 | |||||
2022-01-15 13:38:07.907832=2=0=2 | |||||
2022-01-15 13:38:16.052044=2=0=2 | |||||
2022-01-15 13:39:41.019636=2=0=2 | |||||
2022-01-15 13:39:51.378087=2=0=2 | |||||
2022-01-15 13:40:33.036679=2=0=2 | |||||
2022-04-22 17:22:26.808171=2=0=2 | |||||
2023-02-19 18:06:12.486185=2=0=2 | |||||
2023-02-19 18:06:17.821946=2=0=2 | |||||
2023-02-28 15:12:05.803270=3=0=0 | |||||
2023-02-28 15:16:10.287783=3=0=0 | |||||
2023-02-28 15:16:49.591922=3=0=0 | |||||
2023-02-28 15:17:30.399087=3=0=0 | |||||
2023-02-28 15:19:47.649372=3=0=0 | |||||
2023-02-28 15:22:16.319412=3=0=0 | |||||
2023-02-28 15:24:43.906041=3=0=0 | |||||
2023-02-28 15:33:12.201676=3=0=2 | |||||
2023-02-28 15:34:42.006208=3=0=1 | |||||
2023-02-28 15:43:50.790958=3=0=2 | |||||
2023-02-28 15:45:50.617180=3=0=2 |
@@ -0,0 +1,38 @@ | |||||
# encoding: utf-8 | |||||
""" | |||||
@author: lileilei | |||||
@file: run_excel_re.py | |||||
@time: 2017/6/9 12:45 | |||||
""" | |||||
from Public.pyreport_excel import create | |||||
import os, threading, datetime | |||||
from testCase.case import testinterface | |||||
from Public.get_excel import datacel | |||||
from Public.create_report import save_result | |||||
def start(): | |||||
starttime = datetime.datetime.now() | |||||
mtime = datetime.datetime.now().strftime("%Y%m%d") | |||||
basdir = os.path.abspath(os.path.dirname(__file__)) | |||||
path = os.path.join(os.path.join(os.getcwd(), 'test_case_data'), 'case.xlsx') | |||||
listid, listkey, listconeent, listurl, listmethod, listqiwang, listname = datacel(path) | |||||
listrelust, list_fail, list_pass, list_json, list_weizhi, listone = testinterface() | |||||
filepath = os.path.join(os.path.join(basdir, 'test_Report'), '%s-result.xls' % mtime) | |||||
if os.path.exists(filepath) is False: | |||||
os.system(r'touch %s' % filepath) | |||||
save_result(starttime, len(listrelust), ((list_pass)), list_fail) | |||||
create(filename=filepath, list_fail=list_fail, list_pass=list_pass, list_json=list_json, listurls=listurl, | |||||
listkeys=listkey, listconeents=listconeent, listfangshis=listmethod, | |||||
listqiwangs=listqiwang, | |||||
listids=listid, listrelust=listrelust, listnames=listname) | |||||
def teThread(): | |||||
m = threading.Thread(target=start, args=()) | |||||
m.run() | |||||
if __name__ == '__main__': | |||||
teThread() |
@@ -0,0 +1,36 @@ | |||||
# -*- coding: utf-8 -*- | |||||
# @Author : leizi | |||||
import os, datetime, time | |||||
from testCase.case import testinterface | |||||
from Public.py_Html import createHtml | |||||
from Public.get_excel import datacel | |||||
from Public.create_report import save_result | |||||
import threading | |||||
def stast(): | |||||
starttime = datetime.datetime.now() | |||||
day = time.strftime("%Y%m%d%H%M", time.localtime(time.time())) | |||||
path = os.path.join(os.path.join(os.getcwd(), 'test_case_data'), 'case.xlsx') | |||||
basdir = os.path.abspath(os.path.dirname(__file__)) | |||||
listid, listkey, listconeent, listurl, listfangshi, listqiwang, listname = datacel(path) | |||||
listrelust, list_fail, list_pass, list_json, list_exption, list_weizhi = testinterface() | |||||
filepath = os.path.join(os.path.join(basdir, 'test_Report'), '%s-result.html' % day) | |||||
if os.path.exists(filepath) is False: | |||||
os.system(r'touch %s' % filepath) | |||||
save_result(starttime, len(listrelust), ((list_pass)), list_fail) | |||||
endtime = datetime.datetime.now() | |||||
createHtml(titles='接口测试报告', filepath=filepath, starttime=starttime, | |||||
endtime=endtime, passge=list_pass, fail=list_fail, | |||||
id=listid, name=listname, key=listkey, coneent=listconeent, url=listurl, meth=listfangshi, | |||||
yuqi=listqiwang, json=list_json, relusts=listrelust, exceptions=list_exption, weizhi=list_weizhi) | |||||
# sendemali(filepath) | |||||
def tThread(): | |||||
m = threading.Thread(target=stast, args=()) | |||||
m.run() | |||||
if __name__ == '__main__': | |||||
tThread() |
@@ -0,0 +1,38 @@ | |||||
# -*- coding: utf-8 -*- | |||||
# @Author : leizi | |||||
import os, datetime, time | |||||
from testCase.case import testinterface | |||||
from public.py_Html import createHtml | |||||
from public.get_excel import datacel | |||||
from public.Dingtalk import send_ding | |||||
'''执行测试的主要文件''' | |||||
def start_interface_html_http(): | |||||
starttime = datetime.datetime.now() | |||||
day = time.strftime("%Y%m%d%H%M", time.localtime(time.time())) | |||||
basdir = os.path.abspath(os.path.dirname(__file__)) | |||||
path = os.path.join(os.path.join(os.getcwd(), 'test_case_data'), 'case.xlsx') | |||||
listid, listkey, listconeent, listurl, listfangshi, listqiwang, listname = datacel(path) | |||||
listrelust, list_fail, list_pass, list_json, list_exption, list_weizhi = testinterface() | |||||
filepath = os.path.join(os.path.join(basdir, 'test_Report'), '%s-result.html' % day) | |||||
if os.path.exists(filepath) is False: | |||||
os.system(r'touch %s' % filepath) | |||||
endtime = datetime.datetime.now() | |||||
createHtml(titles=u'http接口自动化测试报告', filepath=filepath, starttime=starttime, | |||||
endtime=endtime, passge=list_pass, fail=list_fail, | |||||
id=listid, name=listname, key=listkey, coneent=listconeent, url=listurl, meth=listfangshi, | |||||
yuqi=listqiwang, json=list_json, relusts=listrelust, weizhi=list_weizhi, exceptions=list_exption) | |||||
# contec = u'http接口自动化测试完成,测试通过:%s,测试失败:%s,异常:%s,未知错误:%s,详情见:%s' % ( | |||||
# list_pass, list_fail, list_exption, list_weizhi, filepath) | |||||
# send_ding(content=contec) | |||||
if __name__ == '__main__': | |||||
start_interface_html_http() |
@@ -0,0 +1,27 @@ | |||||
# -*- coding: utf-8 -*- | |||||
# @Author : leizi | |||||
from testCase.ddt_case import MyTest | |||||
import unittest, time, os | |||||
from public import BSTestRunner | |||||
BASH_DIR = "history" | |||||
if __name__ == '__main__': | |||||
basedir = os.path.abspath(os.path.dirname(__file__)) | |||||
file_dir = os.path.join(basedir, 'test_Report') | |||||
file_reslut = os.path.join(file_dir, 'caseresult.yaml') | |||||
try: | |||||
os.remove(file_reslut) | |||||
except: | |||||
pass | |||||
suite = unittest.TestSuite() | |||||
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(MyTest)) | |||||
now = time.strftime('%Y-%m%d', time.localtime(time.time())) | |||||
file = os.path.join(file_dir, (now + '.html')) | |||||
re_open = open(file, 'wb') | |||||
besautiful = BSTestRunner.BSTestRunner(title="报告", | |||||
description="测试报告", | |||||
stream=re_open, | |||||
trynum=3, | |||||
filepath=BASH_DIR, | |||||
is_show=True) | |||||
besautiful.run(suite) |
@@ -0,0 +1,86 @@ | |||||
# -*- coding: utf-8 -*- | |||||
# @Time : 2017/6/4 20:15 | |||||
# @Author : lileilei | |||||
# @File : case.py | |||||
from Interface.testFengzhuang import TestApi | |||||
from Public.get_excel import datacel | |||||
from Public.log import LOG, logger | |||||
import os | |||||
from config.config import Config_Try_Num, TestPlanUrl | |||||
path = os.path.join(os.path.join(os.getcwd(), 'test_case_data'), 'case.xlsx') | |||||
listid, listkey, listconeent, listurl, listfangshi, listqiwang, listname = datacel(path) | |||||
from Public.panduan import assert_in | |||||
@logger('测试') | |||||
def testinterface(): | |||||
list_pass = 0 | |||||
list_fail = 0 | |||||
list_json = [] | |||||
listrelust = [] | |||||
list_weizhi = 0 | |||||
list_exption = 0 | |||||
error_num = 0 | |||||
for i in range(len(listurl)): | |||||
while error_num <= Config_Try_Num + 1: | |||||
parem = {'key': listkey[i]} | |||||
parem.update({'info': eval(listconeent[i])}) | |||||
#parem=eval(data_test[listconeent[i]) | |||||
api = TestApi(url=TestPlanUrl + listurl[i], parame=parem, method=listfangshi[i]) | |||||
apijson = api.getJson() | |||||
if apijson['code'] == 0: | |||||
LOG.info('inputdata> 参数:%s, url:%s ,返回:%s,预期:%s' % (listconeent[i], listurl[i], apijson, listqiwang[i])) | |||||
assert_re = assert_in(asserassert=listqiwang[i], returnjson=apijson) | |||||
if assert_re['code'] == 0: | |||||
list_json.append(apijson['result']) | |||||
listrelust.append('pass') | |||||
list_pass += 1 | |||||
error_num = 0 | |||||
continue | |||||
elif assert_re['code'] == 1: | |||||
if error_num <= Config_Try_Num: | |||||
error_num += 1 | |||||
LOG.info('失败重试中') | |||||
else: | |||||
LOG.info('失败重试中次数用完,最后结果') | |||||
error_num = 0 | |||||
list_fail += 1 | |||||
listrelust.append('fail') | |||||
list_json.append(apijson['result']) | |||||
break | |||||
elif assert_re['code'] == 2: | |||||
if error_num < Config_Try_Num: | |||||
error_num += 1 | |||||
LOG.info('失败重试中') | |||||
else: | |||||
LOG.info('失败重试中次数用完,最后结果') | |||||
error_num = 0 | |||||
list_exption += 1 | |||||
listrelust.append('exception') | |||||
list_json.append(assert_re['result']) | |||||
break | |||||
else: | |||||
if error_num < Config_Try_Num: | |||||
error_num += 1 | |||||
LOG.info('失败重试中') | |||||
else: | |||||
LOG.info('失败重试中次数用完,最后结果') | |||||
error_num = 0 | |||||
list_weizhi += 1 | |||||
listrelust.append('未知错误') | |||||
list_json.append('未知错误') | |||||
break | |||||
else: | |||||
if error_num < Config_Try_Num: | |||||
error_num += 1 | |||||
LOG.info('失败重试中') | |||||
else: | |||||
LOG.info('失败重试中次数用完,最后结果') | |||||
error_num = 0 | |||||
list_exption += 1 | |||||
listrelust.append('exception') | |||||
list_json.append(apijson['result']) | |||||
break | |||||
return listrelust, list_fail, list_pass, list_json, list_exption, list_weizhi |
@@ -0,0 +1,79 @@ | |||||
import ddt, unittest, os, yaml | |||||
from Interface.testFengzhuang import TestApi | |||||
from public.get_excel import makedata | |||||
from public.log import LOG | |||||
from public.panduan import assertre | |||||
from config.config import TestPlanUrl | |||||
file_dir = os.path.join(os.getcwd(), 'test_Report') | |||||
file_reslut = os.path.join(file_dir, 'caseresult.yaml') | |||||
data_test = makedata() | |||||
def write(data): | |||||
with open(file_reslut, 'a', encoding='utf-8') as f: | |||||
yaml.dump(data, f, allow_unicode=True) | |||||
def read(data): | |||||
f = open(file_reslut, 'r', encoding='utf-8') | |||||
d = yaml.load(f, Loader=yaml.FullLoader) | |||||
return d[data] | |||||
@ddt.ddt | |||||
class MyTest(unittest.TestCase): | |||||
def setUp(self): | |||||
LOG.info('测试用例开始执行') | |||||
def tearDown(self): | |||||
LOG.info('测试用例执行完毕') | |||||
@ddt.data(*data_test) | |||||
def test_api(self, data_test): | |||||
''' | |||||
1.处理参数 | |||||
2.判断参数是否有依赖 | |||||
3.依赖用例参数从本地获取 | |||||
4.获取失败,用例失败 | |||||
5.拼接后请求 | |||||
''' | |||||
parem = {'key': data_test['key']} | |||||
try: | |||||
parem_dict = eval(data_test['coneent']) | |||||
for key, value in parem_dict.items(): | |||||
if str(value).startswith("&"): | |||||
try: | |||||
reply_key_id = str(value).split("&")[-1].split("=") | |||||
reply_keyid = reply_key_id[0] | |||||
reply_key_key = reply_key_id[1] | |||||
reslut = read(reply_keyid) | |||||
if reslut is None: | |||||
self.assertTrue(False, '依赖用例获取失败') | |||||
get_value = reslut[reply_key_key] | |||||
if get_value is None: | |||||
self.assertTrue(False, '依赖参数获取失败,不存在') | |||||
parem_dict[key] = get_value | |||||
except Exception as e: | |||||
LOG.info("用例依赖执行失败:" + str(e)) | |||||
self.assertTrue(False, '用例依赖执行失败') | |||||
parem.update({'info': parem_dict}) | |||||
except: | |||||
self.assertTrue(False, msg="参数格式不对") | |||||
LOG.info(parem) | |||||
api = TestApi(url=TestPlanUrl + data_test['url'], | |||||
parame=parem, | |||||
method=data_test['method']) | |||||
LOG.info('输入参数:url:%s,key:%s,参数:%s,请求方式:%s' % (data_test['url'], data_test['key'], data_test['assertconnect'], | |||||
LOG.info('输入参数:url:%s,key:%s,参数:%s,请求方式:%s' % ( | |||||
data_test['url'], data_test['key'], data_test['assertconnect'], | |||||
data_test['method'])))) | |||||
apijson = api.getJson() | |||||
reslut = {} | |||||
reslut[data_test['id']] = apijson | |||||
write(reslut) | |||||
LOG.info('返回结果:%s' % apijson) | |||||
assertall = assertre(asserassert=data_test['assertconnect']) | |||||
self.assertNotEqual(dict(assertall), dict(apijson), msg='预期和返回不一致') |
@@ -0,0 +1,52 @@ | |||||
""" | |||||
@author: lileilei | |||||
@file: dubbocase.py | |||||
@time: 2018/3/29 12:47 | |||||
""" | |||||
from Interface.dubbo_feng import DubboInterface | |||||
from public.log import LOG, logger | |||||
from public.panduan import assert_in | |||||
from public.get_excel import datacel | |||||
import os | |||||
path = os.path.join(os.path.join(os.getcwd(), 'test_case_data'), 'dubbocase.xlsx') | |||||
listid, listurl, listinterface, listmeth, listfobject, listparam, listassert = datacel(path) | |||||
@logger('dubbo接口测试') | |||||
def testdubbointerface(): | |||||
list_pass = 0 | |||||
list_fail = 0 | |||||
list_json = [] | |||||
listrelust = [] | |||||
list_weizhi = 0 | |||||
list_exption = 0 | |||||
for i in range(len(listid)): | |||||
dubboapi = DubboInterface(url=listurl, interface=listinterface[i], method=listmeth[i], param=listfobject[i], | |||||
**(eval(listparam[i]))) | |||||
dubboapireslu = dubboapi.getresult() | |||||
if dubboapireslu['code'] == 0: | |||||
LOG.info('inputdata> 参数:%s, url:%s ,返回:%s,预期:%s' % (listparam[i], listurl[i], dubboapireslu, listassert[i])) | |||||
assert_re = assert_in(asserassert=listassert[i], returnjson=dubboapireslu) | |||||
if assert_re['code'] == 0: | |||||
list_json.append(dubboapireslu['result']) | |||||
listrelust.append('pass') | |||||
list_pass += 1 | |||||
elif assert_re['code'] == 1: | |||||
list_fail += 1 | |||||
listrelust.append('fail') | |||||
list_json.append(dubboapireslu['result']) | |||||
elif assert_re['code'] == 2: | |||||
list_exption += 1 | |||||
listrelust.append('exception') | |||||
list_json.append(assert_re['result']) | |||||
else: | |||||
list_weizhi += 1 | |||||
listrelust.append('未知错误') | |||||
list_json.append('未知错误') | |||||
else: | |||||
list_exption += 1 | |||||
listrelust.append('exception') | |||||
list_json.append(dubboapireslu['result']) | |||||
continue | |||||
return listrelust, list_fail, list_pass, list_json, list_exption, list_weizhi |
@@ -0,0 +1,64 @@ | |||||
''' | |||||
@Description | |||||
@auther leizi | |||||
''' | |||||
from Interface.testFengzhuang import TestApi | |||||
from public.log import LOG | |||||
from public.panduan import assertre | |||||
from config.config import TestPlanUrl | |||||
import pytest | |||||
import os | |||||
import yaml | |||||
from public.get_excel import makedata | |||||
file_dir = os.path.join(os.getcwd(), 'test_Report') | |||||
file_reslut = os.path.join(file_dir, 'caseresult.yaml') | |||||
def write(data): | |||||
with open(file_reslut, 'a', encoding='utf-8') as f: | |||||
yaml.dump(data, f, allow_unicode=True) | |||||
def read(data): | |||||
f = open(file_reslut, 'r', encoding='utf-8') | |||||
d = yaml.load(f, Loader=yaml.FullLoader) | |||||
return d[data] | |||||
data_test = makedata() | |||||
@pytest.mark.parametrize(data_test) | |||||
class TestParametrize(object): | |||||
def test_parame(self): | |||||
parem = {'key': data_test['key']} | |||||
try: | |||||
parem_dict = eval(data_test['coneent']) | |||||
for key, value in parem_dict.items(): | |||||
if str(value).startswith("&"): | |||||
try: | |||||
reply_key_id = str(value).split("&")[-1].split("=") | |||||
reply_keyid = reply_key_id[0] | |||||
reply_key_key = reply_key_id[1] | |||||
reslut = read(reply_keyid) | |||||
if reslut is None: | |||||
assert False | |||||
get_value = reslut[reply_key_key] | |||||
if get_value is None: | |||||
assert False | |||||
parem_dict[key] = get_value | |||||
except Exception as e: | |||||
LOG.info("用例依赖执行失败:" + str(e)) | |||||
assert False | |||||
parem.update({'info': parem_dict}) | |||||
except: | |||||
assert False | |||||
api = TestApi(url=TestPlanUrl + data_test['url'], | |||||
parame=parem, | |||||
method=data_test['fangshi']) | |||||
LOG.info('输入参数:url:%s,key:%s,参数:%s,请求方式:%s' % (data_test['url'], data_test['key'], data_test['coneent'], | |||||
LOG.info('输入参数:url:%s,key:%s,参数:%s,请求方式:%s' % ( | |||||
data_test['url'], data_test['key'], data_test['coneent'], | |||||
data_test['fangshi'])))) | |||||
apijson = api.getJson() | |||||
reslut = {} | |||||
reslut[data_test['id']] = apijson | |||||
LOG.info('返回结果:%s' % apijson) | |||||
assertall = assertre(asserassert=data_test['qiwang']) | |||||
assert dict(assertall) == dict(apijson) |
@@ -0,0 +1,264 @@ | |||||
<!DOCTYPE html> | |||||
<html lang="zh-cn"> | |||||
<head> | |||||
<meta charset="utf-8"> | |||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |||||
<meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | |||||
<title>报告</title> | |||||
<meta name="generator" content="BSTestRunner 0.8.4"/> | |||||
<link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" "> | |||||
<script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script> | |||||
<style type="text/css" media="screen"> | |||||
/* -- css div popup ------------------------------------------------------------------------ */ | |||||
.popup_window { | |||||
display: none; | |||||
position: relative; | |||||
left: 0px; | |||||
top: 0px; | |||||
/*border: solid #627173 1px; */ | |||||
padding: 10px; | |||||
background-color: #99CCFF; | |||||
font-family: "Lucida Console", "Courier New", Courier, monospace; | |||||
text-align: left; | |||||
font-size: 10pt; | |||||
width: 1200px; | |||||
} | |||||
/* -- report ------------------------------------------------------------------------ */ | |||||
#show_detail_line .label { | |||||
font-size: 85%; | |||||
cursor: pointer; | |||||
} | |||||
#show_detail_line { | |||||
margin: 2em auto 1em auto; | |||||
} | |||||
#total_row { font-weight: bold; } | |||||
.hiddenRow { display: none; } | |||||
.testcase { margin-left: 2em; } | |||||
</style> | |||||
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> | |||||
<!-- WARNING: Respond.js doesn't work if you view the page via file:// --> | |||||
<!--[if lt IE 9]> | |||||
<script src="http://cdn.bootcss.com/html5shiv/3.7.2/html5shiv.min.js"></script> | |||||
<script src="http://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script> | |||||
<![endif]--> | |||||
</head> | |||||
<body> | |||||
<div class="container"> | |||||
<div class='heading'> | |||||
<div style='width: 50%;float:left;margin-top:inherit'> | |||||
<h1>报告</h1> | |||||
<p><strong>开始时间:</strong> 2023-02-19 18:10:47</p> | |||||
<p><strong>持续时间:</strong> 0:00:00.099009</p> | |||||
<p><strong>状态:</strong> <span class="text text-success">通过 <strong>2</strong></span></p> | |||||
<p class='description'>测试报告</p> | |||||
</div> | |||||
<div id='container2' style='width:50%;float:left;margin-top:20px;height:200px;'> | |||||
</div> | |||||
</div > | |||||
<div id='containerchart' style='height: 300px;margin-top: 20%;'></div> | |||||
<p id='show_detail_line'> | |||||
<span class="label label-primary" onclick="showCase(0)">公用</span> | |||||
<span class="label label-danger" onclick="showCase(1)">失败</span> | |||||
<span class="label label-default" onclick="showCase(2)">所有</span> | |||||
</p> | |||||
<table id='result_table' class="table"> | |||||
<thead> | |||||
<tr id='header_row'> | |||||
<th>测试组/测试用例</td> | |||||
<th>数量</td> | |||||
<th>通过</td> | |||||
<th>失败</td> | |||||
<th>错误</td> | |||||
<th>查看</td> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
<tr class='text text-success'> | |||||
<td>testCase.ddt_case.MyTest</td> | |||||
<td>2</td> | |||||
<td>2</td> | |||||
<td>0</td> | |||||
<td>0</td> | |||||
<td><a class="btn btn-xs btn-primary"href="javascript:showClassDetail('c1',2)">详情</a></td> | |||||
</tr> | |||||
<tr id='pt1.1' class='hiddenRow'> | |||||
<td class='text text-success'><div class='testcase'>test_api_1: 1.处理参数</div></td> | |||||
<td colspan='5' align='center'>通过</td> | |||||
</tr> | |||||
<tr id='pt1.2' class='hiddenRow'> | |||||
<td class='text text-success'><div class='testcase'>test_api_2: 1.处理参数</div></td> | |||||
<td colspan='5' align='center'>通过</td> | |||||
</tr> | |||||
</tbody> | |||||
<tfoot> | |||||
<tr id='total_row'> | |||||
<td>总计</td> | |||||
<td>2</td> | |||||
<td class="text text-success">2</td> | |||||
<td class="text text-danger">0</td> | |||||
<td class="text text-warning">0</td> | |||||
<td> </td> | |||||
</tr> | |||||
</tfoot> | |||||
</table> | |||||
<div id='ending'> </div> | |||||
</div> | |||||
<script language='javascript' type='text/javascript'> | |||||
var dom = document.getElementById('containerchart'); | |||||
var myChart = echarts.init(dom); | |||||
var domone = document.getElementById('container2'); | |||||
var myChartone = echarts.init(domone); | |||||
var optionsone; | |||||
optionsone = { | |||||
title: { | |||||
text: '历史记录' | |||||
}, | |||||
tooltip: { | |||||
trigger: 'axis' | |||||
}, | |||||
legend: { | |||||
data: ['成功', '失败','错误'] | |||||
}, | |||||
grid: { | |||||
left: '3%', | |||||
right: '4%', | |||||
bottom: '3%', | |||||
containLabel: true | |||||
}, | |||||
toolbox: { | |||||
feature: { | |||||
saveAsImage: {} | |||||
} | |||||
}, | |||||
xAxis: { | |||||
type: 'category', | |||||
boundaryGap: false, | |||||
data: ['2022_04_22_21_06_05', '2022_01_16_09_43_50', '2023_02_19_18_10_30', '2022_04_22_21_22_01', '2022_04_22_21_29_08', '2022_01_16_09_43_56', '2022_01_16_09_41_37', '2022_04_22_17_22_51', '2022_01_16_09_39_12', '2022_01_15_14_26_21', '2023_02_19_18_10_47', '2022_01_16_09_41_00', '2022_01_16_09_39_32', '2022_01_16_09_44_26', '2022_04_22_21_32_40', '2022_01_16_09_46_33', '2022_01_16_09_43_15', '2023_02_19_18_06_29', '2023_02_19_18_08_39', '2022_01_16_09_44_35', '2022_01_16_09_45_12', '2022_01_16_09_39_51', '2022_01_16_09_42_37', '2022_01_16_09_38_16', '2022_01_16_09_36_13'] | |||||
}, | |||||
yAxis: { | |||||
type: 'value' | |||||
}, | |||||
series: [ | |||||
{ | |||||
name: '成功', | |||||
type: 'line', | |||||
stack: '总量', | |||||
data: ['2', '2', '2', '2', '2', '2', '2', '2', '0', '2', '2', '0', '0', '2', '2', '2', '2', '2', '2', '2', '2', '0', '2', '0', '0'] | |||||
}, | |||||
{ | |||||
name: '失败', | |||||
type: 'line', | |||||
stack: '总量', | |||||
data: ['0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'] | |||||
}, | |||||
{ | |||||
name: '错误', | |||||
type: 'line', | |||||
stack: '总量', | |||||
data: ['0', '0', '0', '0', '0', '0', '0', '0', '2', '0', '0', '2', '2', '0', '0', '0', '0', '0', '0', '0', '0', '2', '0', '2', '2'] | |||||
} | |||||
] | |||||
}; | |||||
if (optionsone && typeof optionsone === 'object') { | |||||
myChartone.setOption(optionsone); | |||||
} | |||||
output_list = Array(); | |||||
/* level - 0:Summary; 1:Failed; 2:All */ | |||||
function showCase(level) { | |||||
trs = document.getElementsByTagName('tr'); | |||||
for (var i = 0; i < trs.length; i++) { | |||||
tr = trs[i]; | |||||
id = tr.id; | |||||
if (id.substr(0,2) == 'ft') { | |||||
if (level < 1) { | |||||
tr.className = 'hiddenRow'; | |||||
} | |||||
else { | |||||
tr.className = ''; | |||||
} | |||||
} | |||||
if (id.substr(0,2) == 'pt') { | |||||
if (level > 1) { | |||||
tr.className = ''; | |||||
} | |||||
else { | |||||
tr.className = 'hiddenRow'; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
function showClassDetail(cid, count) { | |||||
var id_list = Array(count); | |||||
var toHide = 1; | |||||
for (var i = 0; i < count; i++) { | |||||
tid0 = 't' + cid.substr(1) + '.' + (i+1); | |||||
tid = 'f' + tid0; | |||||
tr = document.getElementById(tid); | |||||
if (!tr) { | |||||
tid = 'p' + tid0; | |||||
tr = document.getElementById(tid); | |||||
} | |||||
id_list[i] = tid; | |||||
if (tr.className) { | |||||
toHide = 0; | |||||
} | |||||
} | |||||
for (var i = 0; i < count; i++) { | |||||
tid = id_list[i]; | |||||
if (toHide) { | |||||
document.getElementById('div_'+tid).style.display = 'none' | |||||
document.getElementById(tid).className = 'hiddenRow'; | |||||
} | |||||
else { | |||||
document.getElementById(tid).className = ''; | |||||
} | |||||
} | |||||
} | |||||
function showTestDetail(div_id){ | |||||
var details_div = document.getElementById(div_id) | |||||
var displayState = details_div.style.display | |||||
if (displayState != 'block' ) { | |||||
displayState = 'block' | |||||
details_div.style.display = 'block' | |||||
} | |||||
else { | |||||
details_div.style.display = 'none' | |||||
} | |||||
} | |||||
function html_escape(s) { | |||||
s = s.replace(/&/g,'&'); | |||||
s = s.replace(/</g,'<'); | |||||
s = s.replace(/>/g,'>'); | |||||
return s; | |||||
} | |||||
</script> | |||||
</body> | |||||
</html> | |||||
@@ -0,0 +1,117 @@ | |||||
<!DOCTYPE html> | |||||
<html> | |||||
<head> | |||||
<title>http接口自动化测试报告</title> | |||||
<meta charset="UTF-8"> | |||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |||||
<!-- 引入 Bootstrap --> | |||||
<link href="https://cdn.bootcss.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"> | |||||
<!-- HTML5 Shim 和 Respond.js 用于让 IE8 支持 HTML5元素和媒体查询 --> | |||||
<!-- 注意: 如果通过 file:// 引入 Respond.js 文件,则该文件无法起效果 --> | |||||
<!--[if lt IE 9]> | |||||
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script> | |||||
<script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script> | |||||
<![endif]--> | |||||
<style type="text/css"> | |||||
.hidden-detail,.hidden-tr{ | |||||
display:none; | |||||
} | |||||
</style> | |||||
</head> | |||||
<body> | |||||
<div class='col-md-4 col-md-offset-4' style='margin-left:3%;'> | |||||
<h1>接口测试的结果</h1> | |||||
<table class="table table-hover table-condensed"> | |||||
<tbody> | |||||
<tr> | |||||
<td><strong>开始时间:</strong> 2023-02-19 18:06:22.576639</td> | |||||
</tr> | |||||
<td><strong>结束时间:</strong> 2023-02-19 18:06:23.111143</td></tr> | |||||
<td><strong>耗时:</strong> 0:00:00.534504</td></tr> | |||||
<td><strong>结果:</strong> | |||||
<span >Pass: <strong >0</strong> | |||||
Fail: <strong >2</strong> | |||||
exception: <strong >0</strong> | |||||
weizhicuowu : <strong >0</strong></span></td> | |||||
</tr> | |||||
</tbody></table> | |||||
</div> <div class="row " style="margin:60px"> | |||||
<div style=' margin-top: 18%;' > | |||||
<div class="btn-group" role="group" aria-label="..."> | |||||
<button type="button" id="check-all" class="btn btn-primary">所有用例</button> | |||||
<button type="button" id="check-success" class="btn btn-success">成功用例</button> | |||||
<button type="button" id="check-danger" class="btn btn-danger">失败用例</button> | |||||
<button type="button" id="check-warning" class="btn btn-warning">错误用例</button> | |||||
<button type="button" id="check-except" class="btn btn-defult">异常用例</button> | |||||
</div> | |||||
<div class="btn-group" role="group" aria-label="..."> | |||||
</div> | |||||
<table class="table table-hover table-condensed table-bordered" style="word-wrap:break-word; word-break:break-all; margin-top: 7px;"> | |||||
<tr > | |||||
<td ><strong>用例ID </strong></td> | |||||
<td><strong>用例名字</strong></td> | |||||
<td><strong>key</strong></td> | |||||
<td><strong>请求内容</strong></td> | |||||
<td><strong>url</strong></td> | |||||
<td><strong>请求方式</strong></td> | |||||
<td><strong>预期</strong></td> | |||||
<td><strong>实际返回</strong></td> | |||||
<td><strong>结果</strong></td> | |||||
</tr> | |||||
<tr class="case-tr warning"> | |||||
<td>1.0</td> | |||||
<td>图灵api接口</td> | |||||
<td>aaaa</td> | |||||
<td>{'password':'1222'}</td> | |||||
<td>/openapi/api</td> | |||||
<td>POST</td> | |||||
<td>code=40001</td> | |||||
<td>{'code': 40007, 'text': '您的请求内容为空。'}</td> | |||||
<td bgcolor="fail">fail</td> | |||||
</tr> | |||||
<tr class="case-tr warning"> | |||||
<td>2.0</td> | |||||
<td>图灵api接口</td> | |||||
<td>dfeb1cc8125943d29764a2f2f5c33739</td> | |||||
<td>{'password':'1222'}</td> | |||||
<td>/openapi/api</td> | |||||
<td>POST</td> | |||||
<td>code=40002</td> | |||||
<td>{'code': 40007, 'text': '您的请求内容为空。'}</td> | |||||
<td bgcolor="fail">fail</td> | |||||
</tr> | |||||
</div></div></table><script src="https://code.jquery.com/jquery.js"></script> | |||||
<script src="https://cdn.bootcss.com/bootstrap/3.3.6/js/bootstrap.min.js"></script> | |||||
<script type="text/javascript"> | |||||
$("#check-danger").click(function(e){ | |||||
$(".case-tr").removeClass("hidden-tr"); | |||||
$(".success").addClass("hidden-tr"); | |||||
$(".warning").addClass("hidden-tr"); | |||||
$(".error").addClass("hidden-tr"); | |||||
}); | |||||
$("#check-warning").click(function(e){ | |||||
$(".case-tr").removeClass("hidden-tr"); | |||||
$(".success").addClass("hidden-tr"); | |||||
$(".danger").addClass("hidden-tr"); | |||||
$(".error").addClass("hidden-tr"); | |||||
}); | |||||
$("#check-success").click(function(e){ | |||||
$(".case-tr").removeClass("hidden-tr"); | |||||
$(".warning").addClass("hidden-tr"); | |||||
$(".danger").addClass("hidden-tr"); | |||||
$(".error").addClass("hidden-tr"); | |||||
}); | |||||
$("#check-except").click(function(e){ | |||||
$(".case-tr").removeClass("hidden-tr"); | |||||
$(".warning").addClass("hidden-tr"); | |||||
$(".danger").addClass("hidden-tr"); | |||||
$(".success").addClass("hidden-tr"); | |||||
}); | |||||
$("#check-all").click(function(e){ | |||||
$(".case-tr").removeClass("hidden-tr"); | |||||
}); | |||||
</script> | |||||
</body></html> |
@@ -0,0 +1,10 @@ | |||||
1.0: | |||||
code: 0 | |||||
result: | |||||
code: 40007 | |||||
text: 您的请求内容为空。 | |||||
2.0: | |||||
code: 0 | |||||
result: | |||||
code: 40007 | |||||
text: 您的请求内容为空。 |
@@ -0,0 +1,38 @@ | |||||
-----BEGIN OPENSSH PRIVATE KEY----- | |||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn | |||||
NhAAAAAwEAAQAAAYEAsbthKV/+8Yu5V2R2quG1Xy6kvkZ6PcRzSoarxXh6zxoxVlyEZNXP | |||||
09a9jdf1fS2l9KRaimxjr94mH4r8JGL6afyegKwPJCyjeXrjsFJMpyn4YAOs5qTMO34WbO | |||||
88BSc53omDWuPvQaQFPpMK5rAs4E5c2o91tkzRks52+B2Y1wkIYFZYDBHugVgiY7B6PHQi | |||||
RGoMKbuM5gvxU1zGvGumvUoUo0lXs8oLFtHpp2jZypJdlgRRGfVzfw+bD3LrfH7J6+Lse5 | |||||
bZEsNB+xxRO2qQMb/2fOiP0fRXZRWX+PTkvpqNxxub7Fil8XjUY0M2W0/DG8wPAMfPxt8B | |||||
ZY9ciLL+vsNobPDzsHgOxbD0+nc4XVou+RdMaAmxs8a95BGVsi0236laA/pHcMcyarCGja | |||||
wJrZK+yBe+79NU45umMB9uXn7CY4j4oUX5izTHu+l9tiqpRYsmegcQMSBgDvPd/Q58kgIb | |||||
WybvdOUM9OMfYeWfUXyvT84BOVVNXGGqdKrIWycDAAAFkLHO9WWxzvVlAAAAB3NzaC1yc2 | |||||
EAAAGBALG7YSlf/vGLuVdkdqrhtV8upL5Gej3Ec0qGq8V4es8aMVZchGTVz9PWvY3X9X0t | |||||
pfSkWopsY6/eJh+K/CRi+mn8noCsDyQso3l647BSTKcp+GADrOakzDt+FmzvPAUnOd6Jg1 | |||||
rj70GkBT6TCuawLOBOXNqPdbZM0ZLOdvgdmNcJCGBWWAwR7oFYImOwejx0IkRqDCm7jOYL | |||||
8VNcxrxrpr1KFKNJV7PKCxbR6ado2cqSXZYEURn1c38Pmw9y63x+yevi7HuW2RLDQfscUT | |||||
tqkDG/9nzoj9H0V2UVl/j05L6ajccbm+xYpfF41GNDNltPwxvMDwDHz8bfAWWPXIiy/r7D | |||||
aGzw87B4DsWw9Pp3OF1aLvkXTGgJsbPGveQRlbItNt+pWgP6R3DHMmqwho2sCa2SvsgXvu | |||||
/TVOObpjAfbl5+wmOI+KFF+Ys0x7vpfbYqqUWLJnoHEDEgYA7z3f0OfJICG1sm73TlDPTj | |||||
H2Hln1F8r0/OATlVTVxhqnSqyFsnAwAAAAMBAAEAAAGAQoE2IzBLioDZEo2CJgEdSAeBF7 | |||||
3xgelfprRr1BF4CsTnT0SBOeYTxVXmSgxUTMnm/nr9ciyKxMUgiM8N+GOdBknD2awIYmXd | |||||
qdhFGLZC/o4i5XKaoRdrYJuWsp52XAtIiS/1me4OmgZQ/BAzlQy5ThmkfxgNWPC3vvJI7C | |||||
DPDy/PFZVZjvKqx3V+MMVZiAOAyw7PjFIkr/QqEiJ2Lw0tMElnHY6VJa5lpd1YTA9c54ML | |||||
R9ZHrqn81L+3Kvm6ijQ6o+8k/qZ9vtDBCm062iMnL7bYlZPHAAwcmTA1j781yZVzCiw8BT | |||||
6/qSc4nxq7UROks/pd8MrG+a8W/N5L+/2sP5ovWMqRMZDGG+qTwV7DHk001JKhwDzYOtHh | |||||
rqmXyJpEUCtSpTNW8fuhfsbJisVyD5+VYECrPclCetPMwP5cXf5Lf/7cV4nOFo3jJkoDF7 | |||||
rwDjgNC/VF/n1qAz4vw5Lp8ijj7z+uP4SPOpDYxDl8lTcXntDvf4HRarRYX59WUSChAAAA | |||||
wQDWvVI9iAwme/0r/iJWoM79wlcNc+YK1i7TNlI41v720fAFKu/9AQat4dmosoPn10d+EE | |||||
Vd83A4YTh3xsMGErxBxTl8twNFHcZsB1o9uO8rkTQOoRyJrDu1X8YKxav+p0IEbxeFsZyq | |||||
JlPESgY19ZBMsrPyQTChowmYoGIljtspJzHcc6qrTm56vxgXnWbBHKQ5VXdlxFABAsH3d5 | |||||
51dvQquQR98q348B5TD7IaEEkQRmgqYQFwwa0ApAVXgFBBP00AAADBAOyQ02MNWLdxyI66 | |||||
V8F6VvTppo+DdT9N7GCZBxPQs/vZ8KcaXRGDvbW8/fLB83UH6pA3MZ8bQ5XJ7vNBsyOSgw | |||||
xevFEpwz5KCxwj9JYP534tjtn89QH7tgsAjnETnrDePisUOpKVDdLm8yIhMp1/LJ5/kJj9 | |||||
J3MaxEQYSlhiBmEeUl9f/JMYx9c20zp4jRAO3d2o9NOzfswgvOCqhfQ7y1xYUcNXeKjP3i | |||||
k9nQLgZVWXBsq6cIPYq/P7l0AuxG/4swAAAMEAwFU7A89t6FCmr45WjwPYinkWVHe1+Ok+ | |||||
MEVAW3YfPEsVPf5nb/Uvo2q6Qr8OjzqPIWS4WiPOpzYdkI2abBfo/f/sn3VzXBnpbo/wOP | |||||
NHgdWPs/X1HXmohnBEAjmkGFjjvS2BZhRZ6YMimk5fOkB1qHjQ9r4FuwmiAOBdo/Mstl94 | |||||
1ZZPgzARnqeS8HB0sl0lY8+pYGbGyxxBpAR5/uC6PR5XBYUPD52leir92FTby1u6JGIIhn | |||||
R9HaLEgR8YyCBxAAAAE2xlaWxlaWxpMTI2QDE2My5jb20BAgMEBQYH | |||||
-----END OPENSSH PRIVATE KEY----- |
@@ -0,0 +1 @@ | |||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCxu2EpX/7xi7lXZHaq4bVfLqS+Rno9xHNKhqvFeHrPGjFWXIRk1c/T1r2N1/V9LaX0pFqKbGOv3iYfivwkYvpp/J6ArA8kLKN5euOwUkynKfhgA6zmpMw7fhZs7zwFJzneiYNa4+9BpAU+kwrmsCzgTlzaj3W2TNGSznb4HZjXCQhgVlgMEe6BWCJjsHo8dCJEagwpu4zmC/FTXMa8a6a9ShSjSVezygsW0emnaNnKkl2WBFEZ9XN/D5sPcut8fsnr4ux7ltkSw0H7HFE7apAxv/Z86I/R9FdlFZf49OS+mo3HG5vsWKXxeNRjQzZbT8MbzA8Ax8/G3wFlj1yIsv6+w2hs8POweA7FsPT6dzhdWi75F0xoCbGzxr3kEZWyLTbfqVoD+kdwxzJqsIaNrAmtkr7IF77v01Tjm6YwH25efsJjiPihRfmLNMe76X22KqlFiyZ6BxAxIGAO8939DnySAhtbJu905Qz04x9h5Z9RfK9PzgE5VU1cYap0qshbJwM= leileili126@163.com |