C:Python27Lib中修改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:Python27Lib修改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(" "); 293 d.write("<a href='javascript:window.close()'>close</a> "); 294 d.write("</pre> "); 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 600px; 362 } 363 364 } 365 /* -- report ------------------------------------------------------------------------ */ 366 #show_detail_line { 367 margin-top: 3ex; 368 margin-bottom: 1ex; 369 } 370 #result_table { 371 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(' ') 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(' ') 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(' ') 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(' ') 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, ' Time 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(" ")[0] or "" 770 doc = (cls.__doc__) and cls.__doc__ .split(" ")[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 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 eport{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()
测试结果如图所示: