码迷,mamicode.com
首页 > Web开发 > 详细

HTMLTESTRunner自动化测试报告增加截图功能

时间:2018-07-11 17:12:32      阅读:408      评论:0      收藏:0      [点我收藏+]

标签:success   order   unittest   char   datetime   either   ace   out   ott   

我们都知道HTMLTESTRunner自动化测试报告,是Unittest单元测试框架报告,那么在做ui测试的时候就有点不适用了。

我们需要出错截图功能。

 

以下是我改的,增加了截图功能,先展示界面,再展示代码。

 

概要界面:

技术分享图片

展开界面:

技术分享图片

 

代码展示:

以下代码,只支持python2.7;至于python3的话,可以自己改一下。

截图方式:print ‘screenshot:‘, timestrmap, ‘.png‘    在要截图的位置print就可以了。

 

原理:展示时通过捕获unittest  print中查找字符串“screenshot:”;找到就说明有截图,然后截取图片地址,写到html模版src=中。

 

截图代码:

 

    @property
    def getImage(self):
        ‘‘‘
        截取图片,并保存在images文件夹
        :return: 无
        ‘‘‘
        timestrmap = time.strftime(%Y%m%d_%H.%M.%S)
        imgPath = os.path.join(gl.imgPath, %s.png % str(timestrmap))

        self.driver.save_screenshot(imgPath)
        print  screenshot:, timestrmap, .png

 

 

 

 HTMLTESTRunner.py   点击加号,展开代码

