From 1e5e4c9e553f6bc1778f1a9eb71ac26e81a7a0d1 Mon Sep 17 00:00:00 2001 From: boafantasy Date: Wed, 26 Jul 2017 17:09:09 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E5=B0=86=E6=B5=8B=E8=AF=95=E7=9A=84?= =?UTF-8?q?=E8=BE=93=E5=87=BA=E7=94=B1=E5=B1=85=E4=B8=AD=E6=94=B9=E4=B8=BA?= =?UTF-8?q?=E5=B1=85=E5=B7=A6,=E5=8F=A6=E5=A4=96=E5=9C=A8=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E7=9A=84=E6=97=B6=E5=80=99=E5=AE=9E=E6=97=B6=E8=BE=93?= =?UTF-8?q?=E5=87=BA=E6=AF=8F=E4=B8=80=E6=9D=A1=E7=94=A8=E4=BE=8B=E6=88=90?= =?UTF-8?q?=E5=8A=9F=E5=92=8C=E5=A4=B1=E8=B4=A5=E8=80=8C=E4=B8=8D=E6=98=AF?= =?UTF-8?q?=E6=9C=80=E5=90=8E=E6=89=8D=E8=BE=93=E5=87=BAE\F\.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- python3x/HTMLTestReportCN.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/python3x/HTMLTestReportCN.py b/python3x/HTMLTestReportCN.py index 6b20537..a3b52c9 100644 --- a/python3x/HTMLTestReportCN.py +++ b/python3x/HTMLTestReportCN.py @@ -412,7 +412,7 @@ class Template_mixin(object):
-
+    
     %(script)s
     
@@ -473,6 +473,10 @@ def __init__(self, verbosity=1): def startTest(self, test): + stream = sys.stderr + stdout_content = " Testing: " + str(test) + stream.write(stdout_content) + stream.flush() TestResult.startTest(self, test) # just one buffer for both stdout and stderr self.outputBuffer = io.StringIO() From 3b190982bc36d0d0df1bbd295a11e3b5af5e2306 Mon Sep 17 00:00:00 2001 From: boafantasy Date: Wed, 26 Jul 2017 17:12:21 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=B8=80=E5=A4=84?= =?UTF-8?q?=E7=BC=A9=E8=BF=9B=E7=9A=84=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- python3x/HTMLTestReportCN.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python3x/HTMLTestReportCN.py b/python3x/HTMLTestReportCN.py index a3b52c9..d79e2a3 100644 --- a/python3x/HTMLTestReportCN.py +++ b/python3x/HTMLTestReportCN.py @@ -473,7 +473,7 @@ def __init__(self, verbosity=1): def startTest(self, test): - stream = sys.stderr + stream = sys.stderr stdout_content = " Testing: " + str(test) stream.write(stdout_content) stream.flush() From 35a8941f607d7259f9d4f0fdb29f4fbe03406a32 Mon Sep 17 00:00:00 2001 From: boafantasy Date: Mon, 13 Nov 2017 03:11:09 -0600 Subject: [PATCH 3/4] Update HTMLTestReportCN.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 每个用例加入耗时,并计算总耗时 测试用例结果从居中改为居左 --- python3x/HTMLTestReportCN.py | 76 +++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 28 deletions(-) diff --git a/python3x/HTMLTestReportCN.py b/python3x/HTMLTestReportCN.py index d79e2a3..5571ba2 100644 --- a/python3x/HTMLTestReportCN.py +++ b/python3x/HTMLTestReportCN.py @@ -185,9 +185,9 @@ class Template_mixin(object): 2: '错误', } - DEFAULT_TITLE = '单元测试报告' + DEFAULT_TITLE = '测试报告' DEFAULT_DESCRIPTION = '' - DEFAULT_TESTER='最棒QA' + DEFAULT_TESTER='QA' # ------------------------------------------------------------------------ # HTML Template @@ -356,8 +356,9 @@ class Template_mixin(object): REPORT_TMPL = """

