python |
您所在的位置:网站首页 › python报告模板 › python |
python - HTMLTestRunner 测试报告模板设置 优化模板下载地址: http://download.csdn.net/download/chinayyj2010/10039097 后又有所修改没有更新,最近在群文件中 注意:HTMLTestRunner 对应的 python2.x、pyhon3.x最新优化后的模板文件放到了QQ群:193056556中,有需要的可以进群自取。
从改地址下载下的模板运行结果如下。
其实该模板还有可以优化的地方。可以根据个人需要进行修改,当然这里需要有一定的前端技术基础。
比如上图中的错误,竟然会有背景色,很不协调。 REPORT_TMPL = """ 通过率 [%(passrate)s ] 通过[ %(Pass)s ] 错误[ %(error)s ] 失败[ %(fail)s ] 所有[ %(count)s ] ... #错误[ %(error)s ] # 这里因为原来是没有错误展示的,是我自己添加上去的,所以没有找的合适的样式,就这样先写了一下,所以出现了上图的背景色。
后查看了资料知道 class="btn btn-success" 是前端 Bootstrap 的技术,所以就参考了 http://www.runoob.com/bootstrap/bootstrap-buttons.html Bootstrap 按钮 中的按钮样式 class="btn btn-warning" 代码如下: REPORT_TMPL = """通过率 [%(passrate)s ] 通过[ %(Pass)s ] 错误[ %(error)s ] 失败[ %(fail)s ] 所有[ %(count)s ] ...
效果如图
其他修改可以根据修改 需要自行修改,如修改文字描述,符号展示等。 下面在把这次优化后的源码贴出来,方便今后使用。 ![]() ![]() %(description)s """ # variables: (title, parameters, description) HEADING_ATTRIBUTE_TMPL = """%(name)s : %(value)s """ # variables: (name, value) # ------------------------------------------------------------------------ # Report # # 汉化,加美化效果 --Yang Yao Jun # # 这里涉及到了 Bootstrap 前端技术,Bootstrap 按钮 资料介绍详见:http://www.runoob.com/bootstrap/bootstrap-buttons.html # REPORT_TMPL = """通过率 [%(passrate)s ] 通过[ %(Pass)s ] 错误[ %(error)s ] 失败[ %(fail)s ] 所有[ %(count)s ] 用例集/测试用例 总计 通过 错误 失败 详细 %(test_list)s 总计 %(count)s %(Pass)s %(error)s %(fail)s 通过率:%(passrate)s """ # variables: (test_list, count, Pass, fail, error ,passrate) REPORT_CLASS_TMPL = r""" %(desc)s %(count)s %(Pass)s %(error)s %(fail)s 详细 """ # variables: (style, desc, count, Pass, fail, error, cid) #失败 的样式,去掉原来JS效果,美化展示效果 -Yang Yao Jun REPORT_TEST_WITH_OUTPUT_TMPL = r""" %(desc)s %(status)s %(script)s """ # variables: (tid, Class, style, desc, status) # 通过 的样式,加标签效果 -Yang Yao Jun REPORT_TEST_NO_OUTPUT_TMPL = r""" %(desc)s %(status)s """ # variables: (tid, Class, style, desc, status) REPORT_TEST_OUTPUT_TMPL = r""" %(id)s: %(output)s """ # variables: (id, output) # ------------------------------------------------------------------------ # ENDING # # 增加返回顶部按钮 --Yang Yao Jun ENDING_TMPL = """; """ # -------------------- The end of the Template class ------------------- TestResult = unittest.TestResult class _TestResult(TestResult): # note: _TestResult is a pure representation of results. # It lacks the output and reporting ability compares to unittest._TextTestResult. def __init__(self, verbosity=1): TestResult.__init__(self) self.stdout0 = None self.stderr0 = None self.success_count = 0 self.failure_count = 0 self.error_count = 0 self.verbosity = verbosity # result is a list of result in 4 tuple # ( # result code (0: success; 1: fail; 2: error), # TestCase object, # Test output (byte string), # stack trace, # ) self.result = [] #增加一个测试通过率 --Yang Yao Jun self.passrate=float(0) def startTest(self, test): TestResult.startTest(self, test) # just one buffer for both stdout and stderr self.outputBuffer = StringIO.StringIO() stdout_redirector.fp = self.outputBuffer stderr_redirector.fp = self.outputBuffer self.stdout0 = sys.stdout self.stderr0 = sys.stderr sys.stdout = stdout_redirector sys.stderr = stderr_redirector def complete_output(self): """ Disconnect output redirection and return buffer. Safe to call multiple times. """ if self.stdout0: sys.stdout = self.stdout0 sys.stderr = self.stderr0 self.stdout0 = None self.stderr0 = None return self.outputBuffer.getvalue() def stopTest(self, test): # Usually one of addSuccess, addError or addFailure would have been called. # But there are some path in unittest that would bypass this. # We must disconnect stdout in stopTest(), which is guaranteed to be called. self.complete_output() def addSuccess(self, test): self.success_count += 1 TestResult.addSuccess(self, test) output = self.complete_output() self.result.append((0, test, output, '')) if self.verbosity > 1: sys.stderr.write('ok ') sys.stderr.write(str(test)) sys.stderr.write('\n') else: sys.stderr.write('.') 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)) if self.verbosity > 1: sys.stderr.write('E ') sys.stderr.write(str(test)) sys.stderr.write('\n') else: sys.stderr.write('E') 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)) if self.verbosity > 1: sys.stderr.write('F ') sys.stderr.write(str(test)) sys.stderr.write('\n') else: sys.stderr.write('F') class HTMLTestRunner(Template_mixin): """ """ def __init__(self, stream=sys.stdout, verbosity=1,title=None,description=None,tester=None): self.stream = stream self.verbosity = verbosity if title is None: self.title = self.DEFAULT_TITLE else: self.title = title if description is None: self.description = self.DEFAULT_DESCRIPTION else: self.description = description if tester is None: self.tester = self.DEFAULT_TESTER else: self.tester = tester self.startTime = datetime.datetime.now() def run(self, test): "Run the given test case or test suite." result = _TestResult(self.verbosity) test(result) self.stopTime = datetime.datetime.now() self.generateReport(test, result) print >>sys.stderr, '\nTime Elapsed: %s' % (self.stopTime-self.startTime) return result def sortResult(self, result_list): # unittest does not seems to run in any particular order. # Here at least we want to group them together by class. rmap = {} classes = [] for n,t,o,e in result_list: cls = t.__class__ if not rmap.has_key(cls): rmap[cls] = [] classes.append(cls) rmap[cls].append((n,t,o,e)) r = [(cls, rmap[cls]) for cls in classes] return r #替换测试结果status为通过率 --Yang Yao Jun def getReportAttributes(self, result): """ Return report attributes as a list of (name, value). Override this to add custom attributes. """ startTime = str(self.startTime)[:19] duration = str(self.stopTime - self.startTime) status = [] status.append('共 %s 条用例' % (result.success_count + result.failure_count + result.error_count)) if result.success_count: status.append('通过 %s 条' % result.success_count) if result.failure_count: status.append('失败 %s 条' % result.failure_count) 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)) else: status = 'none' return [ (u'测试人员', self.tester), (u'开始时间',startTime), (u'合计耗时',duration), (u'测试结果',status + ",通过率= "+self.passrate), ] def generateReport(self, test, result): report_attrs = self.getReportAttributes(result) generator = 'HTMLTestRunner %s' % __version__ stylesheet = self._generate_stylesheet() heading = self._generate_heading(report_attrs) report = self._generate_report(result) ending = self._generate_ending() output = self.HTML_TMPL % dict( title = saxutils.escape(self.title), generator = generator, stylesheet = stylesheet, heading = heading, report = report, ending = ending, ) self.stream.write(output.encode('utf8')) def _generate_stylesheet(self): return self.STYLESHEET_TMPL #增加Tester显示 -Yang Yao Jun def _generate_heading(self, report_attrs): a_lines = [] for name, value in report_attrs: line = self.HEADING_ATTRIBUTE_TMPL % dict( name = saxutils.escape(name), value = saxutils.escape(value), ) a_lines.append(line) heading = self.HEADING_TMPL % dict( title = saxutils.escape(self.title), parameters = ''.join(a_lines), description = saxutils.escape(self.description), tester= saxutils.escape(self.tester), ) return heading #生成报告 --Yang Yao Jun添加注释 def _generate_report(self, result): rows = [] sortedResult = self.sortResult(result.result) for cid, (cls, cls_results) in enumerate(sortedResult): # subtotal for a class np = nf = ne = 0 for n,t,o,e in cls_results: if n == 0: np += 1 elif n == 1: nf += 1 else: ne += 1 # format class description if cls.__module__ == "__main__": name = cls.__name__ else: name = "%s.%s" % (cls.__module__, cls.__name__) doc = cls.__doc__ and cls.__doc__.split("\n")[0] or "" desc = doc and '%s: %s' % (name, doc) or name row = self.REPORT_CLASS_TMPL % dict( style = ne > 0 and 'errorClass' or nf > 0 and 'failClass' or 'passClass', desc = desc, count = np+nf+ne, Pass = np, fail = nf, error = ne, cid = 'c%s' % (cid+1), ) rows.append(row) for tid, (n,t,o,e) in enumerate(cls_results): self._generate_report_test(rows, cid, tid, n, t, o, e) 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), passrate =self.passrate, ) return report def _generate_report_test(self, rows, cid, tid, n, t, o, e): # e.g. 'pt1.1', 'ft1.1', etc has_output = bool(o or e) # ID修改点为下划线,支持Bootstrap折叠展开特效 - Yang Yao Jun tid = (n == 0 and 'p' or 'f') + '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 tmpl = has_output and self.REPORT_TEST_WITH_OUTPUT_TMPL or self.REPORT_TEST_NO_OUTPUT_TMPL # utf-8 支持中文 - Yang Yao Jun # o and e should be byte string because they are collected from stdout and stderr? if isinstance(o, str): # TODO: some problem with 'string_escape': it escape \n and mess up formating # uo = unicode(o.encode('string_escape')) # uo = o.decode('latin-1') uo = o.decode('utf-8') else: uo = o if isinstance(e, str): # TODO: some problem with 'string_escape': it escape \n and mess up formating # ue = unicode(e.encode('string_escape')) # ue = e.decode('latin-1') ue = e.decode('utf-8') else: ue = e script = self.REPORT_TEST_OUTPUT_TMPL % dict( id = tid, output = saxutils.escape(uo+ue), ) row = tmpl % dict( tid = tid, Class = (n == 0 and 'hiddenRow' or 'none'), style = n == 2 and 'errorCase' or (n == 1 and 'failCase' or 'passCase'), desc = desc, script = script, status = self.STATUS[n], ) rows.append(row) if not has_output: return def _generate_ending(self): return self.ENDING_TMPL ############################################################################## # Facilities for running tests from the command line ############################################################################## # Note: Reuse unittest.TestProgram to launch test. In the future we may # build our own launcher to support more specific command line # parameters like test title, CSS, etc. class TestProgram(unittest.TestProgram): """ A variation of the unittest.TestProgram. Please refer to the base class for command line parameters. """ def runTests(self): # Pick HTMLTestRunner as the default test runner. # base class's testRunner parameter is not useful because it means # we have to instantiate HTMLTestRunner before we know self.verbosity. if self.testRunner is None: self.testRunner = HTMLTestRunner(verbosity=self.verbosity) unittest.TestProgram.runTests(self) main = TestProgram ############################################################################## # Executing this module from the command line ############################################################################## if __name__ == "__main__": main(module=None) HTMLTestRunner.py注意:HTMLTestRunner 对应的 python2.x、pyhon3.x最新优化后的模板文件放到了QQ群:193056556中,有需要的可以进群自取。
|
今日新闻 |
点击排行 |
|
推荐新闻 |
图片新闻 |
|
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭 |