220821
This commit is contained in:
parent
dd67ce3cf4
commit
82a5910b95
|
@ -845,7 +845,7 @@ class _TestResult(unittest.TestResult):
|
|||
def startTest(self, test):
|
||||
# 单条用例执行开始前的动作
|
||||
if self.verbosity >= 2:
|
||||
sys.stderr.write(_Color(fc=39, bc=4, bo=1, text='%-79s' % ('%04d Testing...' % (len(self.result) + 1))) + "\n")
|
||||
sys.stderr.write(_Color(fc=39, bc=4, bo=1, text='%-79s' % ('%04d @ Testing...' % (len(self.result) + 1))) + "\n")
|
||||
super().startTest(test)
|
||||
if self.verbosity >= 0:
|
||||
self.loggerStream = io.StringIO()
|
||||
|
@ -1072,7 +1072,7 @@ class HTMLTestRunner(Template_mixin):
|
|||
sys.stderr.write(_Color(fc=37, bo=0, text=str(i + 1) + '. ' + value[1][i]) + "\n")
|
||||
if len(casesort.keys()):
|
||||
sys.stderr.write(_Color(fc=34, bo=1,
|
||||
text='%-16s' % ('用例集合') + "\t" +
|
||||
text='%-22s' % ('用例集合') + "\t" +
|
||||
'%-4s' % ('总计') + "\t" +
|
||||
'%-4s' % ('通过') + "\t" +
|
||||
'%-4s' % ('失败') + "\t" +
|
||||
|
@ -1080,12 +1080,12 @@ class HTMLTestRunner(Template_mixin):
|
|||
'%-8s' % ('耗时') + "\t") + "\n")
|
||||
for key, value in casesort.items():
|
||||
sys.stderr.write(_Color(fc=37, bo=0,
|
||||
text='%-16s' % (str(key)) + "\t" +
|
||||
text='%-22s' % (str(key)) + "\t" +
|
||||
'%-4s' % (str(value["p"] + value["f"] + value["e"])) + "\t" +
|
||||
'%-4s' % (str(value["p"])) + "\t" +
|
||||
'%-4s' % (str(value["f"])) + "\t" +
|
||||
'%-4s' % (str(value["e"])) + "\t" +
|
||||
'%.3f' % (round(value["d"], 3)) + '秒' + "\t"
|
||||
'%-8s' % ('%.3f' % (round(value["d"], 3)) + '秒') + "\t"
|
||||
) + "\n")
|
||||
return result
|
||||
|
||||
|
|
1329
HTMLTestRunner.py
1329
HTMLTestRunner.py
File diff suppressed because it is too large
Load Diff
|
@ -229,7 +229,7 @@
|
|||
series: [{
|
||||
name: '通过',
|
||||
color: '#64bb64',
|
||||
data: [2]
|
||||
data: [4]
|
||||
}, {
|
||||
name: '失败',
|
||||
color: '#f16d7e',
|
||||
|
@ -291,7 +291,7 @@
|
|||
innerSize: '80%',
|
||||
name: '比例',
|
||||
data: [
|
||||
['通过', 2], ['失败', 0], ['错误', 0]
|
||||
['通过', 4], ['失败', 0], ['错误', 0]
|
||||
]
|
||||
}]
|
||||
}, function(c) {
|
||||
|
@ -438,11 +438,11 @@ function html_escape(s) {
|
|||
<div id="testinfo" style="max-width: 360px; width: auto; float: left;">
|
||||
<h1 style="margin: 5px 0px 10px 0px; font-family: Microsoft YaHei;">测试报告</h1>
|
||||
|
||||
<p class='attribute'><strong>开始时间 : </strong> 2022-08-16 18:41:36</p>
|
||||
<p class='attribute'><strong>开始时间 : </strong> 2022-08-21 02:25:13</p>
|
||||
|
||||
<p class='attribute'><strong>合计耗时 : </strong> 00:00:00</p>
|
||||
<p class='attribute'><strong>合计耗时 : </strong> 00:00:01</p>
|
||||
|
||||
<p class='attribute'><strong>测试结果 : </strong> 总共 2,通过 2,失败 0,错误 0,通过率 100.00%</p>
|
||||
<p class='attribute'><strong>测试结果 : </strong> 总共 4,通过 4,失败 0,错误 0,通过率 100.00%</p>
|
||||
|
||||
<p class='attribute'><strong>失败用例 : </strong> 无</p>
|
||||
|
||||
|
@ -458,10 +458,10 @@ function html_escape(s) {
|
|||
<div style="width: auto; clear: both;">
|
||||
<p id='show_detail_line'>
|
||||
<a class="btn btn-primary" href='javascript:showCase(0)'>概要 100.00%</a>
|
||||
<a class="btn btn-success" href='javascript:showCase(2)'>通过 2</a>
|
||||
<a class="btn btn-success" href='javascript:showCase(2)'>通过 4</a>
|
||||
<a class="btn btn-danger" href='javascript:showCase(1)'>失败 0</a>
|
||||
<a class="btn btn-warning" href='javascript:showCase(3)'>错误 0</a>
|
||||
<a class="btn btn-info" href='javascript:showCase(4)'>全部 2</a>
|
||||
<a class="btn btn-info" href='javascript:showCase(4)'>全部 4</a>
|
||||
</p>
|
||||
</div>
|
||||
<table id='result_table' class="table table-condensed table-bordered table-hover">
|
||||
|
@ -489,24 +489,25 @@ function html_escape(s) {
|
|||
<tr class='passClass warning'>
|
||||
<td>测试用例</td>
|
||||
<td></td>
|
||||
<td class="text-center">2</td>
|
||||
<td class="text-center">2</td>
|
||||
<td class="text-center">4</td>
|
||||
<td class="text-center">4</td>
|
||||
<td class="text-center">0</td>
|
||||
<td class="text-center">0</td>
|
||||
<td class="text-center">0.238秒</td>
|
||||
<td class="text-center"><a href="javascript:showClassDetail('c1',2)" class="detail" id='c1'>查看全部</a></td>
|
||||
<td class="text-center">1.172秒</td>
|
||||
<td class="text-center"><a href="javascript:showClassDetail('c1',4)" class="detail" id='c1'>查看全部</a></td>
|
||||
</tr>
|
||||
|
||||
<tr id='pt1_1' class='hiddenRow'>
|
||||
<td class='passedCase' style="vertical-align: middle"><div class='testcase'>test0001_lookup2</div></td>
|
||||
<td style="vertical-align: middle"></td>
|
||||
<td class='passedCase' style="vertical-align: middle"><div class='testcase'>test0001_login2</div></td>
|
||||
<td style="vertical-align: middle">P0:测试正常登录</td>
|
||||
<td colspan='5' align='center'>
|
||||
<button id='btn_pt1_1' type="button" class="btn btn-xs" data-toggle="collapse" data-target='#div_pt1_1'>通过</button>
|
||||
<div id='div_pt1_1' class="collapse in">
|
||||
<pre style="text-align:left;font-family:monospace;font-size:12px;color:#119611">pt1_1:
|
||||
2022-08-16 18:41:36,269 - D:
|
||||
2022-08-21 02:25:13,190 - D: test0001_login2
|
||||
2022-08-21 02:25:13,469 - D:
|
||||
[->]
|
||||
GET /iplookup?ip=127.0.0.1 HTTP/1.1
|
||||
GET / HTTP/1.1
|
||||
Host: www.fanscloud.net
|
||||
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36
|
||||
Accept-Encoding: gzip, deflate
|
||||
|
@ -517,14 +518,20 @@ Connection: keep-alive
|
|||
[<-]
|
||||
HTTP/1.1 200 OK
|
||||
Server: nginx
|
||||
Date: Tue, 16 Aug 2022 10:41:36 GMT
|
||||
Content-Type: text/html; charset=utf-8
|
||||
Date: Sat, 20 Aug 2022 18:25:13 GMT
|
||||
Content-Type: text/html; charset=UTF-8
|
||||
Transfer-Encoding: chunked
|
||||
Connection: keep-alive
|
||||
Vary: Accept-Encoding
|
||||
Content-Encoding: gzip
|
||||
|
||||
127.0.0.1 保留地址
|
||||
<!doctype html>
|
||||
<html lang="zh-cn">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<title>阿凡的Blog🌿</title>
|
||||
<meta name="keywo ... [MORE 98% OMITTED HERE]
|
||||
</pre>
|
||||
</div>
|
||||
</td>
|
||||
|
@ -532,15 +539,16 @@ Content-Encoding: gzip
|
|||
</tr>
|
||||
|
||||
<tr id='pt1_2' class='hiddenRow'>
|
||||
<td class='passedCase' style="vertical-align: middle"><div class='testcase'>test0002_lookup2</div></td>
|
||||
<td style="vertical-align: middle"></td>
|
||||
<td class='passedCase' style="vertical-align: middle"><div class='testcase'>test0002_login4</div></td>
|
||||
<td style="vertical-align: middle">P0:测试正常登录</td>
|
||||
<td colspan='5' align='center'>
|
||||
<button id='btn_pt1_2' type="button" class="btn btn-xs" data-toggle="collapse" data-target='#div_pt1_2'>通过</button>
|
||||
<div id='div_pt1_2' class="collapse in">
|
||||
<pre style="text-align:left;font-family:monospace;font-size:12px;color:#119611">pt1_2:
|
||||
2022-08-16 18:41:36,342 - D:
|
||||
2022-08-21 02:25:13,470 - D: test0002_login4
|
||||
2022-08-21 02:25:13,760 - D:
|
||||
[->]
|
||||
GET /iplookup?ip=127.0.0.1 HTTP/1.1
|
||||
GET / HTTP/1.1
|
||||
Host: www.fanscloud.net
|
||||
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36
|
||||
Accept-Encoding: gzip, deflate
|
||||
|
@ -551,17 +559,37 @@ Connection: keep-alive
|
|||
[<-]
|
||||
HTTP/1.1 200 OK
|
||||
Server: nginx
|
||||
Date: Tue, 16 Aug 2022 10:41:37 GMT
|
||||
Content-Type: text/html; charset=utf-8
|
||||
Date: Sat, 20 Aug 2022 18:25:13 GMT
|
||||
Content-Type: text/html; charset=UTF-8
|
||||
Transfer-Encoding: chunked
|
||||
Connection: keep-alive
|
||||
Vary: Accept-Encoding
|
||||
Content-Encoding: gzip
|
||||
|
||||
127.0.0.1 保留地址
|
||||
2022-08-16 18:41:36,364 - D:
|
||||
<!doctype html>
|
||||
<html lang="zh-cn">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<title>阿凡的Blog🌿</title>
|
||||
<meta name="keywo ... [MORE 98% OMITTED HERE]
|
||||
</pre>
|
||||
</div>
|
||||
</td>
|
||||
<td class='passedCase' style="vertical-align: middle"></td>
|
||||
</tr>
|
||||
|
||||
<tr id='pt1_3' class='hiddenRow'>
|
||||
<td class='passedCase' style="vertical-align: middle"><div class='testcase'>test0003_login1</div></td>
|
||||
<td style="vertical-align: middle">P1:测试正常登录</td>
|
||||
<td colspan='5' align='center'>
|
||||
<button id='btn_pt1_3' type="button" class="btn btn-xs" data-toggle="collapse" data-target='#div_pt1_3'>通过</button>
|
||||
<div id='div_pt1_3' class="collapse in">
|
||||
<pre style="text-align:left;font-family:monospace;font-size:12px;color:#119611">pt1_3:
|
||||
2022-08-21 02:25:13,761 - D: test0003_login1
|
||||
2022-08-21 02:25:14,047 - D:
|
||||
[->]
|
||||
GET /iplookup?ip=127.0.0.2 HTTP/1.1
|
||||
GET / HTTP/1.1
|
||||
Host: www.fanscloud.net
|
||||
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36
|
||||
Accept-Encoding: gzip, deflate
|
||||
|
@ -572,14 +600,61 @@ Connection: keep-alive
|
|||
[<-]
|
||||
HTTP/1.1 200 OK
|
||||
Server: nginx
|
||||
Date: Tue, 16 Aug 2022 10:41:37 GMT
|
||||
Content-Type: text/html; charset=utf-8
|
||||
Date: Sat, 20 Aug 2022 18:25:14 GMT
|
||||
Content-Type: text/html; charset=UTF-8
|
||||
Transfer-Encoding: chunked
|
||||
Connection: keep-alive
|
||||
Vary: Accept-Encoding
|
||||
Content-Encoding: gzip
|
||||
|
||||
127.0.0.2 保留地址
|
||||
<!doctype html>
|
||||
<html lang="zh-cn">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<title>阿凡的Blog🌿</title>
|
||||
<meta name="keywo ... [MORE 98% OMITTED HERE]
|
||||
</pre>
|
||||
</div>
|
||||
</td>
|
||||
<td class='passedCase' style="vertical-align: middle"></td>
|
||||
</tr>
|
||||
|
||||
<tr id='pt1_4' class='hiddenRow'>
|
||||
<td class='passedCase' style="vertical-align: middle"><div class='testcase'>test0004_login3</div></td>
|
||||
<td style="vertical-align: middle">P1:测试正常登录</td>
|
||||
<td colspan='5' align='center'>
|
||||
<button id='btn_pt1_4' type="button" class="btn btn-xs" data-toggle="collapse" data-target='#div_pt1_4'>通过</button>
|
||||
<div id='div_pt1_4' class="collapse in">
|
||||
<pre style="text-align:left;font-family:monospace;font-size:12px;color:#119611">pt1_4:
|
||||
2022-08-21 02:25:14,048 - D: test0004_login3
|
||||
2022-08-21 02:25:14,363 - D:
|
||||
[->]
|
||||
GET / HTTP/1.1
|
||||
Host: www.fanscloud.net
|
||||
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36
|
||||
Accept-Encoding: gzip, deflate
|
||||
Accept: */*
|
||||
Connection: keep-alive
|
||||
|
||||
|
||||
[<-]
|
||||
HTTP/1.1 200 OK
|
||||
Server: nginx
|
||||
Date: Sat, 20 Aug 2022 18:25:14 GMT
|
||||
Content-Type: text/html; charset=UTF-8
|
||||
Transfer-Encoding: chunked
|
||||
Connection: keep-alive
|
||||
Vary: Accept-Encoding
|
||||
Content-Encoding: gzip
|
||||
|
||||
<!doctype html>
|
||||
<html lang="zh-cn">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<title>阿凡的Blog🌿</title>
|
||||
<meta name="keywo ... [MORE 98% OMITTED HERE]
|
||||
</pre>
|
||||
</div>
|
||||
</td>
|
||||
|
@ -588,11 +663,11 @@ Content-Encoding: gzip
|
|||
|
||||
<tr id='total_row' class="text-center active">
|
||||
<td colspan='2'>总计</td>
|
||||
<td>2</td>
|
||||
<td>2</td>
|
||||
<td>4</td>
|
||||
<td>4</td>
|
||||
<td>0</td>
|
||||
<td>0</td>
|
||||
<td>0.238秒</td>
|
||||
<td>1.172秒</td>
|
||||
<td>通过:100.00%</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import time
|
||||
import unittest
|
||||
from typing import Any, Text, Dict, List
|
||||
from argparse import ArgumentParser
|
||||
from Business.Class.HTMLTestRunner import HTMLTestRunner
|
||||
from Business.Class.ExcelUtils import *
|
||||
from Business.Class.JsonOrYaml import *
|
||||
|
@ -40,18 +39,18 @@ class ReList(list):
|
|||
return ReDict(r)
|
||||
else:
|
||||
return ReText(r)
|
||||
except:
|
||||
except Exception:
|
||||
return __class__()
|
||||
else:
|
||||
try:
|
||||
return reparse(item, str(self.__str__()))
|
||||
except:
|
||||
except Exception:
|
||||
return ReText('')
|
||||
|
||||
def __str__(self):
|
||||
try:
|
||||
return ReText(self[0])
|
||||
except:
|
||||
except Exception:
|
||||
return ReText('')
|
||||
|
||||
|
||||
|
@ -71,7 +70,7 @@ class ReDict(dict):
|
|||
else:
|
||||
try:
|
||||
return reparse(item, str(self.__str__()))
|
||||
except:
|
||||
except Exception:
|
||||
return ReText('')
|
||||
|
||||
def __str__(self):
|
||||
|
@ -80,7 +79,7 @@ class ReDict(dict):
|
|||
return ReText(self.__getitem__('_'))
|
||||
else:
|
||||
return json_encode(self, indent=None, unicode=False)
|
||||
except:
|
||||
except Exception:
|
||||
return ReText('')
|
||||
|
||||
def update(self, *args, **kwargs):
|
||||
|
@ -104,7 +103,15 @@ class TestCase:
|
|||
_g = {}
|
||||
_l = {}
|
||||
|
||||
def __init__(self, workbook: Text, testlves: List, cases: Text, mysql: Text, httpc: Text):
|
||||
def __del__(self):
|
||||
if self.write_test_result:
|
||||
self.c_excel_object.save()
|
||||
self.b_excel_object.save()
|
||||
self.h_excel_object.save()
|
||||
|
||||
def __init__(self, workbook: str, testcase: str, module: str = None, testlves=None, organize_mode=None, write_test_result=None):
|
||||
if isinstance(testlves, str):
|
||||
testlves = [value.strip() for value in list(filter(lambda x: x, testlves.split(',')))]
|
||||
tabs = {
|
||||
"HTTPConf": {
|
||||
"fixed": {},
|
||||
|
@ -181,11 +188,11 @@ class TestCase:
|
|||
for k, v in tabs.items():
|
||||
match k:
|
||||
case 'TestCase':
|
||||
sheet = cases
|
||||
sheet = testcase
|
||||
case 'DataBase':
|
||||
sheet = mysql
|
||||
sheet = '请求配置'
|
||||
case 'HTTPConf':
|
||||
sheet = httpc
|
||||
sheet = '请求配置'
|
||||
case _:
|
||||
continue
|
||||
self.init.select(sheet)
|
||||
|
@ -200,19 +207,19 @@ class TestCase:
|
|||
data[k]['ocell'] = read_view_dict(
|
||||
filename=workbook, sheet=sheet, area=v['views'], fields=v['field'], auto_truncate=True, object_cell=True)
|
||||
|
||||
self.case = cases
|
||||
self.module_name = module
|
||||
self.write_test_result = write_test_result
|
||||
self.case = '%s_%s' % (testcase, module) if module else testcase
|
||||
self.dirs = os.path.dirname(workbook)
|
||||
self.request = Request()
|
||||
self.session = Session()
|
||||
|
||||
self.h = DataFrame(data['HTTPConf']['views']['data'])
|
||||
self.b = DataFrame(data['DataBase']['views']['data'])
|
||||
self.c = DataFrame(data['TestCase']['views']['data'])
|
||||
|
||||
self.h_ocell = DataFrame(data['HTTPConf']['ocell']['data'])
|
||||
self.b_ocell = DataFrame(data['DataBase']['ocell']['data'])
|
||||
self.c_ocell = DataFrame(data['TestCase']['ocell']['data'])
|
||||
|
||||
self.h_vc = DataFrame(data['HTTPConf']['views']['data']).reset_index(drop=False, inplace=False)
|
||||
self.b_vc = DataFrame(data['DataBase']['views']['data']).reset_index(drop=False, inplace=False)
|
||||
self.c_vc = DataFrame(data['TestCase']['views']['data']).reset_index(drop=False, inplace=False)
|
||||
self.h_oc = DataFrame(data['HTTPConf']['ocell']['data']).reset_index(drop=False, inplace=False)
|
||||
self.b_oc = DataFrame(data['DataBase']['ocell']['data']).reset_index(drop=False, inplace=False)
|
||||
self.c_oc = DataFrame(data['TestCase']['ocell']['data']).reset_index(drop=False, inplace=False)
|
||||
self.h_excel_object = data['HTTPConf']['ocell']['excel_object']
|
||||
self.b_excel_object = data['DataBase']['ocell']['excel_object']
|
||||
self.c_excel_object = data['TestCase']['ocell']['excel_object']
|
||||
|
@ -238,6 +245,14 @@ class TestCase:
|
|||
|
||||
self.pre_executed_list = []
|
||||
|
||||
match str(organize_mode).upper():
|
||||
case 'BY_ORDER' | '1' | '10':
|
||||
self.organize_mode = 10
|
||||
case 'BY_LEVEL' | '2' | '20':
|
||||
self.organize_mode = 20
|
||||
case _:
|
||||
self.organize_mode = 10
|
||||
|
||||
def _set_levels(self, level_list=None):
|
||||
if isinstance(level_list, (list, tuple, str)):
|
||||
self.leve_list = level_list
|
||||
|
@ -251,7 +266,7 @@ class TestCase:
|
|||
return 10
|
||||
case '前置用例':
|
||||
return 20
|
||||
case _:
|
||||
case '关闭用例' | _:
|
||||
return 50
|
||||
|
||||
@staticmethod
|
||||
|
@ -259,7 +274,7 @@ class TestCase:
|
|||
match value:
|
||||
case '全局一次':
|
||||
return 10
|
||||
case _:
|
||||
case '总是执行' | _:
|
||||
return 50
|
||||
|
||||
@staticmethod
|
||||
|
@ -332,7 +347,7 @@ class TestCase:
|
|||
for variable_name in re.findall('\${(.*?)}', text):
|
||||
try:
|
||||
value = vars_dict[variable_name]
|
||||
except:
|
||||
except Exception:
|
||||
value = ''
|
||||
if self._is_nan(value) or value is None:
|
||||
value = ''
|
||||
|
@ -398,7 +413,7 @@ class TestCase:
|
|||
match domain:
|
||||
case 'locals':
|
||||
domain = self._l
|
||||
case 'global':
|
||||
case 'global' | _:
|
||||
domain = self._g
|
||||
vars_dict = {k if not isinstance(k, str) else k.lower(): v for k, v in vars_dict.items()}
|
||||
import re
|
||||
|
@ -455,12 +470,13 @@ class TestCase:
|
|||
actual = str(actual)
|
||||
assert actual == expect, '%s != %s' % (actual, expect)
|
||||
|
||||
def _test_unit(self, data, main=None):
|
||||
def _test_unit(self, func_name, data, main=None):
|
||||
log.d(func_name)
|
||||
if data['HTTPUri']:
|
||||
if not data['HTTPChannel']:
|
||||
raise Exception('channel not set')
|
||||
from pandas.core.frame import DataFrame
|
||||
http = self.h.where((self.h['Name'] == data['HTTPChannel']), inplace=False).dropna(how='all').reset_index(drop=True, inplace=False).loc[0].to_dict()
|
||||
http = self.h_vc.where((self.h_vc['Name'] == data['HTTPChannel']), inplace=False).dropna(how='all').reset_index(drop=True, inplace=False).loc[0].to_dict()
|
||||
res_kwargs = {
|
||||
'method': data['HTTPMethod'],
|
||||
'url': self._sub_variable_auto((http['Scheme'] or 'http').lower() + '://' + (http['Host'] or '') + data['HTTPUri']),
|
||||
|
@ -493,7 +509,7 @@ class TestCase:
|
|||
hvar = {
|
||||
'Status': ReText(res['status'] or ''),
|
||||
'Reason': ReText(res['reason'] or ''),
|
||||
'Header': ReDict(res['header'] or {}).update({'_': "\n".join([k + ': ' + (v or '') for k, v in dict(res['header'] or {}).items()])}),
|
||||
'Header': ReDict(res['header'] or {}).update({'_': "\n".join([k + ':' + "\x20" + (v or '') for k, v in dict(res['header'] or {}).items()])}),
|
||||
'Cookie': ReDict(res['cookie'] or {}).update({'_': "; ".join([k + '=' + (v or '') for k, v in dict(res['cookie'] or {}).items()])}),
|
||||
'Body': ReText(res['text'] or ''),
|
||||
'Json': ReDict(res['json'] or {}),
|
||||
|
@ -510,7 +526,7 @@ class TestCase:
|
|||
if data['BaseSql']:
|
||||
if not data['BaseChannel']:
|
||||
raise Exception('channel not set')
|
||||
base = self.b.where((self.b['Name'] == data['BaseChannel']), inplace=False).dropna(how='all').reset_index(drop=True, inplace=False).loc[0].to_dict()
|
||||
base = self.b_vc.where((self.b_vc['Name'] == data['BaseChannel']), inplace=False).dropna(how='all').reset_index(drop=True, inplace=False).loc[0].to_dict()
|
||||
conn = MySQL().connect(
|
||||
host=base['Host'], port=int(base['Port']),
|
||||
user=base['User'], password=base['Password'], database=base['Database'], charset=base['Charset'], cursor='Dict'
|
||||
|
@ -527,54 +543,73 @@ class TestCase:
|
|||
{'expect': data['BaseAssertRows'], 'actual': bvar['Rows']},
|
||||
], self.assert_list)
|
||||
|
||||
def test(self, index, update_global=None, update_locals=None):
|
||||
def test(self, index, update_global=None, update_locals=None, func_name=''):
|
||||
if isinstance(update_global, (dict,)):
|
||||
self._g.update(update_global)
|
||||
if isinstance(update_locals, (dict,)):
|
||||
self._l.update(update_locals)
|
||||
|
||||
def write_test_result(excel, object_cell, test_result):
|
||||
for cell, value in [[object_cell['TestResult'], test_result], [object_cell['TestTime'], time_strftime(fmt='%Y-%m-%d %H:%M:%S')]]:
|
||||
cell.value = value
|
||||
excel.save()
|
||||
def write_test_result(object_cell, test_result):
|
||||
for cell, new_cell_value in [[object_cell['TestResult'], test_result], [object_cell['TestTime'], time_strftime(fmt='%Y-%m-%d %H:%M:%S')]]:
|
||||
cell.value = new_cell_value
|
||||
|
||||
main_case_object_cell = self.c_ocell.loc[index].to_dict()
|
||||
main_case_object_cell = self.c_oc.loc[index].to_dict()
|
||||
try:
|
||||
main_case = dict(self.c.loc[index].to_dict())
|
||||
main_case = dict(self.c_vc.loc[index].to_dict())
|
||||
prex_list = list(filter(lambda x: x, [value.strip() for value in (main_case['PreExecCase'] or '').replace(',', "\n").split("\n")]))
|
||||
for case_id in prex_list:
|
||||
if self._match_prex_rule(main_case['PreExecRule']) == 10 and case_id in self.pre_executed_list:
|
||||
continue
|
||||
data = self.c.where((self.c['CaseId'] == case_id), inplace=False).dropna(how='all').reset_index(drop=True, inplace=False).loc[0].to_dict()
|
||||
data = self.c_vc.where((self.c_vc['CaseId'] == case_id), inplace=False).dropna(how='all').reset_index(drop=True, inplace=False).loc[0].to_dict()
|
||||
if not self._match_case_type(data['Flag']) == 20:
|
||||
raise Exception('A non-Pre-exec case was called.')
|
||||
if data['PreExecCase'] or data['PreExecRule']:
|
||||
raise Exception('Pre-exec case cannot be nested.')
|
||||
if data['DataFileSet']:
|
||||
raise Exception('Pre-exec case cannot use data files set.')
|
||||
self.pre_executed_list.append(case_id)
|
||||
self._test_unit(data=data)
|
||||
self._test_unit(data=main_case, main=True)
|
||||
self._test_unit(func_name=func_name, data=data)
|
||||
# self.__getattribute__(func_name)(data=data)
|
||||
self._test_unit(func_name=func_name, data=main_case, main=True)
|
||||
# self.__getattribute__(func_name)(data=main_case, main=True)
|
||||
self._l and self._l.clear()
|
||||
write_test_result(self.c_excel_object, main_case_object_cell, 'Passed')
|
||||
write_test_result(main_case_object_cell, 'Passed')
|
||||
except AssertionError:
|
||||
self._l and self._l.clear()
|
||||
write_test_result(self.c_excel_object, main_case_object_cell, 'Failed')
|
||||
write_test_result(main_case_object_cell, 'Failed')
|
||||
raise
|
||||
except Exception:
|
||||
self._l and self._l.clear()
|
||||
write_test_result(self.c_excel_object, main_case_object_cell, 'Errors')
|
||||
write_test_result(main_case_object_cell, 'Errors')
|
||||
raise
|
||||
|
||||
def main(self):
|
||||
from pandas import read_csv
|
||||
|
||||
class ClassTestCase(unittest.TestCase):
|
||||
pass
|
||||
|
||||
ClassTestCase.__qualname__ = self.case
|
||||
ClassTestCase._test_ = self.test
|
||||
|
||||
from pandas import read_csv
|
||||
|
||||
while 1:
|
||||
if self.organize_mode == 20:
|
||||
levels_list = self.leve_list
|
||||
loop = len(levels_list)
|
||||
else:
|
||||
levels_list = None
|
||||
loop = 1
|
||||
break
|
||||
|
||||
serial = 0
|
||||
for i in range(len(self.c)):
|
||||
data = self.c.loc[i].to_dict()
|
||||
for n in range(loop):
|
||||
filter_module = self.c_vc['CaseModule'] == self.module_name if self.module_name else self.c_vc['CaseModule'] != '*'
|
||||
if self.organize_mode == 20:
|
||||
case = self.c_vc.where(filter_module & (self.c_vc['CaseLevel'] == levels_list[n]), inplace=False).dropna(how='all')
|
||||
else:
|
||||
case = self.c_vc.where(filter_module, inplace=False).dropna(how='all')
|
||||
for i in range(len(case)):
|
||||
data = case.iloc[i].to_dict()
|
||||
if not (self._match_case_type(data['Flag']) == 10 and self._match_leve_run(data['CaseLevel'])): continue
|
||||
serial += 1
|
||||
filename = data['DataFileSet'] or ''
|
||||
|
@ -591,51 +626,128 @@ class TestCase:
|
|||
match data_file_flag:
|
||||
case 1:
|
||||
vars_data = data_file.loc[j].to_dict()
|
||||
func_docs = str(data['CaseTitle'] or '') + '_' + '_'.join([str(v) for k, v in vars_data.items()])[:32]
|
||||
func_docs = str(data['CaseLevel'] or 'P?') + ':' + str(data['CaseTitle'] or '') + '_' + '_'.join([str(v) for k, v in vars_data.items()])[:32]
|
||||
func_name = 'test%s_%s_%s' % (str('%04d' % serial), str(data['CaseId']), str('%04d' % (j + 1)))
|
||||
once_do_break = 0
|
||||
case _:
|
||||
vars_data = None
|
||||
func_docs = str(data['CaseTitle'] or '')
|
||||
func_docs = str(data['CaseLevel'] or 'P?') + ':' + str(data['CaseTitle'] or '')
|
||||
func_name = 'test%s_%s' % (str('%04d' % serial), str(data['CaseId']))
|
||||
once_do_break = 1
|
||||
|
||||
def func(self, index=i, update_global=None, update_locals=vars_data):
|
||||
return self._test_(index=index, update_global=update_global, update_locals=update_locals)
|
||||
def func(self, index=data['index'], update_global=None, update_locals=vars_data, func_name=func_name):
|
||||
return self._test_(index=index, update_global=update_global, update_locals=update_locals, func_name=func_name)
|
||||
|
||||
func.__doc__ = func_docs
|
||||
type.__setattr__(ClassTestCase, func_name, func)
|
||||
j += 1
|
||||
if once_do_break: break
|
||||
|
||||
# if filename:
|
||||
# data_file = read_csv(os.path.join(self.dirs, './%s' % filename), keep_default_na=False)
|
||||
# for j in range(len(data_file)):
|
||||
# vars_data = data_file.loc[j].to_dict()
|
||||
#
|
||||
# def func(self, index=i, update_global=None, update_locals=vars_data):
|
||||
# return self._test_(index=index, update_global=update_global, update_locals=update_locals)
|
||||
#
|
||||
# func.__doc__ = (data['CaseTitle'] or '') + '_' + '_'.join([str(v) for k, v in vars_data.items()])[:32]
|
||||
# type.__setattr__(ClassTestCase, 'test%s_%s_%s' % (str('%04d' % serial), str(data['CaseId']), str('%04d' % (j+1))), func)
|
||||
# else:
|
||||
# def func(self, index=i, update_global=None, update_locals=None):
|
||||
# return self._test_(index=index, update_global=update_global, update_locals=update_locals)
|
||||
#
|
||||
# func.__doc__ = data['CaseTitle']
|
||||
# type.__setattr__(ClassTestCase, 'test%s_%s' % (str('%04d' % serial), str(data['CaseId'])), func)
|
||||
|
||||
return ClassTestCase
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
def read_runner_config(file: str):
|
||||
import os
|
||||
path = os.path.abspath(os.path.join(os.getcwd(), file))
|
||||
return auto_decode(open(path, 'r', encoding='utf-8').read())
|
||||
|
||||
|
||||
def abs_path(file: str):
|
||||
if isinstance(file, str):
|
||||
return os.path.abspath(os.path.join(os.getcwd(), file))
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
test_class = TestCase(
|
||||
workbook='D:/Desktop/2.xlsx',
|
||||
testcase='测试用例',
|
||||
module='',
|
||||
testlves='P0,P1',
|
||||
organize_mode='BY_LEVEL',
|
||||
write_test_result=True
|
||||
).main()
|
||||
test_suite = unittest.TestSuite()
|
||||
test_suite.addTest(unittest.makeSuite(testCaseClass=TestCase(
|
||||
workbook='D:/Desktop/接口自动化测试用例.xlsx',
|
||||
testlves=None,
|
||||
cases='测试用例',
|
||||
httpc='请求配置',
|
||||
mysql='请求配置'
|
||||
).main(), prefix='test'))
|
||||
HTMLTestRunner(verbosity=5, report=os.path.abspath(os.path.join(os.path.dirname(__file__), './1.html'))).run(
|
||||
test_suite)
|
||||
test_suite.addTest(unittest.makeSuite(testCaseClass=test_class, prefix='test'))
|
||||
HTMLTestRunner(verbosity=5, log=os.path.abspath(os.path.join(os.path.dirname(__file__), 'D:/Desktop/2.log')), report=os.path.abspath(os.path.join(os.path.dirname(__file__), './1.html'))).run(test_suite)
|
||||
|
||||
exit(0)
|
||||
argparser = ArgumentParser(
|
||||
description='API Test Runner',
|
||||
usage="\n" + os.path.basename(__file__) + ' [-c CONFIG]' + "\n" + os.path.basename(__file__) + ' [-w WORKBOOK] [-t TESTCASE] [-m MODULE] [-l LEVELS] [-o ORGANIZE] [-r WRITE_TEST_RESULT] [-v VERBOSITY] [-p REPORT] [-x LOG] [-i TITLE] [-d DESCRIPTION]'
|
||||
)
|
||||
argparser.add_argument(
|
||||
'-c',
|
||||
required=bool(0), help='Load runner configuration file.',
|
||||
choices=None, default=None, dest='config'
|
||||
)
|
||||
argparser.add_argument(
|
||||
'-w',
|
||||
required=bool(0), help='Excel workbook path.',
|
||||
choices=None, default='./', dest='workbook'
|
||||
)
|
||||
argparser.add_argument(
|
||||
'-t',
|
||||
required=bool(0), help='Testcase worksheet name.',
|
||||
choices=None, default='测试用例', dest='testcase'
|
||||
)
|
||||
argparser.add_argument(
|
||||
'-m',
|
||||
required=bool(0), help='You can specify a module name.',
|
||||
choices=None, default=None, dest='module'
|
||||
)
|
||||
argparser.add_argument(
|
||||
'-l',
|
||||
required=bool(0), help='Case levels can be specified, use comma to separate, e.g. P0,P1,P2.',
|
||||
choices=None, default=None, dest='levels'
|
||||
)
|
||||
argparser.add_argument(
|
||||
'-o',
|
||||
required=bool(0), help='Case organization mode, 1: by order, 2: by level, default: 1.',
|
||||
choices=[1, 2], default=None, dest='organize', type=int
|
||||
)
|
||||
argparser.add_argument(
|
||||
'-r',
|
||||
required=bool(0), help='Enable writing test results to current worksheet, default: 0.',
|
||||
choices=[bool(0), bool(1)], default=None, dest='write_test_result', type=bool
|
||||
)
|
||||
argparser.add_argument(
|
||||
'-v',
|
||||
required=bool(0), help='Level of report and log verbosity(0-5), default: 5.',
|
||||
choices=[0, 1, 2, 3, 4, 5], default=5, dest='verbosity', type=int
|
||||
)
|
||||
argparser.add_argument(
|
||||
'-p',
|
||||
required=bool(0), help='Output path of report.',
|
||||
choices=None, default=None, dest='report'
|
||||
)
|
||||
argparser.add_argument(
|
||||
'-x',
|
||||
required=bool(0), help='Output path of log.',
|
||||
choices=None, default=None, dest='log'
|
||||
)
|
||||
argparser.add_argument(
|
||||
'-i',
|
||||
required=bool(0), help='Report title.',
|
||||
choices=None, default=None, dest='title'
|
||||
)
|
||||
argparser.add_argument(
|
||||
'-d',
|
||||
required=bool(0), help='Report description.',
|
||||
choices=None, default=None, dest='description'
|
||||
)
|
||||
args = argparser.parse_args()
|
||||
print(args)
|
||||
if args.config:
|
||||
config = read_runner_config(args.config)
|
||||
else:
|
||||
config = {
|
||||
'verbosity': args.verbosity, 'report': args.report, 'log': args.log, 'title': args.title, 'description': args.description,
|
||||
'suite': [{"workbook": args.workbook, "testcase": args.testcase, "module": args.module, "levels": args.levels, "organize": args.organize, "result": args.write_test_result}]
|
||||
}
|
||||
test_suite = unittest.TestSuite()
|
||||
for obj in config['suite']:
|
||||
test_suite.addTest(unittest.makeSuite(
|
||||
testCaseClass=TestCase(workbook=obj['workbook'], testcase=obj['testcase'], module=obj['module'], testlves=obj['levels'], organize_mode=obj['organize'], write_test_result=obj['result']).main(), prefix='test'
|
||||
))
|
||||
HTMLTestRunner(verbosity=config['verbosity'], report=abs_path(config['report']), log=abs_path(config['log']), title=config['title'], description=config['description']).run(test_suite)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
{"verbosity": 5, "report": null, "log": null, "title": null, "description": null , "suite": [{"workbook": "D:/Desktop/接口自动化测试用例.xlsx", "testcase": "测试用例", "module": null, "levels": "P0,P1,P2,P3", "organize": 1, "result": true}]}
|
BIN
example.xlsx
BIN
example.xlsx
Binary file not shown.
|
@ -1,194 +0,0 @@
|
|||
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
|
Binary file not shown.
22
main5.py
22
main5.py
|
@ -1,16 +1,6 @@
|
|||
import pandas as pd
|
||||
# from Base.Class.Yaml import *
|
||||
# from pandas import read_csv
|
||||
# df = read_csv("D:/Desktop/新建 XLSX 工作表.csv", keep_default_na=False)
|
||||
# print(df.loc[2].to_dict())
|
||||
from pandas.core.frame import DataFrame
|
||||
from Base.Class.Database import *
|
||||
conn = MySQL().connect(host='sdm821105491.my3w.com', port=3306, user='sdm821105491', password='1234ABCDabcd', database='sdm821105491_db', charset='utf8')
|
||||
conn.execute('select gid,title,date,content from %s;' % 'emlog_blog')
|
||||
data = conn.fetchall()
|
||||
# print(data)
|
||||
print(conn.brief())
|
||||
|
||||
|
||||
|
||||
|
||||
try:
|
||||
assert 1 == 2
|
||||
except AssertionError:
|
||||
print('断言错误')
|
||||
except Exception:
|
||||
print('出错了')
|
||||
|
|
48
main6.py
48
main6.py
|
@ -1,16 +1,34 @@
|
|||
# from Base.Class.Excel import *
|
||||
# from Business.Class.ExcelUtils import *
|
||||
# from argparse import ArgumentParser
|
||||
# def func():
|
||||
# print('哈哈哈哈')
|
||||
#
|
||||
# # excel = Excel().open(filename='D:/Desktop/接口自动化测试用例.xlsx', sheet='测试用例')
|
||||
# # data = excel.cellGetView(area='7A:7AH', ocell=True)
|
||||
# # print(data)
|
||||
# # # data[0][0] = '11111'
|
||||
# # excel.save()
|
||||
# a = read_view_dict(filename='D:/Desktop/接口自动化测试用例.xlsx', sheet='测试用例', area='A7:AH7', object_cell=True)
|
||||
# print(a[0]['col0'].value)
|
||||
# a[0]['col0'].value = 'Passed'
|
||||
# print(a[0]['col0'].value)
|
||||
# from Base.Class.Time import *
|
||||
# print(time_strftime(fmt='%Y-%m-%d %H:%M:%S'))
|
||||
for k, v in [[1,2],[3,4]]:
|
||||
print(k,v)
|
||||
# if __name__ == "__main__":
|
||||
# argparser = ArgumentParser(description='API Test Runner')
|
||||
# argparser.add_argument(
|
||||
# '--',
|
||||
# required=bool(1), help='',
|
||||
# choices=None, default=''
|
||||
# )
|
||||
#
|
||||
# results = argparser.parse_args()
|
||||
# print(results)
|
||||
# from Business.Class.JsonOrYaml import *
|
||||
#
|
||||
#
|
||||
# def read_runner_config(file: str):
|
||||
# import os
|
||||
# path = os.path.abspath(os.path.join(os.path.dirname(__file__), file))
|
||||
# if os.path.exists(path):
|
||||
# return auto_decode(open(path, 'r', encoding='utf-8').read())
|
||||
# else:
|
||||
# return False
|
||||
#
|
||||
#
|
||||
# print(read_runner_config('D:/Project/AutoFramework/Runner/API/api_runner.json'))
|
||||
# import os
|
||||
# print(os.path.abspath(os.path.join(os.getcwd(), './1/2/log.txt')))
|
||||
|
||||
import os
|
||||
print(os.path.abspath(os.path.join(os.path.dirname(__file__), 'D:/Desktop/2.log')))
|
||||
|
||||
a = 2 == 2 if os else 1 != 2
|
||||
|
|
703
report.html
703
report.html
|
@ -1,703 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>自动化测试报告</title>
|
||||
<meta name="generator" content="HTMLTestRunner"/>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0"/>
|
||||
<link rel="stylesheet" href="https://www.fanscloud.net/res/bootstrap/3.0.3/css/bootstrap.min.css">
|
||||
<script src="https://www.fanscloud.net/res/jquery/2.0.0/jquery.min.js"></script>
|
||||
<script src="https://www.fanscloud.net/res/bootstrap/3.0.3/js/bootstrap.min.js"></script>
|
||||
<script src="https://img.hcharts.cn/highcharts/highcharts.js"></script>
|
||||
<script src="https://img.hcharts.cn/highcharts/modules/exporting.js"></script>
|
||||
|
||||
<style type="text/css" media="screen">
|
||||
body { font-family: Microsoft YaHei;padding: 20px; font-size: 100%; }
|
||||
table { font-size: 100%; }
|
||||
.table tbody tr td{
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* -- header ---------------------------------------------------------------------- */
|
||||
.header .description, .attribute {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
/* --- 失败和错误合集样式 -- Gelomen --- */
|
||||
.failCollection, .errorCollection {
|
||||
width: auto;
|
||||
float: left;
|
||||
}
|
||||
#failedCaseOl li {
|
||||
color: red
|
||||
}
|
||||
#errorsCaseOl li {
|
||||
color: orange
|
||||
}
|
||||
|
||||
/* --- 打开截图特效样式 -- Gelomen --- */
|
||||
.data-img{
|
||||
cursor:pointer
|
||||
}
|
||||
|
||||
.pic_looper{
|
||||
width:100%;
|
||||
height:100%;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top:0;
|
||||
opacity: 0.6;
|
||||
background: #000;
|
||||
display: none;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.pic_show{
|
||||
width:100%;
|
||||
position:fixed;
|
||||
left:0;
|
||||
top:0;
|
||||
right:0;
|
||||
bottom:0;
|
||||
margin:auto;
|
||||
text-align: center;
|
||||
display: none;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.pic_box{
|
||||
padding:10px;
|
||||
width:90%;
|
||||
height:90%;
|
||||
margin:40px auto;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.pic_box img{
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
width: auto;
|
||||
height: auto;
|
||||
-moz-box-shadow: 0px 0px 20px 0px #000;
|
||||
-webkit-box-shadow: 0px 0px 20px 0px #000;
|
||||
box-shadow: 0px 0px 20px 0px #000;
|
||||
}
|
||||
|
||||
/* --- 饼状图样式 */
|
||||
#container {
|
||||
max-width: 100%;
|
||||
width: 450px;
|
||||
height: 350px;
|
||||
float: left;
|
||||
}
|
||||
#container_extend {
|
||||
max-width: 100%;
|
||||
width: 550px;
|
||||
height: 400px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
|
||||
/* -- report ------------------------------------------------------------------------ */
|
||||
#total_row { font-weight: bold; }
|
||||
.passedCase { color: #3FB83F; font-family: Menlo,Monaco,Consolas,"Courier New",monospace; font-size: 14px; font-weight: bold; }
|
||||
.failedCase { color: #D9433F; font-family: Menlo,Monaco,Consolas,"Courier New",monospace; font-size: 14px; font-weight: bold; }
|
||||
.errorsCase { color: #F0A02F; font-family: Menlo,Monaco,Consolas,"Courier New",monospace; font-size: 14px; font-weight: bold; }
|
||||
.hiddenRow { display: none; }
|
||||
.testcase { margin-left: 1em; word-break: break-all; white-space: pre-wrap; }
|
||||
.screenshot:link { text-decoration: none;color: deeppink; }
|
||||
.screenshot:visited { text-decoration: none;color: deeppink; }
|
||||
.screenshot:hover { text-decoration: none;color: darkcyan; }
|
||||
.screenshot:active { text-decoration: none;color: deeppink; }
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body >
|
||||
<script language="javascript" type="text/javascript">
|
||||
|
||||
$(function(){
|
||||
// 修改 失败 和 错误 用例里对应按钮的颜色ClassName为动态加载 -- Gelomen
|
||||
$("button").each(function () {
|
||||
var text = $(this).text();
|
||||
if(text == "失败"){
|
||||
$(this).addClass("btn-danger")
|
||||
}else if(text == "错误") {
|
||||
$(this).addClass("btn-warning")
|
||||
}else if(text == "通过") {
|
||||
$(this).addClass("btn-success")
|
||||
}
|
||||
});
|
||||
|
||||
// 给失败和错误合集加样式 -- Gelomen
|
||||
var p_attribute = $("p.attribute");
|
||||
p_attribute.eq(4).addClass("failCollection");
|
||||
p_attribute.eq(5).addClass("errorCollection");
|
||||
|
||||
// 打开截图,放大,点击任何位置可以关闭图片
|
||||
$(".screenshot").click(function(){
|
||||
var img = $(this).attr("img");
|
||||
$('.pic_show img').attr('src', img);
|
||||
$('.pic_looper').fadeIn(200);
|
||||
$('.pic_show').fadeIn(200);
|
||||
|
||||
var browserHeight = $(window).height();
|
||||
var pic_boxHeight = $(".pic_box").height();
|
||||
var top = (browserHeight - pic_boxHeight)/2;
|
||||
$('.pic_box').css("margin-top", top + "px")
|
||||
|
||||
});
|
||||
$('.pic_looper, .pic_show').click(function(){
|
||||
$('.pic_looper').fadeOut(200);
|
||||
$('.pic_show').fadeOut(200)
|
||||
});
|
||||
|
||||
var resize_action = function(){
|
||||
// 改变窗口大小时,自动改变图表边距
|
||||
var browserWidth = $(window).width();
|
||||
var margin_left = browserWidth - 360 - 450 - 550 - 40;
|
||||
if(margin_left <= 0){
|
||||
$("#container").css("width", "100%");
|
||||
$("#container_extend").css("width", "100%");
|
||||
$("#testinfo").css("width", "100%");
|
||||
$("#container").css("margin-left", "0px");
|
||||
}else {
|
||||
$("#container").css("width", "450px");
|
||||
$("#container_extend").css("width", "550px");
|
||||
$("#testinfo").css("width", "25%");
|
||||
$("#container").css("margin-left", (margin_left - 1) + "px");
|
||||
}
|
||||
}
|
||||
resize_action();
|
||||
|
||||
$(window).resize(function(){
|
||||
// 改变窗口大小时,自动改变图片与顶部的距离
|
||||
var browserHeight = $(window).height();
|
||||
var pic_boxHeight = $(".pic_box").height();
|
||||
var top = (browserHeight - pic_boxHeight)/2;
|
||||
$('.pic_box').css("margin-top", top + "px");
|
||||
resize_action();
|
||||
});
|
||||
// 超过浏览器高度时,回到顶部按钮出现
|
||||
$(window).scroll(function(){
|
||||
var browserHeight = $(window).height();
|
||||
var top = $(window).scrollTop();
|
||||
if(top >= browserHeight){
|
||||
$("#toTop").css("display", "block")
|
||||
}else {
|
||||
$("#toTop").css("display", "none")
|
||||
}
|
||||
})
|
||||
// 增加回到顶部过程动画
|
||||
$("#toTop").click(function() {
|
||||
$("html,body").animate({"scrollTop":0}, 500)
|
||||
})
|
||||
// 增加条形图
|
||||
$('#container_extend').highcharts({
|
||||
chart: {
|
||||
type: 'bar'
|
||||
},
|
||||
credits: {
|
||||
enabled: false
|
||||
},
|
||||
navigation: {
|
||||
buttonOptions: {
|
||||
enabled: false
|
||||
}
|
||||
},
|
||||
title: {
|
||||
text: '用例集合情况'
|
||||
},
|
||||
xAxis: {
|
||||
categories: ["TestDemo", "测试用例"]
|
||||
},
|
||||
yAxis: {
|
||||
min: 0,
|
||||
title: {
|
||||
text: '用例数量'
|
||||
},
|
||||
reversedStacks: false
|
||||
},
|
||||
legend: {
|
||||
reversed: false
|
||||
},
|
||||
plotOptions: {
|
||||
series: {
|
||||
stacking: 'normal'
|
||||
}
|
||||
},
|
||||
series: [{
|
||||
name: '通过',
|
||||
color: '#64bb64',
|
||||
data: [1, 0]
|
||||
}, {
|
||||
name: '失败',
|
||||
color: '#f16d7e',
|
||||
data: [1, 0]
|
||||
}, {
|
||||
name: '错误',
|
||||
color: '#fdc68c',
|
||||
data: [3, 1]
|
||||
}]
|
||||
})
|
||||
// 增加饼状图
|
||||
$('#container').highcharts({
|
||||
chart: {
|
||||
plotBackgroundColor: null,
|
||||
plotBorderWidth: null,
|
||||
plotShadow: false,
|
||||
spacing : [0, 0, 0, 0]
|
||||
},
|
||||
credits: {
|
||||
enabled: false
|
||||
},
|
||||
navigation: {
|
||||
buttonOptions: {
|
||||
enabled: false
|
||||
}
|
||||
},
|
||||
title: {
|
||||
floating: true,
|
||||
text: '测试结果占比'
|
||||
},
|
||||
tooltip: {
|
||||
pointFormat: '<text style="font-size:10px">{series.name}: {point.percentage:.1f}%</text>'
|
||||
},
|
||||
plotOptions: {
|
||||
pie: {
|
||||
allowPointSelect: true,
|
||||
cursor: 'pointer',
|
||||
colors: ['#64bb64', '#f16d7e', '#fdc68c'],
|
||||
dataLabels: {
|
||||
enabled: true,
|
||||
format: '<b>{point.name}</b>: {point.percentage:.1f} %',
|
||||
style: {
|
||||
color: (Highcharts.theme && Highcharts.theme.contrastTextColor) || 'black'
|
||||
}
|
||||
},
|
||||
point: {
|
||||
events: {
|
||||
mouseOver: function(e) { // 鼠标滑过时动态更新标题
|
||||
chart.setTitle({
|
||||
text: e.target.name+ '\t'+ e.target.y + ' 个'
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
series: [{
|
||||
type: 'pie',
|
||||
innerSize: '80%',
|
||||
name: '比例',
|
||||
data: [
|
||||
['通过', 1], ['失败', 1], ['错误', 4]
|
||||
]
|
||||
}]
|
||||
}, function(c) {
|
||||
// 环形圆心
|
||||
var centerY = c.series[0].center[1],
|
||||
titleHeight = parseInt(c.title.styles.fontSize);
|
||||
c.setTitle({
|
||||
x:0,
|
||||
y:centerY + titleHeight/2
|
||||
});
|
||||
chart = c;
|
||||
});
|
||||
|
||||
// 查看 失败 和 错误 合集链接文字切换 -- Gelomen
|
||||
$(".showDetail").click(function () {
|
||||
if($(this).html() == "点击查看"){
|
||||
$(this).html("点击收起")
|
||||
}else {
|
||||
$(this).html("点击查看")
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
output_list = Array();
|
||||
|
||||
/*level 调整增加只显示通过用例的分类 --Findyou / 修复筛选显示bug --Gelomen
|
||||
0:Summary //all hiddenRow
|
||||
1:Failed //pt&et hiddenRow, ft none
|
||||
2:Passed //pt none, ft&et hiddenRow
|
||||
3:Errors //pt&ft hiddenRow, et none
|
||||
4:All //all none
|
||||
*/
|
||||
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 == 2 || level == 0 || level == 3) {
|
||||
tr.className = 'hiddenRow';
|
||||
}
|
||||
else {
|
||||
tr.className = '';
|
||||
// 切换筛选时只显示预览 -- Gelomen
|
||||
// 失败
|
||||
$("div[id^='div_ft']").attr("class", "collapse");
|
||||
$("div[id^='div_et']").attr("class", "collapse");
|
||||
$("div[id^='div_pt']").attr("class", "collapse");
|
||||
}
|
||||
}
|
||||
if (id.substr(0,2) == 'pt') {
|
||||
if (level == 1 || level == 0 || level == 3) {
|
||||
tr.className = 'hiddenRow';
|
||||
}
|
||||
else {
|
||||
tr.className = '';
|
||||
// 切换筛选时只显示预览 -- Gelomen
|
||||
// 通过
|
||||
$("div[id^='div_ft']").attr("class", "collapse");
|
||||
$("div[id^='div_et']").attr("class", "collapse");
|
||||
$("div[id^='div_pt']").attr("class", "collapse");
|
||||
}
|
||||
}
|
||||
if (id.substr(0,2) == 'et') {
|
||||
if (level == 1 || level == 0 || level == 2) {
|
||||
tr.className = 'hiddenRow';
|
||||
}
|
||||
else {
|
||||
tr.className = '';
|
||||
// 切换筛选时只显示预览 -- Gelomen
|
||||
// 错误
|
||||
$("div[id^='div_ft']").attr("class", "collapse");
|
||||
$("div[id^='div_et']").attr("class", "collapse");
|
||||
$("div[id^='div_pt']").attr("class", "collapse");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//加入详细切换文字变化
|
||||
detail_class=document.getElementsByClassName('detail');
|
||||
if (level == 4) {
|
||||
for (var i = 0; i < detail_class.length; i++){
|
||||
detail_class[i].innerHTML="收起"
|
||||
}
|
||||
}
|
||||
else{
|
||||
for (var i = 0; i < detail_class.length; i++){
|
||||
detail_class[i].innerHTML="详细"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showClassDetail(cid, count) {
|
||||
var id_list = Array(count);
|
||||
var toHide = 1;
|
||||
for (var i = 0; i < count; i++) {
|
||||
//ID修改.为_
|
||||
tid0 = 't' + cid.substr(1) + '_' + (i+1);
|
||||
tid = 'f' + tid0;
|
||||
tr = document.getElementById(tid);
|
||||
if (!tr) {
|
||||
tid = 'p' + tid0;
|
||||
tr = document.getElementById(tid);
|
||||
if (!tr) {
|
||||
tid = 'e' + 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];
|
||||
//修改点击无法收起的BUG,加入【详细】切换文字变化 --Findyou
|
||||
if (toHide) {
|
||||
document.getElementById(tid).className = 'hiddenRow';
|
||||
document.getElementById(cid).innerText = "详细"
|
||||
}
|
||||
else {
|
||||
document.getElementById(tid).className = '';
|
||||
document.getElementById(cid).innerText = "收起"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function html_escape(s) {
|
||||
s = s.replace(/&/g,'&');
|
||||
s = s.replace(/</g,'<');
|
||||
s = s.replace(/>/g,'>');
|
||||
return s;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class='pic_looper'></div>
|
||||
<div class='pic_show'>
|
||||
<div class='pic_box'>
|
||||
<img src=''/>
|
||||
</div>
|
||||
</div>
|
||||
<div class='header'>
|
||||
<div id="testinfo" style="max-width: 360px; width: auto; float: left;">
|
||||
<h1 style="margin: 5px 0px 10px 0px; font-family: Microsoft YaHei;">自动化测试报告</h1>
|
||||
|
||||
<p class='attribute'><strong>开始时间 : </strong> 2022-07-28 00:36:41</p>
|
||||
|
||||
<p class='attribute'><strong>合计耗时 : </strong> 00:00:02</p>
|
||||
|
||||
<p class='attribute'><strong>测试结果 : </strong> 总共 6,通过 1,失败 1,错误 4,通过率 16.67%</p>
|
||||
|
||||
<p class='attribute'><strong>失败用例 : </strong> <a class='showDetail' data-toggle='collapse' href='#failedCaseOl' style='text-decoration: none;'>点击查看</a><ol id='failedCaseOl' class='collapse' style='float: left; font-family: Menlo,Monaco,Consolas,monospace;'><li>test_case.TestDemo.test_two22</li></ol></p>
|
||||
|
||||
<p class='attribute'><strong>错误用例 : </strong> <a class='showDetail' data-toggle='collapse' href='#errorsCaseOl' style='text-decoration: none;'>点击查看</a><ol id='errorsCaseOl' class='collapse' style='float: left; font-family: Menlo,Monaco,Consolas,monospace;'><li>test_case.TestDemo.test_tre333</li><li>test_case.TestDemo.test_fou444</li><li>main.测试用例.test_demo1</li><li>test_case.TestDemo.test_0123456789ABC</li></ol></p>
|
||||
|
||||
<p class='description'>描述</p>
|
||||
</div>
|
||||
<div id="container"></div>
|
||||
<div id="container_extend"></div>
|
||||
</div>
|
||||
|
||||
|
||||
<div style="width: auto; clear: both;">
|
||||
<p id='show_detail_line'>
|
||||
<a class="btn btn-primary" href='javascript:showCase(0)'>概要 16.67%</a>
|
||||
<a class="btn btn-success" href='javascript:showCase(2)'>通过 1</a>
|
||||
<a class="btn btn-danger" href='javascript:showCase(1)'>失败 1</a>
|
||||
<a class="btn btn-warning" href='javascript:showCase(3)'>错误 4</a>
|
||||
<a class="btn btn-info" href='javascript:showCase(4)'>全部 6</a>
|
||||
</p>
|
||||
</div>
|
||||
<table id='result_table' class="table table-condensed table-bordered table-hover">
|
||||
<colgroup>
|
||||
<col align='left' style="width: 300px;"/>
|
||||
<col align='right' style="width: 285px;"/>
|
||||
<col align='right' />
|
||||
<col align='right' />
|
||||
<col align='right' />
|
||||
<col align='right' />
|
||||
<col align='right' />
|
||||
<col align='right' style="width: 120px;"/>
|
||||
</colgroup>
|
||||
<tr id='header_row' class="text-center success" style="font-weight: bold;font-size: 14px;">
|
||||
<td>测试用例</td>
|
||||
<td>说明</td>
|
||||
<td>总计</td>
|
||||
<td>通过</td>
|
||||
<td>失败</td>
|
||||
<td>错误</td>
|
||||
<td>耗时</td>
|
||||
<td>详细</td>
|
||||
</tr>
|
||||
|
||||
<tr class='errorClass warning'>
|
||||
<td>TestDemo</td>
|
||||
<td></td>
|
||||
<td class="text-center">5</td>
|
||||
<td class="text-center">1</td>
|
||||
<td class="text-center">1</td>
|
||||
<td class="text-center">3</td>
|
||||
<td class="text-center">2.091秒</td>
|
||||
<td class="text-center"><a href="javascript:showClassDetail('c1',5)" class="detail" id='c1'>查看全部</a></td>
|
||||
</tr>
|
||||
|
||||
<tr id='pt1_1' class='hiddenRow'>
|
||||
<td class='passedCase' style="vertical-align: middle"><div class='testcase'>test_one1</div></td>
|
||||
<td style="vertical-align: middle"></td>
|
||||
<td colspan='5' align='center'>
|
||||
<button id='btn_pt1_1' type="button" class="btn btn-xs" data-toggle="collapse" data-target='#div_pt1_1'>通过</button>
|
||||
<div id='div_pt1_1' class="collapse in">
|
||||
<pre style="text-align:left;font-size:12px;color:#e52000">pt1_1:
|
||||
STDOUT
|
||||
STDERR
|
||||
</pre>
|
||||
</div>
|
||||
</td>
|
||||
<td class='passedCase' style="vertical-align: middle"></td>
|
||||
</tr>
|
||||
|
||||
<tr id='ft1_2' class='none'>
|
||||
<td class='failedCase' style="vertical-align: middle"><div class='testcase'>test_two22</div></td>
|
||||
<td style="vertical-align: middle"></td>
|
||||
<td colspan='5' align='center'>
|
||||
<button id='btn_ft1_2' type="button" class="btn btn-xs" data-toggle="collapse" data-target='#div_ft1_2'>失败</button>
|
||||
<div id='div_ft1_2' class="collapse in">
|
||||
<pre style="text-align:left;font-size:12px;color:#e52000">ft1_2:
|
||||
2022-07-28 00:36:41,298 - E: 错误啦!!!
|
||||
Traceback (most recent call last):
|
||||
File "D:\Project\AutoFramework\test_case.py", line 31, in test_two22
|
||||
assert 'A' in 'Hello!', '断言失败'
|
||||
AssertionError: 断言失败
|
||||
</pre>
|
||||
</div>
|
||||
</td>
|
||||
<td class='failedCase' style="vertical-align: middle"></td>
|
||||
</tr>
|
||||
|
||||
<tr id='et1_3' class='none'>
|
||||
<td class='errorsCase' style="vertical-align: middle"><div class='testcase'>test_tre333</div></td>
|
||||
<td style="vertical-align: middle"></td>
|
||||
<td colspan='5' align='center'>
|
||||
<button id='btn_et1_3' type="button" class="btn btn-xs" data-toggle="collapse" data-target='#div_et1_3,#div_et1_3_screenshot'>错误</button>
|
||||
<div id='div_et1_3' class="collapse in">
|
||||
<pre style="text-align:left;font-size:12px;color:#e52000">et1_3:
|
||||
Traceback (most recent call last):
|
||||
File "D:\Project\AutoFramework\test_case.py", line 35, in test_tre333
|
||||
a(1)
|
||||
NameError: name 'a' is not defined
|
||||
</pre>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-center" style="vertical-align: middle">
|
||||
<div style='width:auto;height:auto;border:1px solid #b5b5b5;color:#202020font-weight:bold;text-align:center'>截图信息</div>
|
||||
<div id='div_et1_3_screenshot' style="text-align: left" class="collapse in">
|
||||
<a style="font-family:Consolas,monospace;color:#e52000;text-decoration:underline;" class="screenshot" href="javascript:void(0)" img="./01.png">01.png</a></br>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr id='et1_4' class='none'>
|
||||
<td class='errorsCase' style="vertical-align: middle"><div class='testcase'>test_fou444</div></td>
|
||||
<td style="vertical-align: middle"></td>
|
||||
<td colspan='5' align='center'>
|
||||
<button id='btn_et1_4' type="button" class="btn btn-xs" data-toggle="collapse" data-target='#div_et1_4,#div_et1_4_screenshot'>错误</button>
|
||||
<div id='div_et1_4' class="collapse in">
|
||||
<pre style="text-align:left;font-size:12px;color:#e52000">et1_4:
|
||||
Traceback (most recent call last):
|
||||
File "D:\Project\AutoFramework\test_case.py", line 43, in test_fou444
|
||||
raise Exception('Errors')
|
||||
Exception: Errors
|
||||
</pre>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-center" style="vertical-align: middle">
|
||||
<div style='width:auto;height:auto;border:1px solid #b5b5b5;color:#202020font-weight:bold;text-align:center'>截图信息</div>
|
||||
<div id='div_et1_4_screenshot' style="text-align: left" class="collapse in">
|
||||
<a style="font-family:Consolas,monospace;color:#e52000;text-decoration:underline;" class="screenshot" href="javascript:void(0)" img="./01.png">01.png</a></br><a style="font-family:Consolas,monospace;color:#e52000;text-decoration:underline;" class="screenshot" href="javascript:void(0)" img="./2022072523501942.png">2022072523501942.png</a></br><a style="font-family:Consolas,monospace;color:#e52000;text-decoration:underline;" class="screenshot" href="javascript:void(0)" img="./2022072523501235.png">2022072523501235.png</a></br>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr id='et1_5' class='none'>
|
||||
<td class='errorsCase' style="vertical-align: middle"><div class='testcase'>test_0123456789ABC</div></td>
|
||||
<td style="vertical-align: middle"></td>
|
||||
<td colspan='5' align='center'>
|
||||
<button id='btn_et1_5' type="button" class="btn btn-xs" data-toggle="collapse" data-target='#div_et1_5'>错误</button>
|
||||
<div id='div_et1_5' class="collapse in">
|
||||
<pre style="text-align:left;font-size:12px;color:#e52000">et1_5:
|
||||
Traceback (most recent call last):
|
||||
File "D:\Project\AutoFramework\venv\lib\site-packages\urllib3\connection.py", line 174, in _new_conn
|
||||
conn = connection.create_connection(
|
||||
File "D:\Project\AutoFramework\venv\lib\site-packages\urllib3\util\connection.py", line 95, in create_connection
|
||||
raise err
|
||||
File "D:\Project\AutoFramework\venv\lib\site-packages\urllib3\util\connection.py", line 85, in create_connection
|
||||
sock.connect(sa)
|
||||
ConnectionRefusedError: [WinError 10061] 由于目标计算机积极拒绝,无法连接。
|
||||
|
||||
During handling of the above exception, another exception occurred:
|
||||
|
||||
Traceback (most recent call last):
|
||||
File "D:\Project\AutoFramework\venv\lib\site-packages\urllib3\connectionpool.py", line 703, in urlopen
|
||||
httplib_response = self._make_request(
|
||||
File "D:\Project\AutoFramework\venv\lib\site-packages\urllib3\connectionpool.py", line 398, in _make_request
|
||||
conn.request(method, url, **httplib_request_kw)
|
||||
File "D:\Project\AutoFramework\venv\lib\site-packages\urllib3\connection.py", line 239, in request
|
||||
super(HTTPConnection, self).request(method, url, body=body, headers=headers)
|
||||
File "C:\Program Files\Python310\lib\http\client.py", line 1282, in request
|
||||
self._send_request(method, url, body, headers, encode_chunked)
|
||||
File "C:\Program Files\Python310\lib\http\client.py", line 1328, in _send_request
|
||||
self.endheaders(body, encode_chunked=encode_chunked)
|
||||
File "C:\Program Files\Python310\lib\http\client.py", line 1277, in endheaders
|
||||
self._send_output(message_body, encode_chunked=encode_chunked)
|
||||
File "C:\Program Files\Python310\lib\http\client.py", line 1037, in _send_output
|
||||
self.send(msg)
|
||||
File "C:\Program Files\Python310\lib\http\client.py", line 975, in send
|
||||
self.connect()
|
||||
File "D:\Project\AutoFramework\venv\lib\site-packages\urllib3\connection.py", line 205, in connect
|
||||
conn = self._new_conn()
|
||||
File "D:\Project\AutoFramework\venv\lib\site-packages\urllib3\connection.py", line 186, in _new_conn
|
||||
raise NewConnectionError(
|
||||
urllib3.exceptions.NewConnectionError: <urllib3.connection.HTTPConnection object at 0x00000272B0967280>: Failed to establish a new connection: [WinError 10061] 由于目标计算机积极拒绝,无法连接。
|
||||
|
||||
During handling of the above exception, another exception occurred:
|
||||
|
||||
Traceback (most recent call last):
|
||||
File "D:\Project\AutoFramework\venv\lib\site-packages\requests\adapters.py", line 489, in send
|
||||
resp = conn.urlopen(
|
||||
File "D:\Project\AutoFramework\venv\lib\site-packages\urllib3\connectionpool.py", line 785, in urlopen
|
||||
retries = retries.increment(
|
||||
File "D:\Project\AutoFramework\venv\lib\site-packages\urllib3\util\retry.py", line 592, in increment
|
||||
raise MaxRetryError(_pool, url, error or ResponseError(cause))
|
||||
urllib3.exceptions.MaxRetryError: HTTPConnectionPool(host='127.0.0.1', port=8888): Max retries exceeded with url: http://more-md.fanscloud.net/iplookup (Caused by ProxyError('Cannot connect to proxy.', NewConnectionError('<urllib3.connection.HTTPConnection object at 0x00000272B0967280>: Failed to establish a new connection: [WinError 10061] 由于目标计算机积极拒绝,无法连接。')))
|
||||
|
||||
During handling of the above exception, another exception occurred:
|
||||
|
||||
Traceback (most recent call last):
|
||||
File "D:\Project\AutoFramework\test_case.py", line 53, in test_0123456789ABC
|
||||
Request().http('GET',"http://more-md.fanscloud.net/iplookup", proxy="http://127.0.0.1:8888")
|
||||
File "D:\Project\AutoFramework\Base\Class\Http.py", line 75, in http
|
||||
self.__response_object__ = self.__http__.request(
|
||||
File "D:\Project\AutoFramework\venv\lib\site-packages\requests\api.py", line 59, in request
|
||||
return session.request(method=method, url=url, **kwargs)
|
||||
File "D:\Project\AutoFramework\venv\lib\site-packages\requests\sessions.py", line 587, in request
|
||||
resp = self.send(prep, **send_kwargs)
|
||||
File "D:\Project\AutoFramework\venv\lib\site-packages\requests\sessions.py", line 701, in send
|
||||
r = adapter.send(request, **kwargs)
|
||||
File "D:\Project\AutoFramework\venv\lib\site-packages\requests\adapters.py", line 559, in send
|
||||
raise ProxyError(e, request=request)
|
||||
requests.exceptions.ProxyError: HTTPConnectionPool(host='127.0.0.1', port=8888): Max retries exceeded with url: http://more-md.fanscloud.net/iplookup (Caused by ProxyError('Cannot connect to proxy.', NewConnectionError('<urllib3.connection.HTTPConnection object at 0x00000272B0967280>: Failed to establish a new connection: [WinError 10061] 由于目标计算机积极拒绝,无法连接。')))
|
||||
</pre>
|
||||
</div>
|
||||
</td>
|
||||
<td class='errorsCase' style="vertical-align: middle"></td>
|
||||
</tr>
|
||||
|
||||
<tr class='errorClass warning'>
|
||||
<td>测试用例</td>
|
||||
<td>Doc</td>
|
||||
<td class="text-center">1</td>
|
||||
<td class="text-center">0</td>
|
||||
<td class="text-center">0</td>
|
||||
<td class="text-center">1</td>
|
||||
<td class="text-center">0.000秒</td>
|
||||
<td class="text-center"><a href="javascript:showClassDetail('c2',1)" class="detail" id='c2'>查看全部</a></td>
|
||||
</tr>
|
||||
|
||||
<tr id='et2_1' class='none'>
|
||||
<td class='errorsCase' style="vertical-align: middle"><div class='testcase'>test_demo1</div></td>
|
||||
<td style="vertical-align: middle">这是一条测试用例;这是一条测试用例;这是一条测试用例;这是一条测试用例;这是一条测试用例;这是一条测试用例;这是一条测试用例;这是一条测试用例;这是一条测试用例;</td>
|
||||
<td colspan='5' align='center'>
|
||||
<button id='btn_et2_1' type="button" class="btn btn-xs" data-toggle="collapse" data-target='#div_et2_1'>错误</button>
|
||||
<div id='div_et2_1' class="collapse in">
|
||||
<pre style="text-align:left;font-size:12px;color:#e52000">et2_1:
|
||||
Traceback (most recent call last):
|
||||
File "", line 1, in foo
|
||||
NameError: name 'a' is not defined
|
||||
</pre>
|
||||
</div>
|
||||
</td>
|
||||
<td class='errorsCase' style="vertical-align: middle"></td>
|
||||
</tr>
|
||||
|
||||
<tr id='total_row' class="text-center active">
|
||||
<td colspan='2'>总计</td>
|
||||
<td>6</td>
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>4</td>
|
||||
<td>2.091秒</td>
|
||||
<td>通过:16.67%</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<div id='footer'> </div>
|
||||
<div id="toTop" style="position:fixed;right:50px; bottom:30px; width:20px; height:20px;cursor:pointer; display: none">
|
||||
<a>
|
||||
<span class="glyphicon glyphicon-eject" style = "font-size:28px;color:#b0b0b0" aria-hidden="true">
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div style='width: auto; height: auto; border: 1px solid #e3e3e3; text-align: center; color: #505050; padding: 4px 0px 4px 0px;'>
|
||||
<img src='' style='width: auto; height: auto; max-height: 40px;'>
|
||||
<a href='#' style='font-size: 14px; color: #505050; text-align: center|bottom;'></a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue