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,\'&amp;\');
263     s = s.replace(/</g,\'&lt;\');
264     s = s.replace(/>/g,\'&gt;\');
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\'>&nbsp;</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测试报告美化

python3-如何正常使用HTMLTestRunner.py,生成自动化测试报告

基于python2.7+HTMLTestrunner生成报告后样式美化图版以及源码获取

Python2.7升级到3.0 HTMLTestrunner报错解决方法

pyhton+selenium+unittest自动化测试框架之测试报告

HTMLTestRunner 汉化版---来源一个大神的源码(加了失败截图,用例失败重新执行 功能)