220801
This commit is contained in:
parent
35873d1707
commit
45f55e1d54
|
@ -175,7 +175,7 @@ class Template_mixin(object):
|
|||
# 网页模板开始
|
||||
# 网页模板,变量列表 title, generator, styles, header, report, footer
|
||||
HTML_TMPL = r"""<!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">
|
||||
<html lang="zh-CN" xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>%(title)s</title>
|
||||
<meta name="generator" content="%(generator)s"/>
|
||||
|
@ -721,7 +721,7 @@ function html_escape(s) {
|
|||
<td colspan='5' align='center'>
|
||||
<button id='btn_%(tid)s' type="button" class="btn btn-xs" data-toggle="collapse" data-target='#div_%(tid)s,#div_%(tid)s_screenshot'>%(status)s</button>
|
||||
<div id='div_%(tid)s' class="collapse in">
|
||||
<pre style="text-align:left;font-size:12px;color:#e52000">%(script)s</pre>
|
||||
<pre style="text-align:left;font-size:12px;color:%(pre_color)s">%(script)s</pre>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-center" style="vertical-align: middle">
|
||||
|
@ -741,7 +741,7 @@ function html_escape(s) {
|
|||
<td colspan='5' align='center'>
|
||||
<button id='btn_%(tid)s' type="button" class="btn btn-xs" data-toggle="collapse" data-target='#div_%(tid)s'>%(status)s</button>
|
||||
<div id='div_%(tid)s' class="collapse in">
|
||||
<pre style="text-align:left;font-size:12px;color:#e52000">%(script)s</pre>
|
||||
<pre style="text-align:left;font-size:12px;color:%(pre_color)s">%(script)s</pre>
|
||||
</div>
|
||||
</td>
|
||||
<td class='%(style)s' style="vertical-align: middle"></td>
|
||||
|
@ -1264,12 +1264,16 @@ class HTMLTestRunner(Template_mixin):
|
|||
match n:
|
||||
case 0:
|
||||
tid_flag = 'p'
|
||||
pre_clor = '#282828'
|
||||
case 1:
|
||||
tid_flag = 'f'
|
||||
pre_clor = '#e52000'
|
||||
case 2:
|
||||
tid_flag = 'e'
|
||||
pre_clor = '#e52000'
|
||||
case _:
|
||||
tid_flag = 'u'
|
||||
pre_clor = '#808080'
|
||||
tid = tid_flag + 't%s_%s' % (cid + 1, tid + 1)
|
||||
name = t.id().split('.')[-1]
|
||||
docs = t.shortDescription() or ""
|
||||
|
@ -1307,6 +1311,7 @@ class HTMLTestRunner(Template_mixin):
|
|||
docs=docs,
|
||||
script=script,
|
||||
status=self.STATUS[n],
|
||||
pre_color=pre_clor
|
||||
)
|
||||
else:
|
||||
# 包含截图信息
|
||||
|
@ -1327,6 +1332,7 @@ class HTMLTestRunner(Template_mixin):
|
|||
docs=docs,
|
||||
script=script,
|
||||
status=self.STATUS[n],
|
||||
pre_color=pre_clor,
|
||||
screenshot=screenshot
|
||||
)
|
||||
return row
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<!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">
|
||||
<html lang="zh-CN" xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>测试报告</title>
|
||||
<meta name="generator" content="HTMLTestRunner"/>
|
||||
|
@ -438,9 +438,9 @@ 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-07-30 01:01:38</p>
|
||||
<p class='attribute'><strong>开始时间 : </strong> 2022-08-01 01:43:42</p>
|
||||
|
||||
<p class='attribute'><strong>合计耗时 : </strong> 00:00:00</p>
|
||||
<p class='attribute'><strong>合计耗时 : </strong> 00:00:01</p>
|
||||
|
||||
<p class='attribute'><strong>测试结果 : </strong> 总共 3,通过 1,失败 0,错误 2,通过率 33.33%</p>
|
||||
|
||||
|
@ -493,7 +493,7 @@ function html_escape(s) {
|
|||
<td class="text-center">1</td>
|
||||
<td class="text-center">0</td>
|
||||
<td class="text-center">2</td>
|
||||
<td class="text-center">0.101秒</td>
|
||||
<td class="text-center">1.258秒</td>
|
||||
<td class="text-center"><a href="javascript:showClassDetail('c1',3)" class="detail" id='c1'>查看全部</a></td>
|
||||
</tr>
|
||||
|
||||
|
@ -503,9 +503,9 @@ function html_escape(s) {
|
|||
<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:
|
||||
2022-07-30 01:01:38,956 - D: 正在执行:正常登录
|
||||
2022-07-30 01:01:39,053 - D:
|
||||
<pre style="text-align:left;font-size:12px;color:#282828">pt1_1:
|
||||
2022-08-01 01:43:42,869 - D: 正在执行:正常登录
|
||||
2022-08-01 01:43:44,092 - D:
|
||||
[->]
|
||||
POST /filebox.php?op=home HTTP/1.1
|
||||
Host: www.fanscloud.net
|
||||
|
@ -520,12 +520,12 @@ user=&pass=1234ABCDabcd&submitButtonName=%E7%99%BB%E5%BD%95
|
|||
[<-]
|
||||
HTTP/1.1 200 OK
|
||||
Server: nginx
|
||||
Date: Fri, 29 Jul 2022 17:01:38 GMT
|
||||
Date: Sun, 31 Jul 2022 17:43:44 GMT
|
||||
Content-Type: text/html; charset=utf-8
|
||||
Transfer-Encoding: chunked
|
||||
Connection: keep-alive
|
||||
Vary: Accept-Encoding
|
||||
Set-Cookie: PHPSESSID=8lr8duhbbqtch8t3iu3jq8gsn3; path=/, user=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0, pass=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0
|
||||
Set-Cookie: PHPSESSID=b9lvik70qp9ejqt0gtguv2evn4; path=/, user=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0, pass=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0
|
||||
Expires: Thu, 19 Nov 1981 08:52:00 GMT
|
||||
Cache-Control: no-store, no-cache, must-revalidate
|
||||
Pragma: no-cache
|
||||
|
@ -553,7 +553,7 @@ Content-Encoding: gzip
|
|||
<button id='btn_et1_2' type="button" class="btn btn-xs" data-toggle="collapse" data-target='#div_et1_2'>错误</button>
|
||||
<div id='div_et1_2' class="collapse in">
|
||||
<pre style="text-align:left;font-size:12px;color:#e52000">et1_2:
|
||||
2022-07-30 01:01:39,053 - D: 正在执行:None
|
||||
2022-08-01 01:43:44,094 - D: 正在执行:None
|
||||
Traceback (most recent call last):
|
||||
File "D:\Project\AutoFramework\venv\lib\site-packages\pandas\core\indexes\base.py", line 3621, in get_loc
|
||||
return self._engine.get_loc(casted_key)
|
||||
|
@ -566,11 +566,11 @@ KeyError: 0
|
|||
The above exception was the direct cause of the following exception:
|
||||
|
||||
Traceback (most recent call last):
|
||||
File "D:\Project\AutoFramework\Runner\API\DefaultRunner.py", line 171, in foo
|
||||
File "D:\Project\AutoFramework\Runner\API\DefaultRunner.py", line 223, in foo
|
||||
def foo(self, index=i): return self._test_(index)
|
||||
File "D:\Project\AutoFramework\Runner\API\DefaultRunner.py", line 159, in test
|
||||
File "D:\Project\AutoFramework\Runner\API\DefaultRunner.py", line 211, in test
|
||||
self.test_unit(data=main_case)
|
||||
File "D:\Project\AutoFramework\Runner\API\DefaultRunner.py", line 116, in test_unit
|
||||
File "D:\Project\AutoFramework\Runner\API\DefaultRunner.py", line 179, in test_unit
|
||||
HTTPCh = self.h.where((self.h['Env'] == self.envs) & (self.h['Name'] == data['HTTPCh']), inplace=False).dropna(how='all').loc[0].to_dict()
|
||||
File "D:\Project\AutoFramework\venv\lib\site-packages\pandas\core\indexing.py", line 967, in __getitem__
|
||||
return self._getitem_axis(maybe_callable, axis=axis)
|
||||
|
@ -596,7 +596,7 @@ KeyError: 0
|
|||
<button id='btn_et1_3' type="button" class="btn btn-xs" data-toggle="collapse" data-target='#div_et1_3'>错误</button>
|
||||
<div id='div_et1_3' class="collapse in">
|
||||
<pre style="text-align:left;font-size:12px;color:#e52000">et1_3:
|
||||
2022-07-30 01:01:39,058 - D: 正在执行:None
|
||||
2022-08-01 01:43:44,120 - D: 正在执行:None
|
||||
Traceback (most recent call last):
|
||||
File "D:\Project\AutoFramework\venv\lib\site-packages\pandas\core\indexes\base.py", line 3621, in get_loc
|
||||
return self._engine.get_loc(casted_key)
|
||||
|
@ -609,11 +609,11 @@ KeyError: 0
|
|||
The above exception was the direct cause of the following exception:
|
||||
|
||||
Traceback (most recent call last):
|
||||
File "D:\Project\AutoFramework\Runner\API\DefaultRunner.py", line 171, in foo
|
||||
File "D:\Project\AutoFramework\Runner\API\DefaultRunner.py", line 223, in foo
|
||||
def foo(self, index=i): return self._test_(index)
|
||||
File "D:\Project\AutoFramework\Runner\API\DefaultRunner.py", line 159, in test
|
||||
File "D:\Project\AutoFramework\Runner\API\DefaultRunner.py", line 211, in test
|
||||
self.test_unit(data=main_case)
|
||||
File "D:\Project\AutoFramework\Runner\API\DefaultRunner.py", line 116, in test_unit
|
||||
File "D:\Project\AutoFramework\Runner\API\DefaultRunner.py", line 179, in test_unit
|
||||
HTTPCh = self.h.where((self.h['Env'] == self.envs) & (self.h['Name'] == data['HTTPCh']), inplace=False).dropna(how='all').loc[0].to_dict()
|
||||
File "D:\Project\AutoFramework\venv\lib\site-packages\pandas\core\indexing.py", line 967, in __getitem__
|
||||
return self._getitem_axis(maybe_callable, axis=axis)
|
||||
|
@ -638,7 +638,7 @@ KeyError: 0
|
|||
<td>1</td>
|
||||
<td>0</td>
|
||||
<td>2</td>
|
||||
<td>0.101秒</td>
|
||||
<td>1.258秒</td>
|
||||
<td>通过:33.33%</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
|
@ -8,42 +8,90 @@ from Base.Class.Logger import *
|
|||
log = Logger(name='test', level='DEBUG')
|
||||
|
||||
class TestCase:
|
||||
def __init__(self, workbook, data='数据配置', case='测试用例', envs='测试环境', level_list=None):
|
||||
_g = {}
|
||||
_l = {}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
workbook,
|
||||
envs,
|
||||
level_list: list = None,
|
||||
workbook_config: dict = None,
|
||||
testcase: str = None,
|
||||
testdata: str = None,
|
||||
database: str = None,
|
||||
httpconf: str = None
|
||||
):
|
||||
if workbook_config is None: workbook_config = {}
|
||||
tabs = self._merge_dict(
|
||||
{
|
||||
'HTTPConf': {
|
||||
'sheet': httpconf
|
||||
},
|
||||
'DataBase': {
|
||||
'sheet': database
|
||||
},
|
||||
'TestData': {
|
||||
'sheet': testdata
|
||||
},
|
||||
'TestCase': {
|
||||
'sheet': testcase
|
||||
}
|
||||
}
|
||||
, workbook_config)
|
||||
# tabs = {
|
||||
# 'HTTPConf': {
|
||||
# 'sheet': '数据配置'
|
||||
# },
|
||||
# 'DataBase': {
|
||||
# 'sheet': '数据配置'
|
||||
# },
|
||||
# 'TestData': {
|
||||
# 'sheet': '数据配置'
|
||||
# },
|
||||
# 'TestCase': {
|
||||
# 'sheet': '测试用例'
|
||||
# }
|
||||
# }
|
||||
import os
|
||||
from pandas.core.frame import DataFrame
|
||||
self._g = {}
|
||||
self._l = {}
|
||||
self.case = case
|
||||
self.envs = envs
|
||||
self.http = Request
|
||||
init = Excel().open(workbook, read_only=True)
|
||||
init_data = auto_decode(init.select(data).cellGet(0, 0))
|
||||
init_case = auto_decode(init.select(case).cellGet(0, 0))
|
||||
self.cell_list = {
|
||||
'item':
|
||||
auto_decode(init.select(case).cellGet(cell=init_case['fixeds']['item'])),
|
||||
'mode':
|
||||
auto_decode(init.select(case).cellGet(cell=init_case['fixeds']['mode']))
|
||||
}
|
||||
self.view_list = {
|
||||
'http':
|
||||
DataFrame(read_view_dict(filename=workbook, sheet=data, area=init_data['tables']['http']['views'], fields=init_data['tables']['http']['field'], auto_truncate=True)),
|
||||
'base':
|
||||
DataFrame(read_view_dict(filename=workbook, sheet=data, area=init_data['tables']['base']['views'], fields=init_data['tables']['base']['field'], auto_truncate=True)),
|
||||
'data':
|
||||
DataFrame(read_view_dict(filename=workbook, sheet=data, area=init_data['tables']['data']['views'], fields=init_data['tables']['data']['field'], auto_truncate=True)),
|
||||
'case':
|
||||
DataFrame(read_view_dict(filename=workbook, sheet=case, area=init_case['tables']['case']['views'], fields=init_case['tables']['case']['field'], auto_truncate=True))
|
||||
}
|
||||
self.i = self.cell_list['item']
|
||||
self.m = self.cell_list['mode']
|
||||
self.h = self.view_list['http']
|
||||
self.b = self.view_list['base']
|
||||
self.d = self.view_list['data']
|
||||
self.c = self.view_list['case']
|
||||
init.exit()
|
||||
file = os.path.splitext(workbook)[0] + '.json'
|
||||
conf = self._merge_dict((os.path.exists(file) and auto_decode(open(file, 'r', encoding='utf-8').read())) or {}, tabs)
|
||||
# print(json_encode(conf, indent=4, unicode=False))
|
||||
# exit()
|
||||
data = {}
|
||||
for k, v in conf.items():
|
||||
sheet_name = ('sheet' in v and v['sheet'] or v['default_sheet'])
|
||||
init.select(sheet_name)
|
||||
data[k] = {}
|
||||
if 'fixed' in v.keys():
|
||||
data[k]['fixed'] = {}
|
||||
for key, value in v['fixed'].items():
|
||||
data[k]['fixed'][key] = init.cellGet(cell=value)
|
||||
if 'views' in v.keys() and 'field' in v.keys():
|
||||
data[k]['views'] = DataFrame(read_view_dict(
|
||||
filename=workbook, sheet=sheet_name, area=v['views'], fields=v['field'], auto_truncate=True))
|
||||
else:
|
||||
init.exit()
|
||||
# print(json_encode(data['DataBase'], indent=4, unicode=False))
|
||||
# exit()
|
||||
|
||||
self.envs = envs
|
||||
self.case = testcase
|
||||
self.http = Request
|
||||
self.dirs = os.path.dirname(workbook)
|
||||
|
||||
self.i = data['TestCase']['fixed']['ItemName']
|
||||
self.m = data['TestCase']['fixed']['SessMode']
|
||||
self.h = data['HTTPConf']['views']
|
||||
self.b = data['DataBase']['views']
|
||||
self.d = data['TestData']['views']
|
||||
self.c = data['TestCase']['views']
|
||||
|
||||
self._setLevels(level_list)
|
||||
self._setRequestMode(self.m)
|
||||
self.dirs = os.path.dirname(workbook)
|
||||
|
||||
|
||||
def _setRequestMode(self, value=None):
|
||||
self.http = [Request, Session][value in ['会话模式', 'Session', 'session']]()
|
||||
|
@ -78,6 +126,19 @@ class TestCase:
|
|||
return True
|
||||
return value in self.leve_list
|
||||
|
||||
def _merge_dict(self, dict_ori, dict_add):
|
||||
if isinstance(dict_ori, dict) and isinstance(dict_add, dict):
|
||||
for k, v in dict_ori.items():
|
||||
if k in dict_add.keys():
|
||||
if isinstance(v, dict):
|
||||
dict_ori[k] = self._merge_dict(dict_ori[k], dict_add[k])
|
||||
else:
|
||||
dict_ori[k] = dict_add[k]
|
||||
for k, v in dict_add.items():
|
||||
if k not in dict_ori.keys():
|
||||
dict_ori[k] = dict_add[k]
|
||||
return dict_ori
|
||||
|
||||
@staticmethod
|
||||
def _sub_variable(text='', vars_dict=None):
|
||||
if not isinstance(text, str):
|
||||
|
@ -112,43 +173,34 @@ class TestCase:
|
|||
return data
|
||||
|
||||
def test_unit(self, data):
|
||||
# 开始测试
|
||||
log.d('正在执行:%s' % data['CaseTitle'])
|
||||
# 请求构造
|
||||
HTTPCh = self.h.where((self.h['Env'] == self.envs) & (self.h['Name'] == data['HTTPCh']), inplace=False).dropna(how='all').loc[0].to_dict()
|
||||
res_kwargs = {
|
||||
'debug': True,
|
||||
'method': data['HTTPMethod'],
|
||||
'url':
|
||||
self._sub_variable_auto(
|
||||
(HTTPCh['HostWithScheme'] or '') + (data['HTTPUri'] or '/'),
|
||||
[self._g, self._l]
|
||||
),
|
||||
'query':
|
||||
self._sub_variable_auto(auto_decode(data['HTTPQuery']),
|
||||
[self._g, self._l]),
|
||||
'header':
|
||||
self._sub_variable_auto(auto_decode(data['HTTPHeaders']),
|
||||
[self._g, self._l]),
|
||||
'cookie':
|
||||
self._sub_variable_auto(auto_decode(data['HTTPCookies']),
|
||||
[self._g, self._l]),
|
||||
'auto_redirect':
|
||||
data['HTTPRedirect'] in ['是', 'True', 'true']
|
||||
resKwArgs = {
|
||||
'debug': True,
|
||||
'method': data['HTTPMethod'],
|
||||
'url': self._sub_variable_auto((HTTPCh['HostWithScheme'] or '') + (data['HTTPUri'] or '/'), [self._g, self._l]),
|
||||
'query': self._sub_variable_auto(auto_decode(data['HTTPQuery']), [self._g, self._l]),
|
||||
'header': self._sub_variable_auto(auto_decode(data['HTTPHeaders']), [self._g, self._l]),
|
||||
'cookie': self._sub_variable_auto(auto_decode(data['HTTPCookies']), [self._g, self._l]),
|
||||
'auto_redirect': data['HTTPRedirect'] in ['是', 'True', 'true']
|
||||
}
|
||||
HTTPParamType = self._matchParmType(data['HTTPParamType'])
|
||||
match HTTPParamType:
|
||||
match self._matchParmType(data['HTTPParamType']):
|
||||
case 10:
|
||||
res_kwargs['data_json'] = self._sub_variable_auto(auto_decode(data['HTTPParamContent']))
|
||||
resKwArgs['data_json'] = self._sub_variable_auto(auto_decode(data['HTTPParamContent']))
|
||||
case 20:
|
||||
res_kwargs['data'] = self._sub_variable_auto(auto_decode(data['HTTPParamContent']))
|
||||
resKwArgs['data'] = self._sub_variable_auto(auto_decode(data['HTTPParamContent']))
|
||||
case _:
|
||||
res_kwargs['data'] = self._sub_variable_auto(data['HTTPParamContent'])
|
||||
resKwArgs['data'] = self._sub_variable_auto(data['HTTPParamContent'])
|
||||
HTTPParamOfFile = self._sub_variable_auto(auto_decode(data['HTTPParamOfFile']))
|
||||
if isinstance(HTTPParamOfFile, dict):
|
||||
for k, v in HTTPParamOfFile:
|
||||
HTTPParamOfFile[k] = open(os.path.abspath(os.path.join(self.dirs, './%s' % v)), 'rb')
|
||||
res_kwargs['data_file'] = HTTPParamOfFile
|
||||
resKwArgs['data_file'] = {k: open(os.path.abspath(os.path.join(self.dirs, './%s' % v)), 'rb') for k, v in HTTPParamOfFile.items()}
|
||||
# for k, v in HTTPParamOfFile:
|
||||
# HTTPParamOfFile[k] = open(os.path.abspath(os.path.join(self.dirs, './%s' % v)), 'rb')
|
||||
# resKwArgs['data_file'] = HTTPParamOfFile
|
||||
|
||||
res = self.http.http(**res_kwargs)
|
||||
res = self.http.http(**resKwArgs)
|
||||
log.d('\n%s' % (res['brief'] or ''))
|
||||
# print(res)
|
||||
# print(HTTPCh)
|
||||
|
@ -178,10 +230,9 @@ if __name__ == '__main__':
|
|||
test_suite = unittest.TestSuite()
|
||||
test_suite.addTest(unittest.makeSuite(testCaseClass=TestCase(
|
||||
workbook='D:/Desktop/接口自动化测试用例.xlsx',
|
||||
data='数据配置',
|
||||
case='测试用例',
|
||||
envs='测试环境',
|
||||
level_list=['P0']
|
||||
level_list=['P0'],
|
||||
testcase='测试用例'
|
||||
).main(), prefix='test'))
|
||||
HTMLTestRunner(verbosity=5, report=os.path.abspath(os.path.join(os.path.dirname(__file__), './1.html'))).run(
|
||||
test_suite)
|
||||
|
|
Loading…
Reference in New Issue