Python的unittest拓展和HTMLReport SKIP报表扩展

C:\Python27\Lib中修改unittest内容 

unittest 在init中添加Myskip代码:

__all__ = ['TestResult', 'TestCase', 'TestSuite',
           'TextTestRunner', 'TestLoader', 'FunctionTestCase', 'main',
           'defaultTestLoader', 'SkipTest', 'skip', 'skipIf', 'skipUnless',
           'expectedFailure', 'TextTestResult', 'installHandler',
           'registerResult', 'removeResult', 'removeHandler','Myskip']

from .case import (TestCase, FunctionTestCase, SkipTest, skip, skipIf, Myskip,skipUnless, expectedFailure)

unittest在case.py中增加如下代码:

def _id(obj):
  return obj

def Myskip(func):
    
    def RebackTest(self):
        if self._resultForDoCleanups.failures or self._resultForDoCleanups.errors:
            raise SkipTest("{} do not excute because {} is failed".format(func.__name__,self._resultForDoCleanups.failures[0][0]._testMethodName))
        func(self)
    return  RebackTest

 

C:\Python27\Lib修改HTMLReport文件(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  
  6 The simplest way to use this is to invoke its main method. E.g.
  7  
  8     import unittest
  9     import HTMLTestRunner
 10  
 11     ... define your tests ...
 12  
 13     if __name__ == '__main__':
 14         HTMLTestRunner.main()
 15  
 16  
 17 For more customization options, instantiates a HTMLTestRunner object.
 18 HTMLTestRunner is a counterpart to unittest's TextTestRunner. E.g.
 19  
 20     # output to a file
 21     fp = file('my_report.html', 'wb')
 22     runner = HTMLTestRunner.HTMLTestRunner(
 23                 stream=fp,
 24                 title='My unit test',
 25                 description='This demonstrates the report output by HTMLTestRunner.'
 26                 )
 27  
 28     # Use an external stylesheet.
 29     # See the Template_mixin class for more customizable options
 30     runner.STYLESHEET_TMPL = '<link rel="stylesheet" href="my_stylesheet.css" type="text/css">'
 31  
 32     # run the test
 33     runner.run(my_test_suite)
 34  
 35  
 36 ------------------------------------------------------------------------
 37 Copyright (c) 2004-2007, Wai Yip Tung
 38 All rights reserved.
 39  
 40 Redistribution and use in source and binary forms, with or without
 41 modification, are permitted provided that the following conditions are
 42 met:
 43  
 44 * Redistributions of source code must retain the above copyright notice,
 45   this list of conditions and the following disclaimer.
 46 * Redistributions in binary form must reproduce the above copyright
 47   notice, this list of conditions and the following disclaimer in the
 48   documentation and/or other materials provided with the distribution.
 49 * Neither the name Wai Yip Tung nor the names of its contributors may be
 50   used to endorse or promote products derived from this software without
 51   specific prior written permission.
 52  
 53 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 54 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 55 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 56 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 57 OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 58 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 59 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 60 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 61 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 62 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 63 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 64 """
 65  
 66 # URL: http://tungwaiyip.info/software/HTMLTestRunner.html
 67  
 68 __author__ = "Wai Yip Tung"
 69 __version__ = "0.8.2"
 70  
 71  
 72 """
 73 Change History
 74  
 75 Version 0.8.2
 76 * Show output inline instead of popup window (Viorel Lupu).
 77  
 78 Version in 0.8.1
 79 * Validated XHTML (Wolfgang Borgert).
 80 * Added description of test classes and test cases.
 81  
 82 Version in 0.8.0
 83 * Define Template_mixin class for customization.
 84 * Workaround a IE 6 bug that it does not treat <script> block as CDATA.
 85  
 86 Version in 0.7.1
 87 * Back port to Python 2.3 (Frank Horowitz).
 88 * Fix missing scroll bars in detail log (Podi).
 89 """
 90  
 91 # TODO: color stderr
 92 # TODO: simplify javascript using ,ore than 1 class in the class attribute?
 93 #coding=utf-8
 94 import datetime
 95 import io
 96 import sys
 97 reload(sys)
 98 sys.setdefaultencoding('utf8')
 99 import time
100 import unittest
101 import re
102 from xml.sax import saxutils
103  
104  
105 # ------------------------------------------------------------------------
106 # The redirectors below are used to capture output during testing. Output
107 # sent to sys.stdout and sys.stderr are automatically captured. However
108 # in some cases sys.stdout is already cached before HTMLTestRunner is
109 # invoked (e.g. calling logging.basicConfig). In order to capture those
110 # output, use the redirectors for the cached stream.
111 #
112 # e.g.
113 #   >>> logging.basicConfig(stream=HTMLTestRunner.stdout_redirector)
114 #   >>>
115  
116 class OutputRedirector(object):
117     """ Wrapper to redirect stdout or stderr """
118     def __init__(self, fp):
119         self.fp = fp
120  
121     def write(self, s):
122         self.fp.write(s)
123  
124     def writelines(self, lines):
125         self.fp.writelines(lines)
126  
127     def flush(self):
128         self.fp.flush()
129  
130 stdout_redirector = OutputRedirector(sys.stdout)
131 stderr_redirector = OutputRedirector(sys.stderr)
132  
133  
134  
135 # ----------------------------------------------------------------------
136 # Template
137  
138 class Template_mixin(object):
139     """
140     Define a HTML template for report customerization and generation.
141  
142     Overall structure of an HTML report
143  
144     HTML
145     +------------------------+
146     |<html>                  |
147     |  <head>                |
148     |                        |
149     |   STYLESHEET           |
150     |   +----------------+   |
151     |   |                |   |
152     |   +----------------+   |
153     |                        |
154     |  </head>               |
155     |                        |
156     |  <body>                |
157     |                        |
158     |   HEADING              |
159     |   +----------------+   |
160     |   |                |   |
161     |   +----------------+   |
162     |                        |
163     |   REPORT               |
164     |   +----------------+   |
165     |   |                |   |
166     |   +----------------+   |
167     |                        |
168     |   ENDING               |
169     |   +----------------+   |
170     |   |                |   |
171     |   +----------------+   |
172     |                        |
173     |  </body>               |
174     |</html>                 |
175     +------------------------+
176     """
177  
178     STATUS = {
179     0: 'pass',
180     1: 'fail',
181     2: 'error',
182     3:'skip'
183     }
184  
185     DEFAULT_TITLE = 'Unit Test Report'
186     DEFAULT_DESCRIPTION = ''
187  
188     # ------------------------------------------------------------------------
189     # HTML Template
190  
191     HTML_TMPL = r"""<?xml version="1.0" encoding="UTF-8"?>
192 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
193 <html xmlns="http://www.w3.org/1999/xhtml">
194 <head>
195     <title>%(title)s</title>
196     <meta name="generator" content="%(generator)s"/>
197     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
198     %(stylesheet)s
199 </head>
200 <body>
201 <script language="javascript" type="text/javascript"><!--
202 output_list = Array();
203  
204 /* level - 0:Summary; 1:Failed; 2:All */
205 function showCase(level) {
206     trs = document.getElementsByTagName("tr");
207     for (var i = 0; i < trs.length; i++) {
208         tr = trs[i];
209         id = tr.id;
210         if (id.substr(0,2) == 'ft') {
211             if (level < 1) {
212                 tr.className = 'hiddenRow';
213             }
214             else {
215                 tr.className = '';
216             }
217         }
218         if (id.substr(0,2) == 'pt') {
219             if (level > 1) {
220                 tr.className = '';
221             }
222             else {
223                 tr.className = 'hiddenRow';
224             }        }        if (id.substr(0,2) == 'st') {           if (level > 1) {               tr.className = '';            }           else {               tr.className = 'hiddenRow';           }
225         }
226     }
227 }
228  
229 function showClassDetail(cid, count) {
230     var id_list = Array(count);
231     var toHide = 1;
232     for (var i = 0; i < count; i++) {
233         tid0 = 't' + cid.substr(1) + '.' + (i+1);
234         tid = 'f' + tid0;
235         tr = document.getElementById(tid);
236         if (!tr) {
237             tid = 'p' + tid0;
238             tr = document.getElementById(tid);
239         }
240          if (!tr) {
241             tid = 's' + tid0;
242             tr = document.getElementById(tid);
243         }
244         id_list[i] = tid;
245         if (tr.className) {
246             toHide = 0;
247         }
248  
249     }
250     for (var i = 0; i < count; i++) {
251         tid = id_list[i];
252         if (toHide) {
253             document.getElementById('div_'+tid).style.display = 'none'
254             document.getElementById(tid).className = 'hiddenRow';
255         }
256         else {
257             document.getElementById(tid).className = '';
258         }
259     }
260 }
261  
262  
263 function showTestDetail(div_id){
264     var details_div = document.getElementById(div_id)
265     var displayState = details_div.style.display
266     // alert(displayState)
267     if (displayState != 'block' ) {
268         displayState = 'block'
269         details_div.style.display = 'block'
270     }
271     else {
272         details_div.style.display = 'none'
273     }
274 }
275  
276  
277 function html_escape(s) {
278     s = s.replace(/&/g,'&');
279     s = s.replace(/</g,'<');
280     s = s.replace(/>/g,'>');
281     return s;
282 }
283  
284 /* obsoleted by detail in <div>
285 function showOutput(id, name) {
286     var w = window.open("", //url
287                     name,
288                     "resizable,scrollbars,status,width=800,height=450");
289     d = w.document;
290     d.write("<pre>");
291     d.write(html_escape(output_list[id]));
292     d.write("\n");
293     d.write("<a href='javascript:window.close()'>close</a>\n");
294     d.write("</pre>\n");
295     d.close();
296 }
297 */
298 --></script>
299  
300 %(heading)s
301 %(report)s
302 %(ending)s
303  
304 </body>
305 </html>
306 """
307     # variables: (title, generator, stylesheet, heading, report, ending)
308  
309  
310     # ------------------------------------------------------------------------
311     # Stylesheet
312     #
313     # alternatively use a <link> for external style sheet, e.g.
314     #   <link rel="stylesheet" href="$url" type="text/css">
315  
316     STYLESHEET_TMPL = """
317 <style type="text/css" media="screen">
318 body        { font-family: verdana, arial, helvetica, sans-serif; font-size: 80%; }
319 table       { font-size: 100%; }
320 pre         { word-wrap:break-word;word-break:break-all;overflow:auto;}
321  
322 /* -- heading ---------------------------------------------------------------------- */
323 h1 {
324     font-size: 16pt;
325     color: gray;
326 }
327 .heading {
328     margin-top: 0ex;
329     margin-bottom: 1ex;
330 }
331  
332 .heading .attribute {
333     margin-top: 1ex;
334     margin-bottom: 0;
335 }
336  
337 .heading .description {
338     margin-top: 4ex;
339     margin-bottom: 6ex;
340 }
341  
342 /* -- css div popup ------------------------------------------------------------------------ */
343 a.popup_link {
344 }
345  
346 a.popup_link:hover {
347     color: red;
348 }
349  
350 .popup_window {
351     display: none;
352     position: relative;
353     left: 0px;
354     top: 0px;
355     /*border: solid #627173 1px; */
356     padding: 10px;
357     background-color: 00;
358     font-family: "Lucida Console", "Courier New", Courier, monospace;
359     text-align: left;
360     font-size: 8pt;
361     width: 600px;
362 }
363  
364 }
365 /* -- report ------------------------------------------------------------------------ */
366 #show_detail_line {
367     margin-top: 3ex;
368     margin-bottom: 1ex;
369 }
370 #result_table {
371     width: 80%;
372     border-collapse: collapse;
373     border: 1px solid #777;
374 }
375 #header_row {
376     font-weight: bold;
377     color: white;
378     background-color: #777;
379 }
380 #result_table td {
381     border: 1px solid #777;
382     padding: 2px;
383 }
384 #total_row  { font-weight: bold; }
385 .passClass  { background-color: #6c6; }
386 .failClass  { background-color: #c60; }
387 .errorClass { background-color: #c00; }
388 .passCase   { color: #6c6; }
389 .failCase   { color: #c60; font-weight: bold; }
390 .errorCase  { color: #c00; font-weight: bold; }
391 .hiddenRow  { display: none; }
392 .testcase   { margin-left: 2em; }
393  
394  
395 /* -- ending ---------------------------------------------------------------------- */
396 #ending {
397 }
398  
399 </style>
400 """
401  
402  
403  
404     # ------------------------------------------------------------------------
405     # Heading
406     #
407  
408     HEADING_TMPL = """<div class='heading'>
409 <h1>%(title)s</h1>
410 %(parameters)s
411 <p class='description'>%(description)s</p>
412 </div>
413  
414 """ # variables: (title, parameters, description)
415  
416     HEADING_ATTRIBUTE_TMPL = """<p class='attribute'><strong>%(name)s:</strong> %(value)s</p>
417 """ # variables: (name, value)
418  
419  
420  
421     # ------------------------------------------------------------------------
422     # Report
423     #
424  
425     REPORT_TMPL = """
426 <p id='show_detail_line'>Show
427 <a href='javascript:showCase(0)'>Summary</a>
428 <a href='javascript:showCase(1)'>Failed</a>
429 <a href='javascript:showCase(2)'>All</a>
430 </p>
431 <table id='result_table'>
432 <colgroup>
433 <col align='left' />
434 <col align='right' />
435 <col align='right' />
436 <col align='right' />
437 <col align='right' />
438 <col align='right' />
439 </colgroup>
440 <tr id='header_row'>
441     <td>Test Group/Test case</td>
442     <td>Count</td>
443     <td>Pass</td>
444     <td>Fail</td>
445     <td>Error</td>
446     <td>Skip</td>
447     <td>View</td>
448     <td>Screenshot</td>
449 </tr>
450 %(test_list)s
451 <tr id='total_row'>
452     <td>Total</td>
453     <td>%(count)s</td>
454     <td>%(Pass)s</td>
455     <td>%(fail)s</td>
456     <td>%(error)s</td>
457     <td>%(skip)s</td>
458     <td> </td>
459     <td> </td>
460  
461 </tr>
462 </table>
463 """ # variables: (test_list, count, Pass, fail, error)
464  
465     REPORT_CLASS_TMPL = r"""
466 <tr class='%(style)s'>
467     <td>%(desc)s</td>
468     <td>%(count)s</td>
469     <td>%(Pass)s</td>
470     <td>%(fail)s</td>
471     <td>%(error)s</td>
472     <td>%(skip)s</td>
473     <td><a href="javascript:showClassDetail('%(cid)s',%(count)s)">Detail</a></td>
474     <td> </td>
475 </tr>
476 """ # variables: (style, desc, count, Pass, fail,skip, error, cid)
477  
478  
479     REPORT_TEST_WITH_OUTPUT_TMPL = r"""
480 <tr id='%(tid)s' class='%(Class)s'>
481     <td class='%(style)s'><div class='testcase'>%(desc)s</div></td>
482     <td colspan='6' align='center'>
483     <!--css div popup start-->
484     <a class="popup_link" onfocus='this.blur();' href="javascript:showTestDetail('div_%(tid)s')" >
485         %(status)s</a>
486  
487     <div id='div_%(tid)s' class="popup_window" >
488         <div style='text-align: right; color:red;cursor:pointer'>
489         <a onfocus='this.blur();' onclick="document.getElementById('div_%(tid)s').style.display = 'none' " >
490            [x]</a>
491         </div>
492         <pre>
493         %(script)s
494         </pre>
495     </div>
496     <!--css div popup end-->
497     </td>
498     <td align='center'>
499     <a  %(hidde)s  href="%(image)s">picture_shot</a>
500     </td>
501 </tr>
502 """ # variables: (tid, Class, style, desc, status)
503     REPORT_TEST_NO_OUTPUT_TMPL = r"""
504 <tr id='%(tid)s' class='%(Class)s'>
505     <td class='%(style)s'><div class='testcase'>%(desc)s</div></td>
506     <td colspan='6' align='center'>%(status)s</td>
507     <td align='center'>
508     <a  %(hidde)s  href="%(image)s">picture_shot</a>
509     </td>
510 </tr>
511 """ # variables: (tid, Class, style, desc, status)
512  
513  
514     REPORT_TEST_OUTPUT_TMPL = r"""
515 %(id)s: %(output)s
516 """
517      
518     # variables: (id, output)
519  
520  
521  
522     # ------------------------------------------------------------------------
523     # ENDING
524     #
525  
526     ENDING_TMPL = """<div id='ending'> </div>"""
527  
528 # -------------------- The end of the Template class -------------------
529  
530  
531 TestResult = unittest.TestResult
532  
533 class _TestResult(TestResult):
534     # note: _TestResult is a pure representation of results.
535     # It lacks the output and reporting ability compares to unittest._TextTestResult.
536  
537     def __init__(self, verbosity=1):
538         TestResult.__init__(self)
539         self.stdout0 = None
540         self.stderr0 = None
541         self.success_count = 0
542         self.skipped_count=0#add skipped_count
543         self.failure_count = 0
544         self.error_count = 0
545         self.verbosity = verbosity
546  
547         # result is a list of result in 4 tuple
548         # (
549         #   result code (0: success; 1: fail; 2: error),
550         #   TestCase object,
551         #   Test output (byte string),
552         #   stack trace,
553         # )
554         self.result = []
555  
556  
557     def startTest(self, test):
558         TestResult.startTest(self, test)
559         # just one buffer for both stdout and stderr
560         self.outputBuffer = io.BytesIO()
561         stdout_redirector.fp = self.outputBuffer
562         stderr_redirector.fp = self.outputBuffer
563         self.stdout0 = sys.stdout
564         self.stderr0 = sys.stderr
565         sys.stdout = stdout_redirector
566         sys.stderr = stderr_redirector
567  
568  
569     def complete_output(self):
570         """
571         Disconnect output redirection and return buffer.
572         Safe to call multiple times.
573         """
574         if self.stdout0:
575             sys.stdout = self.stdout0
576             sys.stderr = self.stderr0
577             self.stdout0 = None
578             self.stderr0 = None
579         return self.outputBuffer.getvalue()
580  
581  
582     def stopTest(self, test):
583         # Usually one of addSuccess, addError or addFailure would have been called.
584         # But there are some path in unittest that would bypass this.
585         # We must disconnect stdout in stopTest(), which is guaranteed to be called.
586         self.complete_output()
587  
588  
589     def addSuccess(self, test):
590         self.success_count += 1
591         TestResult.addSuccess(self, test)
592         output = self.complete_output()
593         self.result.append((0, test, output, ''))
594         if self.verbosity > 1:
595             sys.stderr.write('ok ')
596             sys.stderr.write(str(test))
597             sys.stderr.write('\n')
598         else:
599             sys.stderr.write('.')
600  
601     def addSkip(self, test, reason):
602         self.skipped_count+= 1
603         TestResult.addSkip(self, test,reason)
604         output = self.complete_output()
605         self.result.append((3, test,'',reason))
606         if self.verbosity > 1:
607             sys.stderr.write('skip ')
608             sys.stderr.write(str(test))
609             sys.stderr.write('\n')
610         else:
611             sys.stderr.write('s')
612     def addError(self, test, err):
613         self.error_count += 1
614         TestResult.addError(self, test, err)
615         _, _exc_str = self.errors[-1]
616         output = self.complete_output()
617         self.result.append((2, test, output, _exc_str))
618         if self.verbosity > 1:
619             sys.stderr.write('E  ')
620             sys.stderr.write(str(test))
621             sys.stderr.write('\n')
622         else:
623             sys.stderr.write('E')
624  
625     def addFailure(self, test, err):
626         self.failure_count += 1
627         TestResult.addFailure(self, test, err)
628         _, _exc_str = self.failures[-1]
629         output = self.complete_output()
630         self.result.append((1, test, output, _exc_str))
631         if self.verbosity > 1:
632             sys.stderr.write('F  ')
633             sys.stderr.write(str(test))
634             sys.stderr.write('\n')
635         else:
636             sys.stderr.write('F')
637  
638  
639 class HTMLTestRunner(Template_mixin):
640     """
641     """
642     def __init__(self, stream=sys.stdout, verbosity=1, title=None, description=None,name=None):
643         self.stream = stream
644         self.verbosity = verbosity
645         if title is None:
646             self.title = self.DEFAULT_TITLE
647         else:
648             self.title = title
649         if name is None:
650             self.name =''
651         else:
652             self.name = name
653         if description is None:
654             self.description = self.DEFAULT_DESCRIPTION
655         else:
656             self.description = description
657  
658         self.startTime = datetime.datetime.now()
659  
660  
661     def run(self, test):
662         "Run the given test case or test suite."
663         result = _TestResult(self.verbosity)
664         test(result)
665         self.stopTime = datetime.datetime.now()
666         self.generateReport(test, result)
667         # print (sys.stderr, '\nTime Elapsed: %s' % (self.stopTime-self.startTime))
668         return result
669  
670  
671     def sortResult(self, result_list):
672         # unittest does not seems to run in any particular order.
673         # Here at least we want to group them together by class.
674         rmap = {}
675         classes = []
676         for n,t,o,e in result_list:
677             cls = t.__class__
678             if not cls in rmap:
679                 rmap[cls] = []
680                 classes.append(cls)
681             rmap[cls].append((n,t,o,e))
682         r = [(cls, rmap[cls]) for cls in classes]
683         return r
684  
685  
686     def getReportAttributes(self, result):
687         """
688         Return report attributes as a list of (name, value).
689         Override this to add custom attributes.
690         """
691         startTime = str(self.startTime)[:19]
692         duration = str(self.stopTime - self.startTime)
693         status = []
694         if result.success_count: status.append('Pass %s'    % result.success_count)
695         if result.failure_count: status.append('Failure %s' % result.failure_count)
696         if result.skipped_count: status.append('Skip %s' % result.skipped_count)
697         if result.error_count:   status.append('Error %s'   % result.error_count  )
698         if status:
699             status = ' '.join(status)
700         else:
701             status = 'none'
702         return [
703             ('Start Time', startTime),
704             ('Duration', duration),
705             ('Status', status),
706         ]
707  
708  
709     def generateReport(self, test, result):
710         report_attrs = self.getReportAttributes(result)#报告的头部
711         generator = 'HTMLTestRunner %s' % __version__
712         stylesheet = self._generate_stylesheet()#拿到css文件
713         heading = self._generate_heading(report_attrs)
714         report = self._generate_report(result)
715         ending = self._generate_ending()
716         output = self.HTML_TMPL % dict(
717             title = saxutils.escape(self.title),
718             generator = generator,
719             stylesheet = stylesheet,
720             heading = heading,
721             report = report,
722             ending = ending,
723         )
724         self.stream.write(output.encode('utf8'))
725  
726  
727     def _generate_stylesheet(self):
728         return self.STYLESHEET_TMPL
729  
730  
731     def _generate_heading(self, report_attrs):
732         a_lines = []
733         for name, value in report_attrs:
734             line = self.HEADING_ATTRIBUTE_TMPL % dict(
735                     name = saxutils.escape(name),
736                     value = saxutils.escape(value),
737                 )
738             a_lines.append(line)
739         heading = self.HEADING_TMPL % dict(
740             title = saxutils.escape(self.title),
741             parameters = ''.join(a_lines),
742             description = saxutils.escape(self.description),
743         )
744         return heading
745 #根据result收集报告
746     def _generate_report(self, result):
747         rows = []
748         sortedResult = self.sortResult(result.result)
749         i = 0
750         for cid, (cls, cls_results) in enumerate(sortedResult):
751             # subtotal for a class
752             np = nf =ns=ne = 0#np代表pass个数,nf代表fail,ns代表skip,ne,代表error
753             for n,t,o,e in cls_results:
754                 if n == 0: np += 1
755                 elif n == 1: nf += 1
756                 elif n==3:ns+=1
757                 else: ne += 1
758  
759             # format class description
760             # if cls.__module__ == "__main__":
761             #     name = cls.__name__
762             # else:
763             #     name = "%s.%s" % (cls.__module__, cls.__name__)
764             name = cls.__name__
765             try:
766                 core_name=self.name[i]
767             except Exception,e:
768                 core_name =''
769             # doc = (cls.__doc__)+core_name and (cls.__doc__+core_name).split("\n")[0] or ""
770             doc = (cls.__doc__)  and cls.__doc__ .split("\n")[0] or ""
771             desc = doc and '%s: %s' % (name, doc) or name
772             i=i+1            #生成每个TestCase类的汇总数据,对于报告中的
773             row = self.REPORT_CLASS_TMPL % dict(
774                 style = ne > 0 and 'errorClass' or nf > 0 and 'failClass' or 'passClass',
775                 desc = desc,
776                 count = np+nf+ne+ns,
777                 Pass = np,
778                 fail = nf,
779                 error = ne,
780                 skip=ns,
781                 cid = 'c%s' % (cid+1),
782             )
783             rows.append(row)
784             #生成每个TestCase类中所有方法的测试结果
785             for tid, (n,t,o,e) in enumerate(cls_results):
786                 self._generate_report_test(rows, cid, tid, n, t, o, e)
787  
788         report = self.REPORT_TMPL % dict(
789             test_list = ''.join(rows),
790             count = str(result.success_count+result.failure_count+result.error_count+result.skipped_count),
791             Pass = str(result.success_count),
792             fail = str(result.failure_count),
793             error = str(result.error_count),
794             skip=str(result.skipped_count)
795         )
796         return report
797  
798  
799     def _generate_report_test(self, rows, cid, tid, n, t, o, e):
800         # e.g. 'pt1.1', 'ft1.1', etc
801         has_output = bool(o or e)
802         tid = (n == 0 and 'p' or n==3 and 's' or 'f') + 't%s.%s' % (cid+1,tid+1)
803         name = t.id().split('.')[-1]
804         doc = t.shortDescription() or ""
805         desc = doc and ('%s: %s' % (name, doc)) or name
806         tmpl = has_output and self.REPORT_TEST_WITH_OUTPUT_TMPL or self.REPORT_TEST_NO_OUTPUT_TMPL
807         uo1=""
808         # o and e should be byte string because they are collected from stdout and stderr?
809         if isinstance(o,str):
810             uo = str(o)
811         else:
812             uo = e
813         if isinstance(e,str):
814             # TODO: some problem with 'string_escape': it escape \n and mess up formating
815             # ue = unicode(e.encode('string_escape'))
816             ue = e
817         else:
818             ue = o
819         script = self.REPORT_TEST_OUTPUT_TMPL % dict(
820             id = tid,
821             output = saxutils.escape(str(uo) + str(ue))
822         )
823         
824         if "shot_picture_name" in str(saxutils.escape(str(ue))):
825             hidde_status=''
826             pattern = re.compile(r'AssertionError:.*?shot_picture_name=(.*)',re.S)
827             shot_name =re.search(pattern,str(saxutils.escape(str(e))))
828             try:
829                 image_url="http://192.168.99.105/contractreport/screenshot/"+time.strftime("%Y-%m-%d", time.localtime(time.time()))+"/"+shot_name.group(1)+".png"
830             except Exception,e:
831                 image_url = "http://192.168.99.105/contractreport/screenshot/" + time.strftime("%Y-%m-%d",time.localtime(time.time()))
832  
833         else:
834             hidde_status = '''hidden="hidden"'''
835             image_url=''
836         row = tmpl % dict(
837             tid = tid,
838             Class = (n == 0 and 'hiddenRow' or 'none'),
839             style=n == 2 and 'errorCase' or (n == 1 and 'failCase') or (n == 3 and 'skipCase' or 'none'),
840             desc = desc,
841             script = script,
842             hidde=hidde_status,
843         image=image_url,
844             status = self.STATUS[n],
845         )
846  
847         rows.append(row)
848         if not has_output:
849             return
850  
851     def _generate_ending(self):
852         return self.ENDING_TMPL
853  
854  
855 ##############################################################################
856 # Facilities for running tests from the command line
857 ##############################################################################
858  
859 # Note: Reuse unittest.TestProgram to launch test. In the future we may
860 # build our own launcher to support more specific command line
861 # parameters like test title, CSS, etc.
862 # class TestProgram(unittest.TestProgram):
863 #     """
864 #     A variation of the unittest.TestProgram. Please refer to the base
865 #     class for command line parameters.
866 #     """
867 #     def runTests(self):
868 #         # Pick HTMLTestRunner as the default test runner.
869 #         # base class's testRunner parameter is not useful because it means
870 #         # we have to instantiate HTMLTestRunner before we know self.verbosity.
871 #         if self.testRunner is None:
872 #             self.testRunner = HTMLTestRunner(verbosity=self.verbosity)
873 #         unittest.TestProgram.runTests(self)
874 #
875 # main = TestProgram
876  
877 ##############################################################################
878 # Executing this module from the command line
879 ##############################################################################
880  
881 if __name__ == "__main__":
882     main(module=None)

测试SKIP代码

 1 #coding=utf-8
 2 import unittest
 3 # import HTMLTestRunner
 4 import HTMLTestRunner_python2
 5 import time
 6 import sys,os
 7 
 8 class Mydemo(unittest.TestCase):
 9     def test1(self):
10         print "excute test1"
11     @unittest.Myskip
12     def test2(self):
13         print "excute test2"
14 
15     @unittest.Myskip
16     def test3(self):
17         print "excute test3"
18         raise AssertionError("test3 fail")
19     @unittest.Myskip
20     def test4(self):
21         print "excute test4"
22 
23 
24 def suite():
25     #添加测试用例
26     suiteTest=unittest.TestSuite()
27     # suiteTest.addTest(Mydemo("test1"))
28     # suiteTest.addTest(Mydemo("test2"))
29     # suiteTest.addTest(Mydemo("test3"))
30     # suiteTest.addTest(Mydemo("test4"))
31     suiteTest.addTests(map(Mydemo,["test1","test2","test3","test4"]))
32     return suiteTest
33 
34 if __name__=='__main__':
35     # unittest.main()
36     now = time.strftime("%Y-%m-%d-%H_%M_%S", time.localtime(time.time()))
37     filepath = r'D:\Python\report\{0}result.html'.format(now)
38     print(filepath)
39     fp = file(filepath, 'wb')
40 
41     # 定义测试报告的标题与描述
42     runner = HTMLTestRunner_python2.HTMLTestRunner(stream=fp, title=u'单元测试用例', description=u'测试执行情况')
43     #执行测试用例
44     runner.run(suite())
45     fp.close()

 

测试结果如图所示:

 

posted @ 2018-03-16 11:13  yye_2010  阅读(334)  评论(0编辑  收藏  举报