220810
This commit is contained in:
parent
6128b5979a
commit
e087722ecd
|
@ -229,11 +229,11 @@
|
|||
series: [{
|
||||
name: '通过',
|
||||
color: '#64bb64',
|
||||
data: [5]
|
||||
data: [6]
|
||||
}, {
|
||||
name: '失败',
|
||||
color: '#f16d7e',
|
||||
data: [1]
|
||||
data: [0]
|
||||
}, {
|
||||
name: '错误',
|
||||
color: '#fdc68c',
|
||||
|
@ -291,7 +291,7 @@
|
|||
innerSize: '80%',
|
||||
name: '比例',
|
||||
data: [
|
||||
['通过', 5], ['失败', 1], ['错误', 0]
|
||||
['通过', 6], ['失败', 0], ['错误', 0]
|
||||
]
|
||||
}]
|
||||
}, function(c) {
|
||||
|
@ -438,13 +438,13 @@ 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-09 22:17:02</p>
|
||||
<p class='attribute'><strong>开始时间 : </strong> 2022-08-10 18:32:08</p>
|
||||
|
||||
<p class='attribute'><strong>合计耗时 : </strong> 00:00:00</p>
|
||||
<p class='attribute'><strong>合计耗时 : </strong> 00:00:01</p>
|
||||
|
||||
<p class='attribute'><strong>测试结果 : </strong> 总共 6,通过 5,失败 1,错误 0,通过率 83.33%</p>
|
||||
<p class='attribute'><strong>测试结果 : </strong> 总共 6,通过 6,失败 0,错误 0,通过率 100.00%</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>main.测试用例.test0006_None</li></ol></p>
|
||||
<p class='attribute'><strong>失败用例 : </strong> 无</p>
|
||||
|
||||
<p class='attribute'><strong>错误用例 : </strong> 无</p>
|
||||
|
||||
|
@ -457,9 +457,9 @@ function html_escape(s) {
|
|||
|
||||
<div style="width: auto; clear: both;">
|
||||
<p id='show_detail_line'>
|
||||
<a class="btn btn-primary" href='javascript:showCase(0)'>概要 83.33%</a>
|
||||
<a class="btn btn-success" href='javascript:showCase(2)'>通过 5</a>
|
||||
<a class="btn btn-danger" href='javascript:showCase(1)'>失败 1</a>
|
||||
<a class="btn btn-primary" href='javascript:showCase(0)'>概要 100.00%</a>
|
||||
<a class="btn btn-success" href='javascript:showCase(2)'>通过 6</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)'>全部 6</a>
|
||||
</p>
|
||||
|
@ -486,14 +486,14 @@ function html_escape(s) {
|
|||
<td>详细</td>
|
||||
</tr>
|
||||
|
||||
<tr class='failClass warning'>
|
||||
<tr class='passClass warning'>
|
||||
<td>测试用例</td>
|
||||
<td></td>
|
||||
<td class="text-center">6</td>
|
||||
<td class="text-center">5</td>
|
||||
<td class="text-center">1</td>
|
||||
<td class="text-center">6</td>
|
||||
<td class="text-center">0</td>
|
||||
<td class="text-center">0.732秒</td>
|
||||
<td class="text-center">0</td>
|
||||
<td class="text-center">1.154秒</td>
|
||||
<td class="text-center"><a href="javascript:showClassDetail('c1',6)" class="detail" id='c1'>查看全部</a></td>
|
||||
</tr>
|
||||
|
||||
|
@ -513,8 +513,15 @@ function html_escape(s) {
|
|||
|
||||
<tr id='pt1_3' class='hiddenRow'>
|
||||
<td class='passedCase' style="vertical-align: middle"><div class='testcase'>test0003_None</div></td>
|
||||
<td style="vertical-align: left"></td>
|
||||
<td colspan='5' align='center'><button type="button" class="btn btn-xs">通过</button></td>
|
||||
<td style="vertical-align: middle"></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-size:12px;color:#119611">pt1_3:
|
||||
{'var8': 'Windows、Linux修改连接数限制'}
|
||||
</pre>
|
||||
</div>
|
||||
</td>
|
||||
<td class='passedCase' style="vertical-align: middle"></td>
|
||||
</tr>
|
||||
|
||||
|
@ -532,35 +539,21 @@ function html_escape(s) {
|
|||
<td class='passedCase' style="vertical-align: middle"></td>
|
||||
</tr>
|
||||
|
||||
<tr id='ft1_6' class='none'>
|
||||
<td class='failedCase' style="vertical-align: middle"><div class='testcase'>test0006_None</div></td>
|
||||
<td style="vertical-align: middle"></td>
|
||||
<td colspan='5' align='center'>
|
||||
<button id='btn_ft1_6' type="button" class="btn btn-xs" data-toggle="collapse" data-target='#div_ft1_6'>失败</button>
|
||||
<div id='div_ft1_6' class="collapse in">
|
||||
<pre style="text-align:left;font-size:12px;color:#e52000">ft1_6:
|
||||
Traceback (most recent call last):
|
||||
File "D:\Project\AutoFramework\Runner\API\DefaultRunner.py", line 507, in foo
|
||||
return self._test_(index)
|
||||
File "D:\Project\AutoFramework\Runner\API\DefaultRunner.py", line 492, in test
|
||||
self.test_unit(data=main_case)
|
||||
File "D:\Project\AutoFramework\Runner\API\DefaultRunner.py", line 460, in test_unit
|
||||
_assert(_assert_parm[0], _assert_parm[1])
|
||||
AssertionError: 'nginx' unexpectedly found in 'Server: nginx\nDate: Tue, 09 Aug 2022 14:17:03 GMT\nContent-Type: application/json\nContent-Length: 208\nLast-Modified: Thu, 04 Aug 2022 07:51:36 GMT\nConnection: keep-alive\nETag: "62eb7a88-d0"\nAccept-Ranges: bytes'
|
||||
</pre>
|
||||
</div>
|
||||
</td>
|
||||
<td class='failedCase' style="vertical-align: middle"></td>
|
||||
<tr id='pt1_6' class='hiddenRow'>
|
||||
<td class='passedCase' style="vertical-align: middle"><div class='testcase'>test0006_None</div></td>
|
||||
<td style="vertical-align: left"></td>
|
||||
<td colspan='5' align='center'><button type="button" class="btn btn-xs">通过</button></td>
|
||||
<td class='passedCase' style="vertical-align: middle"></td>
|
||||
</tr>
|
||||
|
||||
<tr id='total_row' class="text-center active">
|
||||
<td colspan='2'>总计</td>
|
||||
<td>6</td>
|
||||
<td>5</td>
|
||||
<td>1</td>
|
||||
<td>6</td>
|
||||
<td>0</td>
|
||||
<td>0.732秒</td>
|
||||
<td>通过:83.33%</td>
|
||||
<td>0</td>
|
||||
<td>1.154秒</td>
|
||||
<td>通过:100.00%</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
|
|
@ -169,7 +169,7 @@ class TestCase:
|
|||
"HTTPAssertBody",
|
||||
"HTTPAssertJson",
|
||||
"DatabaseChannel",
|
||||
"DatabaseSqlQuery",
|
||||
"DatabaseSql",
|
||||
"DatabaseExtract",
|
||||
"DatabaseAssertData",
|
||||
"DatabaseAssertCount",
|
||||
|
@ -365,104 +365,124 @@ class TestCase:
|
|||
return str(text)
|
||||
|
||||
def test_unit(self, data):
|
||||
http = self.h.where((self.h['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['HostWithScheme'] or '') + (data['HTTPUri'] or '/'), [self._g, self._l]),
|
||||
'query': self._sub_variable_auto(auto_decode(data['HTTPQuery']), [self._g, self._l]),
|
||||
'data': None,
|
||||
'json': None,
|
||||
'file': None,
|
||||
'header': {},
|
||||
'cookie': self._sub_variable_auto(
|
||||
auto_decode(data['HTTPCookie']),
|
||||
[self._g, self._l]
|
||||
),
|
||||
'auth': None,
|
||||
'timeout': 15,
|
||||
'proxy': None,
|
||||
'auto_redirect': self._match_bool(data['HTTPRedirect']),
|
||||
'ignore_cert_error': False,
|
||||
'debug': True
|
||||
}
|
||||
res_kwargs['header'].update((auto_decode(http['DefaultHeader']) or {}))
|
||||
res_kwargs['header'].update((self._sub_variable_auto(auto_decode(data['HTTPHeader']), [self._g, self._l]) or {}))
|
||||
match self._match_parm_type(data['HTTPParamType']):
|
||||
case 10:
|
||||
res_kwargs['json'] = self._sub_variable_auto(auto_decode(data['HTTPParamContent']))
|
||||
case 20:
|
||||
res_kwargs['data'] = self._sub_variable_auto(auto_decode(data['HTTPParamContent']))
|
||||
case _:
|
||||
res_kwargs['data'] = self._sub_variable_auto(data['HTTPParamContent'])
|
||||
res_kwargs['file'] = locals().setdefault('f', self._sub_variable_auto(auto_decode(
|
||||
data['HTTPParamOfFile']))) and {k: open(os.path.abspath(os.path.join(self.dirs, './%s' % v)), 'rb') for k, v in locals().get('f').items()}
|
||||
res = self.http.http(**res_kwargs)
|
||||
for var_name, var_value in {
|
||||
'_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()])}),
|
||||
'_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 {}),
|
||||
json_encode(None): None,
|
||||
json_encode(bool(0)): bool(0),
|
||||
json_encode(bool(1)): bool(1)
|
||||
}.items():
|
||||
locals().__setitem__(var_name, var_value)
|
||||
for k, v in (auto_decode(data['HTTPExtract']) or {}).items():
|
||||
d = re.findall('^([0-9A-Za-z_]+).*?', v)[0]
|
||||
self._g[str(k)] = str(eval('_' + v.replace(d, d.title(), 1)))
|
||||
for assert_item in [
|
||||
{'expect': data['HTTPAssertStatus'], 'actual': locals().get('_Status')},
|
||||
{'expect': data['HTTPAssertReason'], 'actual': locals().get('_Reason')},
|
||||
{'expect': data['HTTPAssertHeader'], 'actual': locals().get('_Header')},
|
||||
{'expect': data['HTTPAssertCookie'], 'actual': locals().get('_Cookie')},
|
||||
{'expect': data['HTTPAssertBody'], 'actual': locals().get('_Body')},
|
||||
{'expect': data['HTTPAssertJson'], 'actual': locals().get('_Json')},
|
||||
]:
|
||||
actual = assert_item['actual']
|
||||
if isinstance(actual, (int, bool, str)):
|
||||
actual = ReText(actual)
|
||||
if isinstance(actual, (tuple, list, set)):
|
||||
actual = ReList(actual)
|
||||
if isinstance(actual, (dict, )):
|
||||
actual = ReDict(actual)
|
||||
expect = self._to_string(assert_item['expect'])
|
||||
if expect:
|
||||
expect_nums = 0
|
||||
expect_flag = 0
|
||||
for line in list(filter(lambda x: x, expect.split("\n"))):
|
||||
expect_nums += 1
|
||||
for operator in [
|
||||
{'sign': ' == ', 'method': 'self.unit.assertEqual', 'reverse': 0},
|
||||
{'sign': ' != ', 'method': 'self.unit.assertNotEqual', 'reverse': 0},
|
||||
{'sign': ' >= ', 'method': 'self.unit.assertGreaterEqual', 'reverse': 0},
|
||||
{'sign': ' <= ', 'method': 'self.unit.assertLessEqual', 'reverse': 0},
|
||||
{'sign': ' =~ ', 'method': 'self.unit.assertIn', 'reverse': 1},
|
||||
{'sign': ' !~ ', 'method': 'self.unit.assertNotIn', 'reverse': 1},
|
||||
{'sign': ' > ', 'method': 'self.unit.assertGreater', 'reverse': 0},
|
||||
{'sign': ' < ', 'method': 'self.unit.assertLess', 'reverse': 0},
|
||||
{'sign': ' not in ', 'method': 'self.unit.assertNotIn', 'reverse': 0},
|
||||
{'sign': ' in ', 'method': 'self.unit.assertIn', 'reverse': 0},
|
||||
]:
|
||||
formula_args = self._parse_formula(self._sub_variable_auto(line).replace('$', 'actual'), operator['sign'])
|
||||
if formula_args:
|
||||
expect_flag += 1
|
||||
operator['reverse'] and formula_args.reverse()
|
||||
_assert = eval(operator['method'])
|
||||
_assert_parm = [eval(formula_args[0]), eval(formula_args[1])]
|
||||
for i in range(len(_assert_parm)):
|
||||
try:
|
||||
if isinstance(_assert_parm[i], ReDict) and _assert_parm[i]['_']: _assert_parm[i] = str(_assert_parm[i])
|
||||
except TypeError as e:
|
||||
pass
|
||||
_assert(_assert_parm[0], _assert_parm[1])
|
||||
break
|
||||
if 1 <= expect_flag != expect_nums:
|
||||
raise Exception('wrong assertion statement')
|
||||
if 0 == expect_flag:
|
||||
self.unit.assertEqual(str(actual), expect)
|
||||
if data['HTTPUri']:
|
||||
if not data['HTTPChannel']:
|
||||
raise Exception('channel not set')
|
||||
http = self.h.where((self.h['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['HostWithScheme'] or '') + data['HTTPUri'], [self._g, self._l]),
|
||||
'query': self._sub_variable_auto(auto_decode(data['HTTPQuery']), [self._g, self._l]),
|
||||
'data': None,
|
||||
'json': None,
|
||||
'file': None,
|
||||
'header': {},
|
||||
'cookie': self._sub_variable_auto(auto_decode(data['HTTPCookie']), [self._g, self._l]),
|
||||
'auth': None,
|
||||
'timeout': 15,
|
||||
'proxy': None,
|
||||
'auto_redirect': self._match_bool(data['HTTPRedirect']),
|
||||
'ignore_cert_error': False,
|
||||
'debug': True
|
||||
}
|
||||
res_kwargs['header'].update((auto_decode(http['DefaultHeader']) or {}))
|
||||
res_kwargs['header'].update((self._sub_variable_auto(auto_decode(data['HTTPHeader']), [self._g, self._l]) or {}))
|
||||
match self._match_parm_type(data['HTTPParamType']):
|
||||
case 10:
|
||||
res_kwargs['json'] = self._sub_variable_auto(auto_decode(data['HTTPParamContent']))
|
||||
case 20:
|
||||
res_kwargs['data'] = self._sub_variable_auto(auto_decode(data['HTTPParamContent']))
|
||||
case _:
|
||||
res_kwargs['data'] = self._sub_variable_auto(data['HTTPParamContent'])
|
||||
res_kwargs['file'] = locals().setdefault('f', self._sub_variable_auto(auto_decode(
|
||||
data['HTTPParamOfFile']))) and {k: open(os.path.abspath(os.path.join(self.dirs, './%s' % v)), 'rb') for k, v in locals().get('f').items()}
|
||||
res = self.http.http(**res_kwargs)
|
||||
for var_name, var_value in {
|
||||
'_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()])}),
|
||||
'_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 {}),
|
||||
json_encode(None): None,
|
||||
json_encode(bool(0)): bool(0),
|
||||
json_encode(bool(1)): bool(1)
|
||||
}.items():
|
||||
locals().__setitem__(var_name, var_value)
|
||||
for k, v in (auto_decode(data['HTTPExtract']) or {}).items():
|
||||
d = re.findall('^([0-9A-Za-z_]+).*?', v)[0]
|
||||
self._g[str(k)] = str(eval('_' + v.replace(d, d.title(), 1)))
|
||||
for assert_item in [
|
||||
{'expect': data['HTTPAssertStatus'], 'actual': locals().get('_Status')},
|
||||
{'expect': data['HTTPAssertReason'], 'actual': locals().get('_Reason')},
|
||||
{'expect': data['HTTPAssertHeader'], 'actual': locals().get('_Header')},
|
||||
{'expect': data['HTTPAssertCookie'], 'actual': locals().get('_Cookie')},
|
||||
{'expect': data['HTTPAssertBody'], 'actual': locals().get('_Body')},
|
||||
{'expect': data['HTTPAssertJson'], 'actual': locals().get('_Json')},
|
||||
]:
|
||||
actual = assert_item['actual']
|
||||
if isinstance(actual, (int, bool, str)):
|
||||
actual = ReText(actual)
|
||||
if isinstance(actual, (tuple, list, set)):
|
||||
actual = ReList(actual)
|
||||
if isinstance(actual, (dict, )):
|
||||
actual = ReDict(actual)
|
||||
expect = self._to_string(assert_item['expect'])
|
||||
if expect:
|
||||
expect_nums = 0
|
||||
expect_flag = 0
|
||||
for line in list(filter(lambda x: x, expect.split("\n"))):
|
||||
expect_nums += 1
|
||||
for operator in [
|
||||
{'sign': ' == ', 'method': 'self.unit.assertEqual', 'reverse': 0},
|
||||
{'sign': ' != ', 'method': 'self.unit.assertNotEqual', 'reverse': 0},
|
||||
{'sign': ' >= ', 'method': 'self.unit.assertGreaterEqual', 'reverse': 0},
|
||||
{'sign': ' <= ', 'method': 'self.unit.assertLessEqual', 'reverse': 0},
|
||||
{'sign': ' =~ ', 'method': 'self.unit.assertIn', 'reverse': 1},
|
||||
{'sign': ' !~ ', 'method': 'self.unit.assertNotIn', 'reverse': 1},
|
||||
{'sign': ' > ', 'method': 'self.unit.assertGreater', 'reverse': 0},
|
||||
{'sign': ' < ', 'method': 'self.unit.assertLess', 'reverse': 0},
|
||||
{'sign': ' not in ', 'method': 'self.unit.assertNotIn', 'reverse': 0},
|
||||
{'sign': ' in ', 'method': 'self.unit.assertIn', 'reverse': 0},
|
||||
]:
|
||||
formula_args = self._parse_formula(self._sub_variable_auto(line).replace('$', 'actual'), operator['sign'])
|
||||
if formula_args:
|
||||
expect_flag += 1
|
||||
operator['reverse'] and formula_args.reverse()
|
||||
_assert = eval(operator['method'])
|
||||
_assert_parm = [eval(formula_args[0]), eval(formula_args[1])]
|
||||
for i in range(len(_assert_parm)):
|
||||
try:
|
||||
if isinstance(_assert_parm[i], ReDict) and _assert_parm[i]['_']: _assert_parm[i] = str(_assert_parm[i])
|
||||
except TypeError as e:
|
||||
pass
|
||||
_assert(_assert_parm[0], _assert_parm[1])
|
||||
break
|
||||
if 1 <= expect_flag != expect_nums:
|
||||
raise Exception('wrong assertion statement')
|
||||
if 0 == expect_flag:
|
||||
self.unit.assertEqual(str(actual), expect)
|
||||
if data['DatabaseSql']:
|
||||
if not data['DatabaseChannel']:
|
||||
raise Exception('channel not set')
|
||||
base = self.b.where((self.b['Name'] == data['DatabaseChannel']), inplace=False).dropna(how='all').reset_index(drop=True, inplace=False).loc[0].to_dict()
|
||||
# print(base)
|
||||
conn = MySQL().connect(
|
||||
host=base['Host'], port=int(base['Port']),
|
||||
user=base['User'], password=base['Password'], database=base['Database'], charset=base['Charset'], cursor='Dict'
|
||||
)
|
||||
conn.execute(data['DatabaseSql'])
|
||||
# print(conn.fetchall())
|
||||
# print(conn.count())
|
||||
for var_name, var_value in {
|
||||
'_Data': ReList(conn.fetchall() or [])
|
||||
}.items():
|
||||
locals().__setitem__(var_name, var_value)
|
||||
for k, v in (auto_decode(data['DatabaseExtract']) or {}).items():
|
||||
d = re.findall('^([0-9A-Za-z_]+).*?', v)[0]
|
||||
self._g[str(k)] = str(eval('_' + v.replace(d, d.title(), 1)))
|
||||
|
||||
print(self._g)
|
||||
|
||||
|
||||
# expect = self._to_string(data['HTTPAssertStatus'])
|
||||
|
|
Loading…
Reference in New Issue