技术分享图片
  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=天枢
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 4:Error  
195 */
196 function showCase(level) {
197     trs = document.getElementsByTagName("tr");
198     for (var i = 0; i < trs.length; i++) {
199         tr = trs[i];
200         id = tr.id;
201         if (id.substr(0,2) == ‘ft‘) {
202             if (level == 2 || level == 0 ) {
203                 tr.className = ‘hiddenRow‘;
204             }
205             else {
206                 tr.className = ‘‘;
207             }
208         }
209         if (id.substr(0,2) == ‘pt‘) {
210             if (level < 2 || level ==4) {
211                 tr.className = ‘hiddenRow‘;
212             }
213             else {
214                 tr.className = ‘‘;
215             }
216         }
217     }
218     //加入【详细】切换文字变化 --Findyou
219     detail_class=document.getElementsByClassName(‘detail‘);
220     //console.log(detail_class.length)
221     if (level == 3) {
222         for (var i = 0; i < detail_class.length; i++){
223             detail_class[i].innerHTML="收起"
224         }
225     }
226     else{
227             for (var i = 0; i < detail_class.length; i++){
228             detail_class[i].innerHTML="详细"
229         }
230     }
231 }
232 function showClassDetail(cid, count) {
233     var id_list = Array(count);
234     var toHide = 1;
235     for (var i = 0; i < count; i++) {
236         //ID修改 点 为 下划线 -Findyou
237         tid0 = ‘t‘ + cid.substr(1) + ‘_‘ + (i+1);
238         tid = ‘f‘ + tid0;
239         tr = document.getElementById(tid);
240         if (!tr) {
241             tid = ‘p‘ + tid0;
242             tr = document.getElementById(tid);
243         }
244         id_list[i] = tid;
245         if (tr.className) {
246             toHide = 0;
247         }
248     }
249     for (var i = 0; i < count; i++) {
250         tid = id_list[i];
251         //修改点击无法收起的BUG,加入【详细】切换文字变化 --Findyou
252         if (toHide) {
253             document.getElementById(tid).className = ‘hiddenRow‘;
254             document.getElementById(cid).innerText = "详细"
255         }
256         else {
257             document.getElementById(tid).className = ‘‘;
258             document.getElementById(cid).innerText = "收起"
259         }
260     }
261 }
262 function html_escape(s) {
263     s = s.replace(/&/g,‘&amp;‘);
264     s = s.replace(/</g,‘&lt;‘);
265     s = s.replace(/>/g,‘&gt;‘);
266     return s;
267 }
268 </script>
269 %(heading)s
270 %(report)s
271 %(ending)s
272 </body>
273 </html>
274 """
275     # variables: (title, generator, stylesheet, heading, report, ending)
276 
277 
278     # ------------------------------------------------------------------------
279     # Stylesheet
280     #
281     # alternatively use a <link> for external style sheet, e.g.
282     #   <link rel="stylesheet" href="$url" type="text/css">
283 
284     STYLESHEET_TMPL = """
285 <style type="text/css" media="screen">
286 body        { font-family: Microsoft YaHei,Tahoma,arial,helvetica,sans-serif;padding: 20px; font-size: 80%; }
287 table       { font-size: 100%; }
288 /* -- heading ---------------------------------------------------------------------- */
289 .heading {
290     margin-top: 0ex;
291     margin-bottom: 1ex;
292 }
293 .heading .description {
294     margin-top: 4ex;
295     margin-bottom: 6ex;
296 }
297 /* -- report ------------------------------------------------------------------------ */
298 #total_row  { font-weight: bold; }
299 .passCase   { color: #5cb85c; }
300 .failCase   { color: #d9534f; font-weight: bold; }
301 .errorCase  { color: #f0ad4e; font-weight: bold; }
302 .hiddenRow  { display: none; }
303 .testcase   { margin-left: 2em; }
304 </style>
305 """
306 
307     # ------------------------------------------------------------------------
308     # Heading
309     #
310 
311     HEADING_TMPL = """<div class=‘heading‘>
312 <h4 style="font-family: Microsoft YaHei">%(title)s</h4>
313 %(parameters)s
314 <p class=‘description‘>%(description)s</p>
315 </div>
316 """ # variables: (title, parameters, description)
317 
318     HEADING_ATTRIBUTE_TMPL = """<p class=‘attribute‘><strong>%(name)s : </strong> %(value)s</p>
319 """ # variables: (name, value)
320 
321 
322 
323     # ------------------------------------------------------------------------
324     # Report
325     #
326     # 汉化,加美化效果 --Findyou
327     REPORT_TMPL = """
328 <p id=‘show_detail_line‘>
329 <a class="btn btn-primary" href=‘javascript:showCase(0)‘>概要{ %(passrate)s }</a>
330 <a class="btn btn-warning" href=‘javascript:showCase(4)‘>错误{ %(error)s }</a>
331 <a class="btn btn-danger" href=‘javascript:showCase(1)‘>失败{ %(fail)s }</a>
332 <a class="btn btn-success" href=‘javascript:showCase(2)‘>通过{ %(Pass)s }</a>
333 <a class="btn btn-info" href=‘javascript:showCase(3)‘>所有{ %(count)s }</a>
334 </p>
335 <table id=‘result_table‘ class="table table-condensed table-bordered table-hover">
336 <colgroup>
337 <col align=‘left‘ />
338 <col align=‘right‘ />
339 <col align=‘right‘ />
340 <col align=‘right‘ />
341 <col align=‘right‘ />
342 <col align=‘right‘ />
343 <col align=‘right‘ />
344 </colgroup>
345 <tr id=‘header_row‘ class="text-center success" style="font-weight: bold;font-size: 14px;">
346     <td>用例集/测试用例</td>
347     <td>总计</td>
348     <td>通过</td>
349     <td>失败</td>
350     <td>错误</td>
351     <td>详细</td>
352     <td>截图</td>
353 </tr>
354 %(test_list)s
355 <tr id=‘total_row‘ class="text-center active">
356     <td>总计</td>
357     <td>%(count)s</td>
358     <td>%(Pass)s</td>
359     <td>%(fail)s</td>
360     <td>%(error)s</td>
361     <td>通过率:%(passrate)s</td>
362     <td> <a href="" target="_blank"></a></td>
363 </tr>
364 </table>
365 """ # variables: (test_list, count, Pass, fail, error ,passrate)
366 
367     REPORT_CLASS_TMPL = r"""
368 <tr class=‘%(style)s warning‘>
369     <td>%(desc)s</td>
370     <td class="text-center">%(count)s</td>
371     <td class="text-center">%(Pass)s</td>
372     <td class="text-center">%(fail)s</td>
373     <td class="text-center">%(error)s</td>
374     <td class="text-center"><a href="javascript:showClassDetail(‘%(cid)s‘,%(count)s)" class="detail" id=‘%(cid)s‘>详细</a></td>
375     <td class="text-center">Assert or Error Image</td>
376 </tr>
377 """ # variables: (style, desc, count, Pass, fail, error, cid)
378 
379     #失败 的样式,去掉原来JS效果,美化展示效果  -Findyou
380     REPORT_TEST_WITH_OUTPUT_TMPL = r"""
381 <tr id=‘%(tid)s‘ class=‘%(Class)s‘>
382     <td class=‘%(style)s‘ width=‘300px‘><div class=‘testcase‘>%(desc)s</div></td>
383     <td colspan=‘5‘ align=‘left‘ width=‘600px‘> <!--print 输出框位置-->
384     <!--默认收起错误信息 -Findyou
385     <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>
386     <div id=‘div_%(tid)s‘ class="collapse">  -->
387     <!-- 默认展开错误信息 -Findyou -->
388     <button id=‘btn_%(tid)s‘ type="button"  class="btn btn-danger btn-xs" data-toggle="collapse" data-target=‘#div_%(tid)s‘>%(status)s</button>
389     <div id=‘div_%(tid)s‘ class="collapse in">
390     <pre>
391     %(script)s
392     </pre>
393     </div>
394     </td>
395     <td align="right">
396         <a %(hidde)s href="%(image)s">
397             <img   src="%(image)s" height="200" width="400"/>
398         </a>
399     </td>
400 </tr>
401 
402 
403 """ # variables: (tid, Class, style, desc, status)
404 
405     # 通过 的样式,加标签效果  -Findyou
406     REPORT_TEST_NO_OUTPUT_TMPL = r"""
407 <tr id=‘%(tid)s‘ class=‘%(Class)s‘>
408     <td class=‘%(style)s‘><div class=‘testcase‘>%(desc)s</div></td>
409     <td colspan=‘5‘ align=‘center‘><span class="label label-success success">%(status)s</span></td>
410     <td align="right">
411         <a %(hidde)s href="%(image)s">
412             <img   src="%(image)s" height="200" width="400"/>
413         </a>
414     </td>
415 </tr>
416 """ # variables: (tid, Class, style, desc, status)
417 
418     REPORT_TEST_OUTPUT_TMPL = r"""
419 %(id)s: %(output)s
420 """ # variables: (id, output)
421 
422     # ------------------------------------------------------------------------
423     # ENDING
424     #
425     # 增加返回顶部按钮  --Findyou
426     ENDING_TMPL = """<div id=‘ending‘>&nbsp;</div>
427     <div style=" position:fixed;right:50px; bottom:30px; width:20px; height:20px;cursor:pointer">
428     <a href="#"><span class="glyphicon glyphicon-eject" style = "font-size:30px;" aria-hidden="true">
429     </span></a></div>
430     """
431 
432 # -------------------- The end of the Template class -------------------
433 
434 
435 TestResult = unittest.TestResult
436 
437 class _TestResult(TestResult):
438     # note: _TestResult is a pure representation of results.
439     # It lacks the output and reporting ability compares to unittest._TextTestResult.
440 
441     def __init__(self, verbosity=1):
442         TestResult.__init__(self)
443         self.stdout0 = None
444         self.stderr0 = None
445         self.success_count = 0
446         self.failure_count = 0
447         self.error_count = 0
448         self.verbosity = verbosity
449 
450         # result is a list of result in 4 tuple
451         # (
452         #   result code (0: success; 1: fail; 2: error),
453         #   TestCase object,
454         #   Test output (byte string),
455         #   stack trace,
456         # )
457         self.result = []
458         #增加一个测试通过率 --Findyou
459         self.passrate=float(0)
460 
461 
462     def startTest(self, test):
463         TestResult.startTest(self, test)
464         # just one buffer for both stdout and stderr
465         self.outputBuffer = StringIO.StringIO()
466         stdout_redirector.fp = self.outputBuffer
467         stderr_redirector.fp = self.outputBuffer
468         self.stdout0 = sys.stdout
469         self.stderr0 = sys.stderr
470         sys.stdout = stdout_redirector
471         sys.stderr = stderr_redirector
472 
473 
474     def complete_output(self):
475         """
476         Disconnect output redirection and return buffer.
477         Safe to call multiple times.
478         """
479         if self.stdout0:
480             sys.stdout = self.stdout0
481             sys.stderr = self.stderr0
482             self.stdout0 = None
483             self.stderr0 = None
484         return self.outputBuffer.getvalue()
485 
486 
487     def stopTest(self, test):
488         # Usually one of addSuccess, addError or addFailure would have been called.
489         # But there are some path in unittest that would bypass this.
490         # We must disconnect stdout in stopTest(), which is guaranteed to be called.
491         self.complete_output()
492 
493 
494     def addSuccess(self, test):
495         self.success_count += 1
496         TestResult.addSuccess(self, test)
497         output = self.complete_output()
498         self.result.append((0, test, output, ‘‘))
499         if self.verbosity > 1:
500             sys.stderr.write(ok )
501             sys.stderr.write(str(test))
502             sys.stderr.write(\n)
503         else:
504             sys.stderr.write(.)
505 
506     def addError(self, test, err):
507         self.error_count += 1
508         TestResult.addError(self, test, err)
509         _, _exc_str = self.errors[-1]
510         output = self.complete_output()
511         self.result.append((2, test, output, _exc_str))
512         if self.verbosity > 1:
513             sys.stderr.write(E  )
514             sys.stderr.write(str(test))
515             sys.stderr.write(\n)
516         else:
517             sys.stderr.write(E)
518 
519     def addFailure(self, test, err):
520         self.failure_count += 1
521         TestResult.addFailure(self, test, err)
522         _, _exc_str = self.failures[-1]
523         output = self.complete_output()
524         self.result.append((1, test, output, _exc_str))
525         if self.verbosity > 1:
526             sys.stderr.write(F  )
527             sys.stderr.write(str(test))
528             sys.stderr.write(\n)
529         else:
530             sys.stderr.write(F)
531 
532 
533 class HTMLTestRunner(Template_mixin):
534     """
535     """
536     def __init__(self, stream=sys.stdout, verbosity=1,title=None,description=None,tester=None):
537         self.stream = stream
538         self.verbosity = verbosity
539         if title is None:
540             self.title = self.DEFAULT_TITLE
541         else:
542             self.title = title
543         if description is None:
544             self.description = self.DEFAULT_DESCRIPTION
545         else:
546             self.description = description
547         if tester is None:
548             self.tester = self.DEFAULT_TESTER
549         else:
550             self.tester = tester
551 
552         self.startTime = datetime.datetime.now()
553 
554 
555     def run(self, test):
556         "Run the given test case or test suite."
557         result = _TestResult(self.verbosity)
558         test(result)
559         self.stopTime = datetime.datetime.now()
560         self.generateReport(test, result)
561         print >>sys.stderr, \nTime Elapsed: %s % (self.stopTime-self.startTime)
562         return result
563 
564 
565     def sortResult(self, result_list):
566         # unittest does not seems to run in any particular order.
567         # Here at least we want to group them together by class.
568         rmap = {}
569         classes = []
570         for n,t,o,e in result_list:
571             cls = t.__class__
572             if not rmap.has_key(cls):
573                 rmap[cls] = []
574                 classes.append(cls)
575             rmap[cls].append((n,t,o,e))
576         r = [(cls, rmap[cls]) for cls in classes]
577         return r
578 
579     #替换测试结果status为通过率 --Findyou
580     def getReportAttributes(self, result):
581         """
582         Return report attributes as a list of (name, value).
583         Override this to add custom attributes.
584         """
585         startTime = str(self.startTime)[:19]
586         duration = str(self.stopTime - self.startTime)
587         status = []
588         status.append(共 %s % (result.success_count + result.failure_count + result.error_count))
589         if result.success_count: status.append(通过 %s    % result.success_count)
590         if result.failure_count: status.append(失败 %s % result.failure_count)
591         if result.error_count:   status.append(错误 %s   % result.error_count  )
592         if status:
593             status = .join(status)
594             self.passrate = str("%.2f%%" % (float(result.success_count) / float(result.success_count + result.failure_count + result.error_count) * 100))
595         else:
596             status = none
597         return [
598             (u测试人员, self.tester),
599             (u开始时间,startTime),
600             (u合计耗时,duration),
601             (u测试结果,status + ",通过率= "+self.passrate),
602         ]
603 
604 
605     def generateReport(self, test, result):
606         report_attrs = self.getReportAttributes(result)
607         generator = HTMLTestRunner %s % __version__
608         stylesheet = self._generate_stylesheet()
609         heading = self._generate_heading(report_attrs)
610         report = self._generate_report(result)
611         ending = self._generate_ending()
612         output = self.HTML_TMPL % dict(
613             title = saxutils.escape(self.title),
614             generator = generator,
615             stylesheet = stylesheet,
616             heading = heading,
617             report = report,
618             ending = ending,
619         )
620         self.stream.write(output.encode(utf8))
621 
622 
623     def _generate_stylesheet(self):
624         return self.STYLESHEET_TMPL
625 
626     #增加Tester显示 -Findyou
627     def _generate_heading(self, report_attrs):
628         a_lines = []
629         for name, value in report_attrs:
630             line = self.HEADING_ATTRIBUTE_TMPL % dict(
631                     name = saxutils.escape(name),
632                     value = saxutils.escape(value),
633                 )
634             a_lines.append(line)
635         heading = self.HEADING_TMPL % dict(
636             title = saxutils.escape(self.title),
637             parameters = ‘‘.join(a_lines),
638             description = saxutils.escape(self.description),
639             tester= saxutils.escape(self.tester),
640         )
641         return heading
642 
643     #生成报告  --Findyou添加注释
644     def _generate_report(self, result):
645         rows = []
646         sortedResult = self.sortResult(result.result)
647         for cid, (cls, cls_results) in enumerate(sortedResult):
648             # subtotal for a class
649             np = nf = ne = 0
650             for n,t,o,e in cls_results:
651                 if n == 0: np += 1
652                 elif n == 1: nf += 1
653                 else: ne += 1
654 
655             # format class description
656             if cls.__module__ == "__main__":
657                 name = cls.__name__
658             else:
659                 name = "%s.%s" % (cls.__module__, cls.__name__)
660             doc = cls.__doc__ and cls.__doc__.split("\n")[0] or ""
661             desc = doc and %s: %s % (name, doc) or name
662 
663             row = self.REPORT_CLASS_TMPL % dict(
664                 style = ne > 0 and errorClass or nf > 0 and failClass or passClass,
665                 desc = desc,
666                 count = np+nf+ne,
667                 Pass = np,
668                 fail = nf,
669                 error = ne,
670                 cid = c%s % (cid+1),
671             )
672             rows.append(row)
673 
674             for tid, (n,t,o,e) in enumerate(cls_results):
675                 self._generate_report_test(rows, cid, tid, n, t, o, e)
676 
677         report = self.REPORT_TMPL % dict(
678             test_list = ‘‘.join(rows),
679             count = str(result.success_count+result.failure_count+result.error_count),
680             Pass = str(result.success_count),
681             fail = str(result.failure_count),
682             error = str(result.error_count),
683             passrate =self.passrate,
684         )
685         return report
686 
687 
688     def _generate_report_test(self, rows, cid, tid, n, t, o, e):
689         # e.g. ‘pt1.1‘, ‘ft1.1‘, etc
690         has_output = bool(o or e)
691         # ID修改点为下划线,支持Bootstrap折叠展开特效 - Findyou
692         tid = (n == 0 and p or f) + t%s_%s % (cid+1,tid+1)
693         name = t.id().split(.)[-1]
694         doc = t.shortDescription() or ""
695         desc = doc and (%s: %s % (name, doc)) or name
696         tmpl = has_output and self.REPORT_TEST_WITH_OUTPUT_TMPL or self.REPORT_TEST_NO_OUTPUT_TMPL
697 
698         # utf-8 支持中文 - Findyou
699          # o and e should be byte string because they are collected from stdout and stderr?
700         if isinstance(o, str):
701             # TODO: some problem with ‘string_escape‘: it escape \n and mess up formating
702             # uo = unicode(o.encode(‘string_escape‘))
703             # uo = o.decode(‘latin-1‘)
704             uo = o.decode(utf-8)
705         else:
706             uo = o
707         if isinstance(e, str):
708             # TODO: some problem with ‘string_escape‘: it escape \n and mess up formating
709             # ue = unicode(e.encode(‘string_escape‘))
710             # ue = e.decode(‘latin-1‘)
711             ue = e.decode(utf-8)
712         else:
713             ue = e
714 
715         script = self.REPORT_TEST_OUTPUT_TMPL % dict(
716             id = tid,
717             output = saxutils.escape(uo+ue),
718         )
719         # 插入图片
720         unum = str(uo).find(screenshot:)
721         if ((uo or ue) and unum !=-1):
722             hidde_status = ‘‘
723             unum=str(uo).find(screenshot:)
724             image_url = ./images/+str(uo)[unum+11:unum+34].replace( ,‘‘)
725 
726         else:
727             hidde_status = ‘‘‘hidden="hidden"‘‘‘
728             image_url = ‘‘
729 
730         row = tmpl % dict(
731             tid = tid,
732             Class = (n == 0 and hiddenRow or none),
733             style = n == 2 and errorCase or (n == 1 and failCase or passCase),
734             desc = desc,
735             script = script,
736             hidde=hidde_status,
737             image=image_url,
738             status = self.STATUS[n],
739         )
740         rows.append(row)
741         if not has_output:
742             return
743 
744     def _generate_ending(self):
745         return self.ENDING_TMPL
746 
747 
748 ##############################################################################
749 # Facilities for running tests from the command line
750 ##############################################################################
751 
752 # Note: Reuse unittest.TestProgram to launch test. In the future we may
753 # build our own launcher to support more specific command line
754 # parameters like test title, CSS, etc.
755 class TestProgram(unittest.TestProgram):
756     """
757     A variation of the unittest.TestProgram. Please refer to the base
758     class for command line parameters.
759     """
760     def runTests(self):
761         # Pick HTMLTestRunner as the default test runner.
762         # base class‘s testRunner parameter is not useful because it means
763         # we have to instantiate HTMLTestRunner before we know self.verbosity.
764         if self.testRunner is None:
765             self.testRunner = HTMLTestRunner(verbosity=self.verbosity)
766         unittest.TestProgram.runTests(self)
767 
768 main = TestProgram
769 
770 ##############################################################################
771 # Executing this module from the command line
772 ##############################################################################
773 
774 if __name__ == "__main__":
775     main(module=None)
View Code

 

 期待你的加入;共同学习,一起进步:
python|测试|技术交流 qq群:563227894
python|测试|技术交流 qq群:563227894
python|测试|技术交流 qq群:563227894

 

HTMLTESTRunner自动化测试报告增加截图功能

标签:success   order   unittest   char   datetime   either   ace   out   ott   

原文地址:https://www.cnblogs.com/yhleng/p/9295328.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!