概要{ %(passrate)s } -失败{ %(fail)s } 通过{ %(Pass)s } +失败{ %(fail)s } +错误{ %(error)s } 所有{ %(count)s }

@@ -375,6 +376,7 @@ class Template_mixin(object): + %(test_list)s @@ -384,6 +386,7 @@ class Template_mixin(object): +
通过 失败 错误耗时 详细
%(Pass)s %(fail)s %(error)s%(time_usage)s 通过率:%(passrate)s
@@ -396,6 +399,7 @@ class Template_mixin(object): %(Pass)s %(fail)s %(error)s + %(time_usage)s 详细 """ # variables: (style, desc, count, Pass, fail, error, cid) @@ -474,9 +478,10 @@ def __init__(self, verbosity=1): def startTest(self, test): stream = sys.stderr - stdout_content = " Testing: " + str(test) - stream.write(stdout_content) - stream.flush() + # stdout_content = " Testing: " + str(test) + # stream.write(stdout_content) + # stream.flush() + # stream.write("\n") TestResult.startTest(self, test) # just one buffer for both stdout and stderr self.outputBuffer = io.StringIO() @@ -486,13 +491,14 @@ def startTest(self, test): self.stderr0 = sys.stderr sys.stdout = stdout_redirector sys.stderr = stderr_redirector - + self.test_start_time = round(time.time(), 2) def complete_output(self): """ Disconnect output redirection and return buffer. Safe to call multiple times. """ + self.test_end_time = round(time.time(), 2) if self.stdout0: sys.stdout = self.stdout0 sys.stderr = self.stderr0 @@ -512,45 +518,51 @@ def addSuccess(self, test): self.success_count += 1 TestResult.addSuccess(self, test) output = self.complete_output() - self.result.append((0, test, output, '')) + use_time = round(self.test_end_time - self.test_start_time, 2) + self.result.append((0, test, output, '', use_time)) if self.verbosity > 1: - sys.stderr.write('ok ') + sys.stderr.write(' S ') sys.stderr.write(str(test)) sys.stderr.write('\n') else: - sys.stderr.write('.') + sys.stderr.write(' S ') + sys.stderr.write('\n') def addError(self, test, err): self.error_count += 1 TestResult.addError(self, test, err) _, _exc_str = self.errors[-1] output = self.complete_output() - self.result.append((2, test, output, _exc_str)) + use_time = round(self.test_end_time - self.test_start_time, 2) + self.result.append((2, test, output, _exc_str, use_time)) if self.verbosity > 1: - sys.stderr.write('E ') + sys.stderr.write(' E ') sys.stderr.write(str(test)) sys.stderr.write('\n') else: - sys.stderr.write('E') + sys.stderr.write(' E ') + sys.stderr.write('\n') def addFailure(self, test, err): self.failure_count += 1 TestResult.addFailure(self, test, err) _, _exc_str = self.failures[-1] output = self.complete_output() - self.result.append((1, test, output, _exc_str)) + use_time = round(self.test_end_time - self.test_start_time, 2) + self.result.append((1, test, output, _exc_str, use_time)) if self.verbosity > 1: - sys.stderr.write('F ') + sys.stderr.write(' F ') sys.stderr.write(str(test)) sys.stderr.write('\n') else: - sys.stderr.write('F') + sys.stderr.write(' F ') + sys.stderr.write('\n') class HTMLTestRunner(Template_mixin): """ """ - def __init__(self, stream=sys.stdout, verbosity=1,title=None,description=None,tester=None): + def __init__(self, stream=sys.stdout, verbosity=2 ,title=None,description=None,tester=None): self.stream = stream self.verbosity = verbosity if title is None: @@ -571,7 +583,7 @@ def __init__(self, stream=sys.stdout, verbosity=1,title=None,description=None,te def run(self, test): "Run the given test case or test suite." - result = _TestResult(self.verbosity) + result = _TestResult(self.verbosity) # verbosity为1,只输出成功与否,为2会输出用例名称 test(result) self.stopTime = datetime.datetime.now() self.generateReport(test, result) @@ -584,12 +596,12 @@ def sortResult(self, result_list): # Here at least we want to group them together by class. rmap = {} classes = [] - for n,t,o,e in result_list: + for n,t,o,e,s in result_list: cls = t.__class__ if cls not in rmap: rmap[cls] = [] classes.append(cls) - rmap[cls].append((n,t,o,e)) + rmap[cls].append((n,t,o,e,s)) r = [(cls, rmap[cls]) for cls in classes] return r @@ -608,17 +620,19 @@ def getReportAttributes(self, result): if result.error_count: status.append('错误 %s' % result.error_count ) if status: status = ','.join(status) - self.passrate = str("%.2f%%" % (float(result.success_count) / float(result.success_count + result.failure_count + result.error_count) * 100)) + if (result.success_count + result.failure_count + result.error_count) > 0: + self.passrate = str("%.2f%%" % (float(result.success_count) / float(result.success_count + result.failure_count + result.error_count) * 100)) + else: + self.passrate = "0.00 %" else: status = 'none' return [ ('测试人员', self.tester), ('开始时间',startTime), ('合计耗时',duration), - ('测试结果',status + ",通过率= "+self.passrate), + ('测试结果',status + ",通过率 = "+self.passrate), ] - def generateReport(self, test, result): report_attrs = self.getReportAttributes(result) generator = 'HTMLTestRunner %s' % __version__ @@ -661,14 +675,18 @@ def _generate_heading(self, report_attrs): def _generate_report(self, result): rows = [] sortedResult = self.sortResult(result.result) + # 所有用例统计耗时初始化 + sum_ns = 0 for cid, (cls, cls_results) in enumerate(sortedResult): # subtotal for a class - np = nf = ne = 0 - for n,t,o,e in cls_results: + np = nf = ne = ns = 0 + for n,t,o,e,s in cls_results: if n == 0: np += 1 elif n == 1: nf += 1 else: ne += 1 - + ns += s # 把单个class用例文件里面的多个def用例每次的耗时相加 + ns = round(ns, 2) + sum_ns += ns # 把所有用例的每次耗时相加 # format class description if cls.__module__ == "__main__": name = cls.__name__ @@ -685,18 +703,20 @@ def _generate_report(self, result): fail = nf, error = ne, cid = 'c%s' % (cid+1), + time_usage=str(ns) + "秒" # 单个用例耗时 ) rows.append(row) - for tid, (n,t,o,e) in enumerate(cls_results): + for tid, (n,t,o,e,s) in enumerate(cls_results): self._generate_report_test(rows, cid, tid, n, t, o, e) - + sum_ns = round(sum_ns, 2) report = self.REPORT_TMPL % dict( test_list = ''.join(rows), count = str(result.success_count+result.failure_count+result.error_count), Pass = str(result.success_count), fail = str(result.failure_count), error = str(result.error_count), + time_usage=str(sum_ns) + "秒", # 所有用例耗时 passrate =self.passrate, ) return report From 0e3299de2c0ae12df1715baa01cb9222e8238917 Mon Sep 17 00:00:00 2001 From: boafantasy Date: Wed, 7 Feb 2018 17:42:14 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=82=B9=E5=87=BB?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E6=8C=89=E9=92=AE=E4=B8=8D=E4=BC=9A=E6=AD=A3?= =?UTF-8?q?=E7=A1=AE=E5=B1=95=E7=A4=BA=E5=AF=B9=E5=BA=94=E7=BA=A7=E5=88=AB?= =?UTF-8?q?=E7=9A=84=E7=94=A8=E4=BE=8B=E6=97=A5=E5=BF=97=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- python3x/HTMLTestReportCN.py | 49 +++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/python3x/HTMLTestReportCN.py b/python3x/HTMLTestReportCN.py index 5571ba2..d7227c8 100644 --- a/python3x/HTMLTestReportCN.py +++ b/python3x/HTMLTestReportCN.py @@ -107,6 +107,7 @@ import unittest from xml.sax import saxutils import sys +import re # ------------------------------------------------------------------------ # The redirectors below are used to capture output during testing. Output @@ -213,6 +214,7 @@ class Template_mixin(object): 1:Failed //pt hiddenRow, ft none 2:Pass //pt none, ft hiddenRow 3:All //pt none, ft none +4:Error //pt diddenRow, et none */ function showCase(level) { trs = document.getElementsByTagName("tr"); @@ -220,7 +222,7 @@ class Template_mixin(object): tr = trs[i]; id = tr.id; if (id.substr(0,2) == 'ft') { - if (level == 2 || level == 0 ) { + if (level == 2 || level == 0 || level ==4) { tr.className = 'hiddenRow'; } else { @@ -228,7 +230,15 @@ class Template_mixin(object): } } if (id.substr(0,2) == 'pt') { - if (level < 2) { + if (level == 1 || level == 0 || level == 4) { + tr.className = 'hiddenRow'; + } + else { + tr.className = ''; + } + } + if (id.substr(0,2) == 'et') { + if (level < 4) { tr.className = 'hiddenRow'; } else { @@ -263,6 +273,10 @@ class Template_mixin(object): 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) { @@ -358,7 +372,7 @@ class Template_mixin(object): 概要{ %(passrate)s } 通过{ %(Pass)s } 失败{ %(fail)s } -错误{ %(error)s } +错误{ %(error)s } 所有{ %(count)s }

@@ -626,11 +640,28 @@ def getReportAttributes(self, result): self.passrate = "0.00 %" else: status = 'none' + # 失败模块列表统计逻辑start + # 为了发邮件的时候确定知道哪个模块失败了,这里在报告的头里面单独添加一行失败模块的列表 + # 把用例结果和对应的模块名称单独提取到一个list + module_result_list = [(status, re.split(" |\(|\.", str(name))[2]) for status, name, _, _, _ in result.result] + failed_report_module_list = [] # 初始化模块失败列表 + for module_result in module_result_list: + if module_result[0] != 0: # 如果结果是失败的,则把模块名字放到失败模块列表 + failed_report_module_list.append(module_result[1]) + failed_report_module_list = list(set(failed_report_module_list)) # 去重 + if len(failed_report_module_list) == 0: # 如果没有失败的模块,失败模块日志为固定描述,否则用“,”连接 + failed_string = "无失败模块" + elif len(failed_report_module_list) == 1: + failed_string = "".join(failed_report_module_list) + else: + failed_string = ",".join(failed_report_module_list) + # 失败模块列表统计逻辑end return [ ('测试人员', self.tester), ('开始时间',startTime), ('合计耗时',duration), ('测试结果',status + ",通过率 = "+self.passrate), + ('失败的模块', failed_string) ] def generateReport(self, test, result): @@ -683,7 +714,7 @@ def _generate_report(self, result): for n,t,o,e,s in cls_results: if n == 0: np += 1 elif n == 1: nf += 1 - else: ne += 1 + elif n == 2: ne += 1 ns += s # 把单个class用例文件里面的多个def用例每次的耗时相加 ns = round(ns, 2) sum_ns += ns # 把所有用例的每次耗时相加 @@ -723,10 +754,16 @@ def _generate_report(self, result): def _generate_report_test(self, rows, cid, tid, n, t, o, e): - # e.g. 'pt1.1', 'ft1.1', etc + # e.g. 'pt1_1', 'ft1_1', 'et1_1'etc has_output = bool(o or e) # ID修改点为下划线,支持Bootstrap折叠展开特效 - Findyou - tid = (n == 0 and 'p' or 'f') + 't%s_%s' % (cid+1,tid+1) + if n == 0: + tid_flag = 'p' + elif n == 1: + tid_flag = 'f' + elif n == 2: + tid_flag = 'e' + tid = tid_flag + 't%s_%s' % (cid+1, tid+1) name = t.id().split('.')[-1] doc = t.shortDescription() or "" desc = doc and ('%s: %s' % (name, doc)) or name