Python2 HTMLTestRunner自动化测试报告美化
Posted BlackTest
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python2 HTMLTestRunner自动化测试报告美化相关的知识,希望对你有一定的参考价值。
python2 的测试报告美化,需要的同学直接用
1 #coding=utf-8 2 """ 3 A TestRunner for use with the Python unit testing framework. It 4 generates a HTML report to show the result at a glance. 5 The simplest way to use this is to invoke its main method. E.g. 6 import unittest 7 import HTMLTestRunner 8 ... define your tests ... 9 if __name__ == \'__main__\': 10 HTMLTestRunner.main() 11 For more customization options, instantiates a HTMLTestRunner object. 12 HTMLTestRunner is a counterpart to unittest\'s TextTestRunner. E.g. 13 # output to a file 14 fp = file(\'my_report.html\', \'wb\') 15 runner = HTMLTestRunner.HTMLTestRunner( 16 stream=fp, 17 title=\'My unit test\', 18 description=\'This demonstrates the report output by HTMLTestRunner.\' 19 ) 20 # Use an external stylesheet. 21 # See the Template_mixin class for more customizable options 22 runner.STYLESHEET_TMPL = \'<link rel="stylesheet" href="my_stylesheet.css" type="text/css">\' 23 # run the test 24 runner.run(my_test_suite) 25 ------------------------------------------------------------------------ 26 Copyright (c) 2004-2007, Wai Yip Tung 27 All rights reserved. 28 Redistribution and use in source and binary forms, with or without 29 modification, are permitted provided that the following conditions are 30 met: 31 * Redistributions of source code must retain the above copyright notice, 32 this list of conditions and the following disclaimer. 33 * Redistributions in binary form must reproduce the above copyright 34 notice, this list of conditions and the following disclaimer in the 35 documentation and/or other materials provided with the distribution. 36 * Neither the name Wai Yip Tung nor the names of its contributors may be 37 used to endorse or promote products derived from this software without 38 specific prior written permission. 39 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 40 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 41 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 42 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 43 OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 44 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 45 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 46 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 47 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 48 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 49 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 50 """ 51 52 # URL: http://tungwaiyip.info/software/HTMLTestRunner.html 53 54 __author__ = "Wai Yip Tung, Findyou" 55 __version__ = "0.8.2.1" 56 57 58 """ 59 Change History 60 Version 0.8.2.1 -Findyou 61 * 支持中文,汉化 62 * 调整样式,美化(需要连入网络,使用的百度的Bootstrap.js) 63 * 增加 通过分类显示、测试人员、通过率的展示 64 * 优化“详细”与“收起”状态的变换 65 * 增加返回顶部的锚点 66 Version 0.8.2 67 * Show output inline instead of popup window (Viorel Lupu). 68 Version in 0.8.1 69 * Validated XHTML (Wolfgang Borgert). 70 * Added description of test classes and test cases. 71 Version in 0.8.0 72 * Define Template_mixin class for customization. 73 * Workaround a IE 6 bug that it does not treat <script> block as CDATA. 74 Version in 0.7.1 75 * Back port to Python 2.3 (Frank Horowitz). 76 * Fix missing scroll bars in detail log (Podi). 77 """ 78 79 # TODO: color stderr 80 # TODO: simplify javascript using ,ore than 1 class in the class attribute? 81 82 import datetime 83 import StringIO 84 import sys 85 import time 86 import unittest 87 from xml.sax import saxutils 88 import sys 89 reload(sys) 90 sys.setdefaultencoding(\'utf-8\') 91 92 # ------------------------------------------------------------------------ 93 # The redirectors below are used to capture output during testing. Output 94 # sent to sys.stdout and sys.stderr are automatically captured. However 95 # in some cases sys.stdout is already cached before HTMLTestRunner is 96 # invoked (e.g. calling logging.basicConfig). In order to capture those 97 # output, use the redirectors for the cached stream. 98 # 99 # e.g. 100 # >>> logging.basicConfig(stream=HTMLTestRunner.stdout_redirector) 101 # >>> 102 103 class OutputRedirector(object): 104 """ Wrapper to redirect stdout or stderr """ 105 def __init__(self, fp): 106 self.fp = fp 107 108 def write(self, s): 109 self.fp.write(s) 110 111 def writelines(self, lines): 112 self.fp.writelines(lines) 113 114 def flush(self): 115 self.fp.flush() 116 117 stdout_redirector = OutputRedirector(sys.stdout) 118 stderr_redirector = OutputRedirector(sys.stderr) 119 120 # ---------------------------------------------------------------------- 121 # Template 122 123 class Template_mixin(object): 124 """ 125 Define a HTML template for report customerization and generation. 126 Overall structure of an HTML report 127 HTML 128 +------------------------+ 129 |<html> | 130 | <head> | 131 | | 132 | STYLESHEET | 133 | +----------------+ | 134 | | | | 135 | +----------------+ | 136 | | 137 | </head> | 138 | | 139 | <body> | 140 | | 141 | HEADING | 142 | +----------------+ | 143 | | | | 144 | +----------------+ | 145 | | 146 | REPORT | 147 | +----------------+ | 148 | | | | 149 | +----------------+ | 150 | | 151 | ENDING | 152 | +----------------+ | 153 | | | | 154 | +----------------+ | 155 | | 156 | </body> | 157 |</html> | 158 +------------------------+ 159 """ 160 161 STATUS = { 162 0: \'通过\', 163 1: \'失败\', 164 2: \'错误\', 165 } 166 167 DEFAULT_TITLE = \'自动化测试报告\' 168 DEFAULT_DESCRIPTION = \'\' 169 DEFAULT_TESTER=\'WangYingHao\' 170 171 # ------------------------------------------------------------------------ 172 # HTML Template 173 174 HTML_TMPL = r"""<?xml version="1.0" encoding="UTF-8"?> 175 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 176 <html xmlns="http://www.w3.org/1999/xhtml"> 177 <head> 178 <title>%(title)s</title> 179 <meta name="generator" content="%(generator)s"/> 180 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> 181 <link href="http://libs.baidu.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet"> 182 <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script> 183 <script src="http://libs.baidu.com/bootstrap/3.0.3/js/bootstrap.min.js"></script> 184 %(stylesheet)s 185 </head> 186 <body > 187 <script language="javascript" type="text/javascript"> 188 output_list = Array(); 189 /*level 调整增加只显示通过用例的分类 --Findyou 190 0:Summary //all hiddenRow 191 1:Failed //pt hiddenRow, ft none 192 2:Pass //pt none, ft hiddenRow 193 3:All //pt none, ft none 194 */ 195 function showCase(level) { 196 trs = document.getElementsByTagName("tr"); 197 for (var i = 0; i < trs.length; i++) { 198 tr = trs[i]; 199 id = tr.id; 200 if (id.substr(0,2) == \'ft\') { 201 if (level == 2 || level == 0 ) { 202 tr.className = \'hiddenRow\'; 203 } 204 else { 205 tr.className = \'\'; 206 } 207 } 208 if (id.substr(0,2) == \'pt\') { 209 if (level < 2) { 210 tr.className = \'hiddenRow\'; 211 } 212 else { 213 tr.className = \'\'; 214 } 215 } 216 } 217 //加入【详细】切换文字变化 --Findyou 218 detail_class=document.getElementsByClassName(\'detail\'); 219 //console.log(detail_class.length) 220 if (level == 3) { 221 for (var i = 0; i < detail_class.length; i++){ 222 detail_class[i].innerHTML="收起" 223 } 224 } 225 else{ 226 for (var i = 0; i < detail_class.length; i++){ 227 detail_class[i].innerHTML="详细" 228 } 229 } 230 } 231 function showClassDetail(cid, count) { 232 var id_list = Array(count); 233 var toHide = 1; 234 for (var i = 0; i < count; i++) { 235 //ID修改 点 为 下划线 -Findyou 236 tid0 = \'t\' + cid.substr(1) + \'_\' + (i+1); 237 tid = \'f\' + tid0; 238 tr = document.getElementById(tid); 239 if (!tr) { 240 tid = \'p\' + tid0; 241 tr = document.getElementById(tid); 242 } 243 id_list[i] = tid; 244 if (tr.className) { 245 toHide = 0; 246 } 247 } 248 for (var i = 0; i < count; i++) { 249 tid = id_list[i]; 250 //修改点击无法收起的BUG,加入【详细】切换文字变化 --Findyou 251 if (toHide) { 252 document.getElementById(tid).className = \'hiddenRow\'; 253 document.getElementById(cid).innerText = "详细" 254 } 255 else { 256 document.getElementById(tid).className = \'\'; 257 document.getElementById(cid).innerText = "收起" 258 } 259 } 260 } 261 function html_escape(s) { 262 s = s.replace(/&/g,\'&\'); 263 s = s.replace(/</g,\'<\'); 264 s = s.replace(/>/g,\'>\'); 265 return s; 266 } 267 </script> 268 %(heading)s 269 %(report)s 270 %(ending)s 271 </body> 272 </html> 273 """ 274 # variables: (title, generator, stylesheet, heading, report, ending) 275 276 277 # ------------------------------------------------------------------------ 278 # Stylesheet 279 # 280 # alternatively use a <link> for external style sheet, e.g. 281 # <link rel="stylesheet" href="$url" type="text/css"> 282 283 STYLESHEET_TMPL = """ 284 <style type="text/css" media="screen"> 285 body { font-family: Microsoft YaHei,Tahoma,arial,helvetica,sans-serif;padding: 20px; font-size: 80%; } 286 table { font-size: 100%; } 287 /* -- heading ---------------------------------------------------------------------- */ 288 .heading { 289 margin-top: 0ex; 290 margin-bottom: 1ex; 291 } 292 .heading .description { 293 margin-top: 4ex; 294 margin-bottom: 6ex; 295 } 296 /* -- report ------------------------------------------------------------------------ */ 297 #total_row { font-weight: bold; } 298 .passCase { color: #5cb85c; } 299 .failCase { color: #d9534f; font-weight: bold; } 300 .errorCase { color: #f0ad4e; font-weight: bold; } 301 .hiddenRow { display: none; } 302 .testcase { margin-left: 2em; } 303 </style> 304 """ 305 306 # ------------------------------------------------------------------------ 307 # Heading 308 # 309 310 HEADING_TMPL = """<div class=\'heading\'> 311 <h1 style="font-family: Microsoft YaHei">%(title)s</h1> 312 %(parameters)s 313 <p class=\'description\'>%(description)s</p> 314 </div> 315 """ # variables: (title, parameters, description) 316 317 HEADING_ATTRIBUTE_TMPL = """<p class=\'attribute\'><strong>%(name)s : </strong> %(value)s</p> 318 """ # variables: (name, value) 319 320 321 322 # ------------------------------------------------------------------------ 323 # Report 324 # 325 # 汉化,加美化效果 --Findyou 326 REPORT_TMPL = """ 327 <p id=\'show_detail_line\'> 328 <a class="btn btn-primary" href=\'javascript:showCase(0)\'>概要{ %(passrate)s }</a> 329 <a class="btn btn-danger" href=\'javascript:showCase(1)\'>失败{ %(fail)s }</a> 330 <a class="btn btn-success" href=\'javascript:showCase(2)\'>通过{ %(Pass)s }</a> 331 <a class="btn btn-info" href=\'javascript:showCase(3)\'>所有{ %(count)s }</a> 332 </p> 333 <table id=\'result_table\' class="table table-condensed table-bordered table-hover"> 334 <colgroup> 335 <col align=\'left\' /> 336 <col align=\'right\' /> 337 <col align=\'right\' /> 338 <col align=\'right\' /> 339 <col align=\'right\' /> 340 <col align=\'right\' /> 341 </colgroup> 342 <tr id=\'header_row\' class="text-center success" style="font-weight: bold;font-size: 14px;"> 343 <td>用例集/测试用例</td> 344 <td>总计</td> 345 <td>通过</td> 346 <td>失败</td> 347 <td>错误</td> 348 <td>详细</td> 349 </tr> 350 %(test_list)s 351 <tr id=\'total_row\' class="text-center active"> 352 <td>总计</td> 353 <td>%(count)s</td> 354 <td>%(Pass)s</td> 355 <td>%(fail)s</td> 356 <td>%(error)s</td> 357 <td>通过率:%(passrate)s</td> 358 </tr> 359 </table> 360 """ # variables: (test_list, count, Pass, fail, error ,passrate) 361 362 REPORT_CLASS_TMPL = r""" 363 <tr class=\'%(style)s warning\'> 364 <td>%(desc)s</td> 365 <td class="text-center">%(count)s</td> 366 <td class="text-center">%(Pass)s</td> 367 <td class="text-center">%(fail)s</td> 368 <td class="text-center">%(error)s</td> 369 <td class="text-center"><a href="javascript:showClassDetail(\'%(cid)s\',%(count)s)" class="detail" id=\'%(cid)s\'>详细</a></td> 370 </tr> 371 """ # variables: (style, desc, count, Pass, fail, error, cid) 372 373 #失败 的样式,去掉原来JS效果,美化展示效果 -Findyou 374 REPORT_TEST_WITH_OUTPUT_TMPL = r""" 375 <tr id=\'%(tid)s\' class=\'%(Class)s\'> 376 <td class=\'%(style)s\'><div class=\'testcase\'>%(desc)s</div></td> 377 <td colspan=\'5\' align=\'center\'> 378 <!--默认收起错误信息 -Findyou 379 <button id=\'btn_%(tid)s\' type="button" class="btn btn-danger btn-xs collapsed" data-toggle="collapse" data-target=\'#div_%(tid)s\'>%(status)s</button> 380 <div id=\'div_%(tid)s\' class="collapse"> --> 381 <!-- 默认展开错误信息 -Findyou --> 382 <button id=\'btn_%(tid)s\' type="button" class="btn btn-danger btn-xs" data-toggle="collapse" data-target=\'#div_%(tid)s\'>%(status)s</button> 383 <div id=\'div_%(tid)s\' class="collapse in"> 384 <pre> 385 %(script)s 386 </pre> 387 </div> 388 </td> 389 </tr> 390 """ # variables: (tid, Class, style, desc, status) 391 392 # 通过 的样式,加标签效果 -Findyou 393 REPORT_TEST_NO_OUTPUT_TMPL = r""" 394 <tr id=\'%(tid)s\' class=\'%(Class)s\'> 395 <td class=\'%(style)s\'><div class=\'testcase\'>%(desc)s</div></td> 396 <td colspan=\'5\' align=\'center\'><span class="label label-success success">%(status)s</span></td> 397 </tr> 398 """ # variables: (tid, Class, style, desc, status) 399 400 REPORT_TEST_OUTPUT_TMPL = r""" 401 %(id)s: %(output)s 402 """ # variables: (id, output) 403 404 # ------------------------------------------------------------------------ 405 # ENDING 406 # 407 # 增加返回顶部按钮 --Findyou 408 ENDING_TMPL = """<div id=\'ending\'> </div> 409 <div style=" position:fixed;right:50px; bottom:30px; width:20px; height:20px;cursor:pointer"> 410 <a href="#"><span class="glyphicon glyphicon-eject" style = "font-size:30px;" aria-hidden="true"> 411 </span></a></div> 412 """ 413 414 # -------------------- The end of the Template class ------------------- 415 416 417 TestResult = unittest.TestResult 418 419 class _TestResult(TestResult): 420 # note: _TestResult is a pure representation of results. 421 # It lacks the output and reporting ability compares to unittest._TextTestResult. 422 423 def __init__(self, verbosity=1): 424 TestResult.__init__(self) 425 self.stdout0 = None 426 self.stderr0 = None 427 self.success_count = 0 428 self.failure_count = 0 429 self.error_count = 0 430 self.verbosity = verbosity 431 432 # result is a list of result in 4 tuple 433 # ( 434 # result code (0: success; 1: fail; 2: error), 435 # TestCase object, 436 # Test output (byte string), 437 # stack trace, 438 # ) 439 self.result = [] 440 #增加一个测试通过率 --Findyou 441 self.passrate=float(0) 442 443 444 def startTest(self, test): 445 TestResult.startTest(self, test) 446 # just one buffer for both stdout and stderr 447 self.outputBuffer = StringIO.StringIO() 448 stdout_redirector.fp = self.outputBuffer 449 stderr_redirector.fp = self.outputBuffer 450 self.stdout0 = sys.stdout 451 self.stderr0 = sys.stderr 452 sys.stdout = stdout_redirector 453 sys.stderr = stderr_redirector 454 455 456 def complete_output(self): 457 """ 458 Disconnect output redirection and return buffer. 459 Safe to call multiple times. 460以上是关于Python2 HTMLTestRunner自动化测试报告美化的主要内容,如果未能解决你的问题,请参考以下文章
python3-如何正常使用HTMLTestRunner.py,生成自动化测试报告
基于python2.7+HTMLTestrunner生成报告后样式美化图版以及源码获取
Python2.7升级到3.0 HTMLTestrunner报错解决方法