At Aug 12 A.
This commit is contained in:
parent
e087722ecd
commit
15b21f25a5
|
@ -229,7 +229,7 @@
|
||||||
series: [{
|
series: [{
|
||||||
name: '通过',
|
name: '通过',
|
||||||
color: '#64bb64',
|
color: '#64bb64',
|
||||||
data: [6]
|
data: [5]
|
||||||
}, {
|
}, {
|
||||||
name: '失败',
|
name: '失败',
|
||||||
color: '#f16d7e',
|
color: '#f16d7e',
|
||||||
|
@ -237,7 +237,7 @@
|
||||||
}, {
|
}, {
|
||||||
name: '错误',
|
name: '错误',
|
||||||
color: '#fdc68c',
|
color: '#fdc68c',
|
||||||
data: [0]
|
data: [1]
|
||||||
}]
|
}]
|
||||||
})
|
})
|
||||||
// 增加饼状图
|
// 增加饼状图
|
||||||
|
@ -291,7 +291,7 @@
|
||||||
innerSize: '80%',
|
innerSize: '80%',
|
||||||
name: '比例',
|
name: '比例',
|
||||||
data: [
|
data: [
|
||||||
['通过', 6], ['失败', 0], ['错误', 0]
|
['通过', 5], ['失败', 0], ['错误', 1]
|
||||||
]
|
]
|
||||||
}]
|
}]
|
||||||
}, function(c) {
|
}, function(c) {
|
||||||
|
@ -438,15 +438,15 @@ function html_escape(s) {
|
||||||
<div id="testinfo" style="max-width: 360px; width: auto; float: left;">
|
<div id="testinfo" style="max-width: 360px; width: auto; float: left;">
|
||||||
<h1 style="margin: 5px 0px 10px 0px; font-family: Microsoft YaHei;">测试报告</h1>
|
<h1 style="margin: 5px 0px 10px 0px; font-family: Microsoft YaHei;">测试报告</h1>
|
||||||
|
|
||||||
<p class='attribute'><strong>开始时间 : </strong> 2022-08-10 18:32:08</p>
|
<p class='attribute'><strong>开始时间 : </strong> 2022-08-12 11:13:49</p>
|
||||||
|
|
||||||
<p class='attribute'><strong>合计耗时 : </strong> 00:00:01</p>
|
<p class='attribute'><strong>合计耗时 : </strong> 00:00:00</p>
|
||||||
|
|
||||||
<p class='attribute'><strong>测试结果 : </strong> 总共 6,通过 6,失败 0,错误 0,通过率 100.00%</p>
|
<p class='attribute'><strong>测试结果 : </strong> 总共 6,通过 5,失败 0,错误 1,通过率 83.33%</p>
|
||||||
|
|
||||||
<p class='attribute'><strong>失败用例 : </strong> 无</p>
|
<p class='attribute'><strong>失败用例 : </strong> 无</p>
|
||||||
|
|
||||||
<p class='attribute'><strong>错误用例 : </strong> 无</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>main.测试用例.test0003_None</li></ol></p>
|
||||||
|
|
||||||
<p class='description'></p>
|
<p class='description'></p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -457,10 +457,10 @@ function html_escape(s) {
|
||||||
|
|
||||||
<div style="width: auto; clear: both;">
|
<div style="width: auto; clear: both;">
|
||||||
<p id='show_detail_line'>
|
<p id='show_detail_line'>
|
||||||
<a class="btn btn-primary" href='javascript:showCase(0)'>概要 100.00%</a>
|
<a class="btn btn-primary" href='javascript:showCase(0)'>概要 83.33%</a>
|
||||||
<a class="btn btn-success" href='javascript:showCase(2)'>通过 6</a>
|
<a class="btn btn-success" href='javascript:showCase(2)'>通过 5</a>
|
||||||
<a class="btn btn-danger" href='javascript:showCase(1)'>失败 0</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-warning" href='javascript:showCase(3)'>错误 1</a>
|
||||||
<a class="btn btn-info" href='javascript:showCase(4)'>全部 6</a>
|
<a class="btn btn-info" href='javascript:showCase(4)'>全部 6</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -486,74 +486,121 @@ function html_escape(s) {
|
||||||
<td>详细</td>
|
<td>详细</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr class='passClass warning'>
|
<tr class='errorClass warning'>
|
||||||
<td>测试用例</td>
|
<td>测试用例</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td class="text-center">6</td>
|
<td class="text-center">6</td>
|
||||||
<td class="text-center">6</td>
|
<td class="text-center">5</td>
|
||||||
<td class="text-center">0</td>
|
<td class="text-center">0</td>
|
||||||
<td class="text-center">0</td>
|
<td class="text-center">1</td>
|
||||||
<td class="text-center">1.154秒</td>
|
<td class="text-center">0.720秒</td>
|
||||||
<td class="text-center"><a href="javascript:showClassDetail('c1',6)" class="detail" id='c1'>查看全部</a></td>
|
<td class="text-center"><a href="javascript:showClassDetail('c1',6)" class="detail" id='c1'>查看全部</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr id='pt1_1' class='hiddenRow'>
|
<tr id='pt1_1' class='hiddenRow'>
|
||||||
<td class='passedCase' style="vertical-align: middle"><div class='testcase'>test0001_None</div></td>
|
<td class='passedCase' style="vertical-align: middle"><div class='testcase'>test0001_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='pt1_2' class='hiddenRow'>
|
|
||||||
<td class='passedCase' style="vertical-align: middle"><div class='testcase'>test0002_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='pt1_3' class='hiddenRow'>
|
|
||||||
<td class='passedCase' style="vertical-align: middle"><div class='testcase'>test0003_None</div></td>
|
|
||||||
<td style="vertical-align: middle"></td>
|
<td style="vertical-align: middle"></td>
|
||||||
<td colspan='5' align='center'>
|
<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>
|
<button id='btn_pt1_1' type="button" class="btn btn-xs" data-toggle="collapse" data-target='#div_pt1_1'>通过</button>
|
||||||
<div id='div_pt1_3' class="collapse in">
|
<div id='div_pt1_1' class="collapse in">
|
||||||
<pre style="text-align:left;font-size:12px;color:#119611">pt1_3:
|
<pre style="text-align:left;font-size:12px;color:#119611">pt1_1:
|
||||||
{'var8': 'Windows、Linux修改连接数限制'}
|
{}
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class='passedCase' style="vertical-align: middle"></td>
|
<td class='passedCase' style="vertical-align: middle"></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
<tr id='pt1_2' class='hiddenRow'>
|
||||||
|
<td class='passedCase' style="vertical-align: middle"><div class='testcase'>test0002_None</div></td>
|
||||||
|
<td style="vertical-align: middle"></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-size:12px;color:#119611">pt1_2:
|
||||||
|
{}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class='passedCase' style="vertical-align: middle"></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr id='et1_3' class='none'>
|
||||||
|
<td class='errorsCase' style="vertical-align: middle"><div class='testcase'>test0003_None</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'>错误</button>
|
||||||
|
<div id='div_et1_3' class="collapse in">
|
||||||
|
<pre style="text-align:left;font-size:12px;color:#e54f00">et1_3:
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "D:\Project\AutoFramework\Runner\API\DefaultRunner.py", line 579, in foo
|
||||||
|
return self._test_(index)
|
||||||
|
File "D:\Project\AutoFramework\Runner\API\DefaultRunner.py", line 564, in test
|
||||||
|
self.test_unit(data=main_case)
|
||||||
|
File "D:\Project\AutoFramework\Runner\API\DefaultRunner.py", line 500, in test_unit
|
||||||
|
self._assert([
|
||||||
|
File "D:\Project\AutoFramework\Runner\API\DefaultRunner.py", line 437, in _assert
|
||||||
|
assert_parm = [eval(form[0]), eval(form[1])]
|
||||||
|
File "<string>", line 1, in <module>
|
||||||
|
File "C:\Program Files\Python310\lib\_sitebuiltins.py", line 26, in __call__
|
||||||
|
raise SystemExit(code)
|
||||||
|
SystemExit: None
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class='errorsCase' style="vertical-align: middle"></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
<tr id='pt1_4' class='hiddenRow'>
|
<tr id='pt1_4' class='hiddenRow'>
|
||||||
<td class='passedCase' style="vertical-align: middle"><div class='testcase'>test0004_None</div></td>
|
<td class='passedCase' style="vertical-align: middle"><div class='testcase'>test0004_None</div></td>
|
||||||
<td style="vertical-align: left"></td>
|
<td style="vertical-align: middle"></td>
|
||||||
<td colspan='5' align='center'><button type="button" class="btn btn-xs">通过</button></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-size:12px;color:#119611">pt1_4:
|
||||||
|
{}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
<td class='passedCase' style="vertical-align: middle"></td>
|
<td class='passedCase' style="vertical-align: middle"></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr id='pt1_5' class='hiddenRow'>
|
<tr id='pt1_5' class='hiddenRow'>
|
||||||
<td class='passedCase' style="vertical-align: middle"><div class='testcase'>test0005_None</div></td>
|
<td class='passedCase' style="vertical-align: middle"><div class='testcase'>test0005_None</div></td>
|
||||||
<td style="vertical-align: left"></td>
|
<td style="vertical-align: middle"></td>
|
||||||
<td colspan='5' align='center'><button type="button" class="btn btn-xs">通过</button></td>
|
<td colspan='5' align='center'>
|
||||||
|
<button id='btn_pt1_5' type="button" class="btn btn-xs" data-toggle="collapse" data-target='#div_pt1_5'>通过</button>
|
||||||
|
<div id='div_pt1_5' class="collapse in">
|
||||||
|
<pre style="text-align:left;font-size:12px;color:#119611">pt1_5:
|
||||||
|
{'var2': 'nginx'}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
<td class='passedCase' style="vertical-align: middle"></td>
|
<td class='passedCase' style="vertical-align: middle"></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr id='pt1_6' class='hiddenRow'>
|
<tr id='pt1_6' class='hiddenRow'>
|
||||||
<td class='passedCase' style="vertical-align: middle"><div class='testcase'>test0006_None</div></td>
|
<td class='passedCase' style="vertical-align: middle"><div class='testcase'>test0006_None</div></td>
|
||||||
<td style="vertical-align: left"></td>
|
<td style="vertical-align: middle"></td>
|
||||||
<td colspan='5' align='center'><button type="button" class="btn btn-xs">通过</button></td>
|
<td colspan='5' align='center'>
|
||||||
|
<button id='btn_pt1_6' type="button" class="btn btn-xs" data-toggle="collapse" data-target='#div_pt1_6'>通过</button>
|
||||||
|
<div id='div_pt1_6' class="collapse in">
|
||||||
|
<pre style="text-align:left;font-size:12px;color:#119611">pt1_6:
|
||||||
|
{'var2': 'nginx', 'var3': '101', 'var4': '阿凡\n凡凡', 'var5': '{"name": "小红", "age": 22}'}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
<td class='passedCase' style="vertical-align: middle"></td>
|
<td class='passedCase' style="vertical-align: middle"></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr id='total_row' class="text-center active">
|
<tr id='total_row' class="text-center active">
|
||||||
<td colspan='2'>总计</td>
|
<td colspan='2'>总计</td>
|
||||||
<td>6</td>
|
<td>6</td>
|
||||||
<td>6</td>
|
<td>5</td>
|
||||||
<td>0</td>
|
<td>0</td>
|
||||||
<td>0</td>
|
<td>1</td>
|
||||||
<td>1.154秒</td>
|
<td>0.720秒</td>
|
||||||
<td>通过:100.00%</td>
|
<td>通过:83.33%</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import sys
|
|
||||||
import unittest
|
import unittest
|
||||||
from typing import Any, Text, Dict, List
|
from typing import Any, Text, Dict, List
|
||||||
from Business.Class.HTMLTestRunner import HTMLTestRunner
|
from Business.Class.HTMLTestRunner import HTMLTestRunner
|
||||||
|
@ -33,7 +32,7 @@ class ReList(list):
|
||||||
if isinstance(item, (int, bool)):
|
if isinstance(item, (int, bool)):
|
||||||
try:
|
try:
|
||||||
r = super().__getitem__(item)
|
r = super().__getitem__(item)
|
||||||
if isinstance(r, (list, tuple, set)):
|
if isinstance(r, (list, tuple, set)):
|
||||||
return __class__(r)
|
return __class__(r)
|
||||||
elif isinstance(r, (dict,)):
|
elif isinstance(r, (dict,)):
|
||||||
return ReDict(r)
|
return ReDict(r)
|
||||||
|
@ -61,7 +60,7 @@ class ReDict(dict):
|
||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
if item in self:
|
if item in self:
|
||||||
r = super().__getitem__(item)
|
r = super().__getitem__(item)
|
||||||
if isinstance(r, (dict,)):
|
if isinstance(r, (dict,)):
|
||||||
return __class__(r)
|
return __class__(r)
|
||||||
elif isinstance(r, (list, tuple, set)):
|
elif isinstance(r, (list, tuple, set)):
|
||||||
return ReList(r)
|
return ReList(r)
|
||||||
|
@ -87,10 +86,21 @@ class ReDict(dict):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
class CustomAssert:
|
||||||
|
@staticmethod
|
||||||
|
def assertPreWith(string: str, sub: str):
|
||||||
|
if not string.startswith(sub):
|
||||||
|
raise AssertionError('%s does not starts with %s' % (string, sub))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def assertSufWith(string: str, sub: str):
|
||||||
|
if not string.endswith(sub):
|
||||||
|
raise AssertionError('%s does not ends with %s' % (string, sub))
|
||||||
|
|
||||||
|
|
||||||
class TestCase:
|
class TestCase:
|
||||||
_g = {}
|
_g = {}
|
||||||
_l = {}
|
_l = {}
|
||||||
unit = unittest.TestCase()
|
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
@ -104,19 +114,21 @@ class TestCase:
|
||||||
tabs = {
|
tabs = {
|
||||||
"HTTPConf": {
|
"HTTPConf": {
|
||||||
"fixed": {},
|
"fixed": {},
|
||||||
"views": "A4:C*",
|
"views": "A4:F*",
|
||||||
"field": [
|
"field": [
|
||||||
"Name",
|
"Name",
|
||||||
"HostWithScheme",
|
"Scheme",
|
||||||
"DefaultHeader"
|
"Host",
|
||||||
|
"DefaultHeader",
|
||||||
|
"Timeout",
|
||||||
|
"Session"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"DataBase": {
|
"DataBase": {
|
||||||
"fixed": {},
|
"fixed": {},
|
||||||
"views": "E4:L*",
|
"views": "H4:N*",
|
||||||
"field": [
|
"field": [
|
||||||
"Name",
|
"Name",
|
||||||
"Type",
|
|
||||||
"Host",
|
"Host",
|
||||||
"Port",
|
"Port",
|
||||||
"User",
|
"User",
|
||||||
|
@ -137,10 +149,7 @@ class TestCase:
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"TestCase": {
|
"TestCase": {
|
||||||
"fixed": {
|
"fixed": {},
|
||||||
"ItemName": "B3",
|
|
||||||
"SessMode": "E3"
|
|
||||||
},
|
|
||||||
"views": "A7:AH*",
|
"views": "A7:AH*",
|
||||||
"field": [
|
"field": [
|
||||||
"Flag",
|
"Flag",
|
||||||
|
@ -168,11 +177,11 @@ class TestCase:
|
||||||
"HTTPAssertCookie",
|
"HTTPAssertCookie",
|
||||||
"HTTPAssertBody",
|
"HTTPAssertBody",
|
||||||
"HTTPAssertJson",
|
"HTTPAssertJson",
|
||||||
"DatabaseChannel",
|
"BaseChannel",
|
||||||
"DatabaseSql",
|
"BaseSql",
|
||||||
"DatabaseExtract",
|
"BaseExtract",
|
||||||
"DatabaseAssertData",
|
"BaseAssertData",
|
||||||
"DatabaseAssertCount",
|
"BaseAssertRows",
|
||||||
"DataSet",
|
"DataSet",
|
||||||
"Author",
|
"Author",
|
||||||
"TestTime",
|
"TestTime",
|
||||||
|
@ -208,21 +217,33 @@ class TestCase:
|
||||||
else:
|
else:
|
||||||
init.exit()
|
init.exit()
|
||||||
self.case = testcase
|
self.case = testcase
|
||||||
self.http = Request
|
|
||||||
self.dirs = os.path.dirname(workbook)
|
self.dirs = os.path.dirname(workbook)
|
||||||
|
self.request = Request()
|
||||||
|
self.session = Session()
|
||||||
|
|
||||||
self.i = data['TestCase']['fixed']['ItemName']
|
|
||||||
self.m = data['TestCase']['fixed']['SessMode']
|
|
||||||
self.h = data['HTTPConf']['views']
|
self.h = data['HTTPConf']['views']
|
||||||
self.b = data['DataBase']['views']
|
self.b = data['DataBase']['views']
|
||||||
self.d = data['TestData']['views']
|
self.d = data['TestData']['views']
|
||||||
self.c = data['TestCase']['views']
|
self.c = data['TestCase']['views']
|
||||||
|
|
||||||
self._set_levels(testlves)
|
self._set_levels(testlves)
|
||||||
self._set_request_mode(self.m)
|
|
||||||
|
|
||||||
def _set_request_mode(self, value=None):
|
self.assert_unit = unittest.TestCase()
|
||||||
self.http = [Request, Session][self._match_mode(value)]()
|
self.assert_cust = CustomAssert()
|
||||||
|
self.assert_list = [
|
||||||
|
{'sign': ' == ', 'method': self.assert_unit.assertEqual, 'reverse': 0, 'cast': 0},
|
||||||
|
{'sign': ' != ', 'method': self.assert_unit.assertNotEqual, 'reverse': 0, 'cast': 0},
|
||||||
|
{'sign': ' >= ', 'method': self.assert_unit.assertGreaterEqual, 'reverse': 0, 'cast': float},
|
||||||
|
{'sign': ' <= ', 'method': self.assert_unit.assertLessEqual, 'reverse': 0, 'cast': float},
|
||||||
|
{'sign': ' =~ ', 'method': self.assert_unit.assertIn, 'reverse': 1, 'cast': str},
|
||||||
|
{'sign': ' !~ ', 'method': self.assert_unit.assertNotIn, 'reverse': 1, 'cast': str},
|
||||||
|
{'sign': ' > ', 'method': self.assert_unit.assertGreater, 'reverse': 0, 'cast': float},
|
||||||
|
{'sign': ' < ', 'method': self.assert_unit.assertLess, 'reverse': 0, 'cast': float},
|
||||||
|
{'sign': ' not in ', 'method': self.assert_unit.assertNotIn, 'reverse': 0, 'cast': 0},
|
||||||
|
{'sign': ' in ', 'method': self.assert_unit.assertIn, 'reverse': 0, 'cast': 0},
|
||||||
|
{'sign': ' *= ', 'method': self.assert_cust.assertPreWith, 'reverse': 0, 'cast': str},
|
||||||
|
{'sign': ' =* ', 'method': self.assert_cust.assertSufWith, 'reverse': 0, 'cast': str},
|
||||||
|
]
|
||||||
|
|
||||||
def _set_levels(self, level_list=None):
|
def _set_levels(self, level_list=None):
|
||||||
if isinstance(level_list, (list, tuple, str)):
|
if isinstance(level_list, (list, tuple, str)):
|
||||||
|
@ -238,24 +259,10 @@ class TestCase:
|
||||||
case _:
|
case _:
|
||||||
return 50
|
return 50
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _match_parm_type(value=None):
|
|
||||||
match value:
|
|
||||||
case 'Json':
|
|
||||||
return 10
|
|
||||||
case 'Form':
|
|
||||||
return 20
|
|
||||||
case _:
|
|
||||||
return 50
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _match_bool(value=None):
|
def _match_bool(value=None):
|
||||||
return value in ['是', '开启', '打开', 'True', 'true', 'TRUE', True, 'Yes', 'yes', 'YES', 'Y', 'y', '1', 1, 1.0]
|
return value in ['是', '开启', '打开', 'True', 'true', 'TRUE', True, 'Yes', 'yes', 'YES', 'Y', 'y', '1', 1, 1.0]
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _match_mode(value=None):
|
|
||||||
return value in ['会话模式', 'Session', 'session']
|
|
||||||
|
|
||||||
def _match_leve_run(self, value=None):
|
def _match_leve_run(self, value=None):
|
||||||
if self.leve_list is None:
|
if self.leve_list is None:
|
||||||
return True
|
return True
|
||||||
|
@ -317,7 +324,7 @@ class TestCase:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _sub_variable(text='', vars_dict=None):
|
def _sub_variable(text, vars_dict):
|
||||||
if not isinstance(text, str):
|
if not isinstance(text, str):
|
||||||
return text
|
return text
|
||||||
for variable_name in re.findall('\${(.*?)}', text):
|
for variable_name in re.findall('\${(.*?)}', text):
|
||||||
|
@ -328,7 +335,8 @@ class TestCase:
|
||||||
text = text.replace('${%s}' % variable_name, str(value))
|
text = text.replace('${%s}' % variable_name, str(value))
|
||||||
return text
|
return text
|
||||||
|
|
||||||
def _sub_variable_auto(self, data=None, vars_dict=None):
|
def _sub_variable_auto(self, data):
|
||||||
|
vars_dict = [self._g, self._l]
|
||||||
if isinstance(vars_dict, list):
|
if isinstance(vars_dict, list):
|
||||||
d = {}
|
d = {}
|
||||||
for v in vars_dict:
|
for v in vars_dict:
|
||||||
|
@ -351,139 +359,184 @@ class TestCase:
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _to_string(text):
|
def _to_string(value):
|
||||||
import math
|
import math
|
||||||
if text is None:
|
if value is None:
|
||||||
return ''
|
return ''
|
||||||
try:
|
try:
|
||||||
if math.isnan(text):
|
if math.isnan(value):
|
||||||
return ''
|
return ''
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
if isinstance(text, float) and math.modf(text)[0] == 0:
|
if isinstance(value, float) and math.modf(value)[0] == 0:
|
||||||
return str(int(text))
|
return str(int(value))
|
||||||
return str(text)
|
return str(value)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _to_number(value):
|
||||||
|
import math
|
||||||
|
if not value:
|
||||||
|
return 0
|
||||||
|
if value is True:
|
||||||
|
return 1
|
||||||
|
try:
|
||||||
|
if math.isnan(value):
|
||||||
|
return 0
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return int(float(value))
|
||||||
|
|
||||||
|
def _extract_variable(self, extract, vars_dict: dict, domain: str | list | dict):
|
||||||
|
if not extract: return None
|
||||||
|
if not isinstance(extract, (list, dict)):
|
||||||
|
extract = auto_decode(extract)
|
||||||
|
if isinstance(domain, str):
|
||||||
|
match domain:
|
||||||
|
case 'locals':
|
||||||
|
domain = self._l
|
||||||
|
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
|
||||||
|
for k, v in (extract or {}).items():
|
||||||
|
d = re.findall('^([0-9A-Za-z_]+).*?', v)[0]
|
||||||
|
locals().__setitem__('r', vars_dict[d.lower()])
|
||||||
|
domain[str(k)] = str(eval(v.replace(d, 'r', 1)))
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _assert(self, assert_items, assert_lists):
|
||||||
|
for assert_item in assert_items:
|
||||||
|
expect = self._to_string(assert_item['expect'])
|
||||||
|
if not expect: continue
|
||||||
|
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)
|
||||||
|
assert_rows = 0
|
||||||
|
assert_real = 0
|
||||||
|
for name, value in {
|
||||||
|
json_encode(None): None,
|
||||||
|
json_encode(bool(0)): bool(0),
|
||||||
|
json_encode(bool(1)): bool(1)
|
||||||
|
}.items():
|
||||||
|
locals().__setitem__(name, value)
|
||||||
|
for line in list(filter(lambda x: x, expect.split("\n"))):
|
||||||
|
assert_rows += 1
|
||||||
|
for oper in assert_lists:
|
||||||
|
form = self._parse_formula(re.compile('(\$)(?!{).*?').sub('actual', line), oper['sign'])
|
||||||
|
if not form:
|
||||||
|
continue
|
||||||
|
for i in range(len(form)):
|
||||||
|
form[i] = self._sub_variable_auto(form[i]).replace("\n", "\\n")
|
||||||
|
assert_real += 1
|
||||||
|
oper['reverse'] and form.reverse()
|
||||||
|
assert_meth = oper['method']
|
||||||
|
assert_parm = [eval(form[0]), eval(form[1])]
|
||||||
|
for i in range(len(assert_parm)):
|
||||||
|
try:
|
||||||
|
if assert_parm[i]['_']: assert_parm[i] = str(assert_parm[i])
|
||||||
|
except TypeError as e:
|
||||||
|
pass
|
||||||
|
cast = oper['cast']
|
||||||
|
if cast: assert_parm[i] = cast(assert_parm[i])
|
||||||
|
assert_meth(assert_parm[0], assert_parm[1])
|
||||||
|
break
|
||||||
|
if 1 <= assert_real != assert_rows:
|
||||||
|
raise Exception('wrong assertion statement')
|
||||||
|
if 0 == assert_real:
|
||||||
|
expect = self._sub_variable_auto(expect)
|
||||||
|
actual = str(actual)
|
||||||
|
assert actual == expect, '%s != %s' % (actual, expect)
|
||||||
|
|
||||||
def test_unit(self, data):
|
def test_unit(self, data):
|
||||||
if data['HTTPUri']:
|
if data['HTTPUri']:
|
||||||
if not data['HTTPChannel']:
|
if not data['HTTPChannel']:
|
||||||
raise Exception('channel not set')
|
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()
|
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 = {
|
res_kwargs = {
|
||||||
'method': data['HTTPMethod'],
|
'method': data['HTTPMethod'],
|
||||||
'url': self._sub_variable_auto((http['HostWithScheme'] or '') + data['HTTPUri'], [self._g, self._l]),
|
'url': self._sub_variable_auto((http['Scheme'] or 'http').lower() + '://' + (http['Host'] or '') + data['HTTPUri']),
|
||||||
'query': self._sub_variable_auto(auto_decode(data['HTTPQuery']), [self._g, self._l]),
|
'query': self._sub_variable_auto(auto_decode(data['HTTPQuery'])),
|
||||||
'data': None,
|
'data': None,
|
||||||
'json': None,
|
'json': None,
|
||||||
'file': None,
|
'file': None,
|
||||||
'header': {},
|
'header': {},
|
||||||
'cookie': self._sub_variable_auto(auto_decode(data['HTTPCookie']), [self._g, self._l]),
|
'cookie': self._sub_variable_auto(auto_decode(data['HTTPCookie'])),
|
||||||
'auth': None,
|
'auth': None,
|
||||||
'timeout': 15,
|
'timeout': self._to_number(http['Timeout']) or 15,
|
||||||
'proxy': None,
|
'proxy': None,
|
||||||
'auto_redirect': self._match_bool(data['HTTPRedirect']),
|
'auto_redirect': self._match_bool(data['HTTPRedirect']),
|
||||||
'ignore_cert_error': False,
|
'ignore_cert_error': False,
|
||||||
'debug': True
|
'debug': True
|
||||||
}
|
}
|
||||||
res_kwargs['header'].update((auto_decode(http['DefaultHeader']) or {}))
|
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 {}))
|
res_kwargs['header'].update((self._sub_variable_auto(auto_decode(data['HTTPHeader'])) or {}))
|
||||||
match self._match_parm_type(data['HTTPParamType']):
|
match str(data['HTTPParamType']).strip().title():
|
||||||
case 10:
|
case 'Json':
|
||||||
res_kwargs['json'] = self._sub_variable_auto(auto_decode(data['HTTPParamContent']))
|
res_kwargs['json'] = self._sub_variable_auto(auto_decode(data['HTTPParamContent']))
|
||||||
case 20:
|
case 'Form':
|
||||||
res_kwargs['data'] = self._sub_variable_auto(auto_decode(data['HTTPParamContent']))
|
res_kwargs['data'] = self._sub_variable_auto(auto_decode(data['HTTPParamContent']))
|
||||||
case _:
|
case _:
|
||||||
res_kwargs['data'] = self._sub_variable_auto(data['HTTPParamContent'])
|
res_kwargs['data'] = self._sub_variable_auto(data['HTTPParamContent'])
|
||||||
res_kwargs['file'] = locals().setdefault('f', self._sub_variable_auto(auto_decode(
|
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()}
|
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)
|
res = [self.request, self.session][self._match_bool(http['Session'])].http(**res_kwargs)
|
||||||
for var_name, var_value in {
|
# 创建变量
|
||||||
'_Status': ReText(res['status'] or ''),
|
hvar = {
|
||||||
'_Reason': ReText(res['reason'] or ''),
|
'Status': ReText(res['status'] or ''),
|
||||||
'_Header': ReDict(res['header'] or {}).update({'_': "\n".join([k + ': ' + (v or '') for k, v in dict(res['header'] or {}).items()])}),
|
'Reason': ReText(res['reason'] or ''),
|
||||||
'_Cookie': ReDict(res['cookie'] or {}).update({'_': "; ".join([k + '=' + (v or '') for k, v in dict(res['cookie'] or {}).items()])}),
|
'Header': ReDict(res['header'] or {}).update({'_': "\n".join([k + ': ' + (v or '') for k, v in dict(res['header'] or {}).items()])}),
|
||||||
'_Body': ReText(res['text'] or ''),
|
'Cookie': ReDict(res['cookie'] or {}).update({'_': "; ".join([k + '=' + (v or '') for k, v in dict(res['cookie'] or {}).items()])}),
|
||||||
'_Json': ReDict(res['json'] or {}),
|
'Body': ReText(res['text'] or ''),
|
||||||
json_encode(None): None,
|
'Json': ReDict(res['json'] or {}),
|
||||||
json_encode(bool(0)): bool(0),
|
}
|
||||||
json_encode(bool(1)): bool(1)
|
# 提取变量
|
||||||
}.items():
|
self._extract_variable(extract=data['HTTPExtract'], vars_dict=hvar, domain='global')
|
||||||
locals().__setitem__(var_name, var_value)
|
# 开始断言
|
||||||
for k, v in (auto_decode(data['HTTPExtract']) or {}).items():
|
self._assert([
|
||||||
d = re.findall('^([0-9A-Za-z_]+).*?', v)[0]
|
{'expect': data['HTTPAssertStatus'], 'actual': hvar['Status']},
|
||||||
self._g[str(k)] = str(eval('_' + v.replace(d, d.title(), 1)))
|
{'expect': data['HTTPAssertReason'], 'actual': hvar['Reason']},
|
||||||
for assert_item in [
|
{'expect': data['HTTPAssertHeader'], 'actual': hvar['Header']},
|
||||||
{'expect': data['HTTPAssertStatus'], 'actual': locals().get('_Status')},
|
{'expect': data['HTTPAssertCookie'], 'actual': hvar['Cookie']},
|
||||||
{'expect': data['HTTPAssertReason'], 'actual': locals().get('_Reason')},
|
{'expect': data['HTTPAssertBody'], 'actual': hvar['Body']},
|
||||||
{'expect': data['HTTPAssertHeader'], 'actual': locals().get('_Header')},
|
{'expect': data['HTTPAssertJson'], 'actual': hvar['Json']},
|
||||||
{'expect': data['HTTPAssertCookie'], 'actual': locals().get('_Cookie')},
|
], self.assert_list)
|
||||||
{'expect': data['HTTPAssertBody'], 'actual': locals().get('_Body')},
|
if data['BaseSql']:
|
||||||
{'expect': data['HTTPAssertJson'], 'actual': locals().get('_Json')},
|
if not data['BaseChannel']:
|
||||||
]:
|
|
||||||
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')
|
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()
|
base = self.b.where((self.b['Name'] == data['BaseChannel']), inplace=False).dropna(how='all').reset_index(drop=True, inplace=False).loc[0].to_dict()
|
||||||
# print(base)
|
# 创建请求
|
||||||
conn = MySQL().connect(
|
conn = MySQL().connect(
|
||||||
host=base['Host'], port=int(base['Port']),
|
host=base['Host'], port=int(base['Port']),
|
||||||
user=base['User'], password=base['Password'], database=base['Database'], charset=base['Charset'], cursor='Dict'
|
user=base['User'], password=base['Password'], database=base['Database'], charset=base['Charset'], cursor='Dict'
|
||||||
)
|
)
|
||||||
conn.execute(data['DatabaseSql'])
|
conn.execute(data['BaseSql'])
|
||||||
# print(conn.fetchall())
|
# 创建变量
|
||||||
# print(conn.count())
|
bvar = {
|
||||||
for var_name, var_value in {
|
'Data': ReList(conn.fetchall() or []),
|
||||||
'_Data': ReList(conn.fetchall() or [])
|
'Rows': conn.count() or 0
|
||||||
}.items():
|
}
|
||||||
locals().__setitem__(var_name, var_value)
|
# 提取变量
|
||||||
for k, v in (auto_decode(data['DatabaseExtract']) or {}).items():
|
self._extract_variable(extract=data['BaseExtract'], vars_dict=bvar, domain='global')
|
||||||
d = re.findall('^([0-9A-Za-z_]+).*?', v)[0]
|
# for var_name, var_value in {
|
||||||
self._g[str(k)] = str(eval('_' + v.replace(d, d.title(), 1)))
|
# '_Data': ReList(conn.fetchall() or []),
|
||||||
|
# '_Rows': conn.count() or 0
|
||||||
print(self._g)
|
# }.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)))
|
||||||
|
# 开始断言
|
||||||
|
self._assert([
|
||||||
|
{'expect': data['BaseAssertData'], 'actual': bvar['Data']},
|
||||||
|
{'expect': data['BaseAssertRows'], 'actual': bvar['Rows']},
|
||||||
|
], self.assert_list)
|
||||||
|
|
||||||
|
print(self._g)
|
||||||
|
|
||||||
# expect = self._to_string(data['HTTPAssertStatus'])
|
# expect = self._to_string(data['HTTPAssertStatus'])
|
||||||
# if expect:
|
# if expect:
|
||||||
|
|
12
main4.py
12
main4.py
|
@ -1,9 +1,5 @@
|
||||||
import unittest
|
import unittest
|
||||||
# ut = unittest.TestCase()
|
|
||||||
# ut.assertEqual('1', '1')
|
unit = unittest.TestCase(
|
||||||
# # ut.assertIn('1234', '123')
|
)
|
||||||
# ut.assertLessEqual('4','3')
|
unit.assertEqual("阿凡\n凡凡", '123')
|
||||||
# ut.assert
|
|
||||||
l = [1, 2]
|
|
||||||
print(l.reverse())
|
|
||||||
print(l)
|
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
def assertPreWith(string: str, sub: str):
|
||||||
|
if not string.startswith(sub):
|
||||||
|
raise AssertionError('%s does not starts with %s' % (string, sub))
|
||||||
|
|
||||||
|
|
||||||
|
def assertSufWith(string: str, sub: str):
|
||||||
|
if not string.endswith(sub):
|
||||||
|
raise AssertionError('%s does not ends with %s' % (string, sub))
|
||||||
|
|
||||||
|
assertSufWith('admin 123456 ...', '...')
|
||||||
|
assertPreWith('admin 123456 ...', 'admin 1')
|
Loading…
Reference in New Issue