├── .idea ├── Daemon_.iml ├── misc.xml ├── modules.xml └── vcs.xml ├── README.md ├── config ├── __init__.py ├── config.yml └── db_config.ini ├── data ├── __init__.py └── baidu.xlsx ├── db ├── __init__.py └── mongo_db.py ├── drivers ├── IEDriverServer.exe ├── chromedriver.exe └── phantomjs.exe ├── emaill └── mail.py ├── geckodriver.log ├── htmltestrunner ├── HTMLTestRunner.py ├── HTMLTestRunner_in.py └── __init__.py ├── report ├── 2018-04-13 11_27_17_result.html ├── 2018-04-13 11_33_34_result.html ├── 2018-04-13 11_34_55_result.html ├── 2018-04-13 13_06_08_result.html └── screenpicture │ ├── 20180413112728.png │ ├── 20180413113348.png │ ├── 20180413113506.png │ └── 20180413130657.png ├── run.py ├── src ├── __init__.py ├── test │ ├── __init__.py │ ├── case │ │ ├── __init__.py │ │ ├── geckodriver.log │ │ ├── test_ad_position.py │ │ ├── test_baidu.py │ │ └── test_login.py │ ├── common │ │ ├── __init__.py │ │ └── base_page.py │ └── suit │ │ ├── __init__.py │ │ ├── aquapaasADV │ │ ├── __init__.py │ │ ├── ad_position_page.py │ │ └── login_page.py │ │ ├── baidu │ │ ├── __init__.py │ │ └── search_page.py │ │ └── docker_interface │ │ └── __init__.py └── utils │ ├── __init__.py │ ├── browser.py │ ├── config.py │ ├── file_reader.py │ ├── geckodriver.log │ └── log.py └── test.py /.idea/Daemon_.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Daemon_AutoFramework 2 | web自动化测试框架 3 | -------------------------------------------------------------------------------- /config/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2018/4/11 10:32 4 | # @Author : huanghe 5 | # @Site : 6 | # @File : __init__.py.py 7 | # @Software: PyCharm -------------------------------------------------------------------------------- /config/config.yml: -------------------------------------------------------------------------------- 1 | URL: http://10.50.4.115:8080/paasadv/ 2 | USER: root 3 | PASSWORD: 123 4 | BaiDuURl: https://www.baidu.com/ 5 | log: 6 | file_name: test.log 7 | backup: 5INFO 8 | console_level: DEBUG 9 | file_level: DEBUG 10 | pattern: '%(asctime)s - %(name)s - %(levelname)s - %(message)s' 11 | 12 | mongodb: 13 | host: 39.106.144.46 14 | port: 27017 15 | user: 16 | password: -------------------------------------------------------------------------------- /config/db_config.ini: -------------------------------------------------------------------------------- 1 | [mongoconf] 2 | host=39.106.144.46 3 | port=27017 4 | user= 5 | password= -------------------------------------------------------------------------------- /data/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2018/4/11 10:33 4 | # @Author : huanghe 5 | # @Site : 6 | # @File : __init__.py.py 7 | # @Software: PyCharm -------------------------------------------------------------------------------- /data/baidu.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smarthaut/Daemon_AutoFramework/49dd148173b294ff33079c7ac284ae00723b82ed/data/baidu.xlsx -------------------------------------------------------------------------------- /db/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2018/4/13 13:09 4 | # @Author : huanghe 5 | # @Site : 6 | # @File : __init__.py.py 7 | # @Software: PyCharm -------------------------------------------------------------------------------- /db/mongo_db.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2018/4/13 13:11 4 | # @Author : huanghe 5 | # @Site : 6 | # @File : mongo_db.py 7 | # @Software: PyCharm 8 | import pymongo 9 | from src.utils.config import Config 10 | 11 | class DB: 12 | def __init__(self): 13 | cf = Config().get('mongodb') 14 | self.host = cf.get('host') 15 | self.port = cf.get('port') 16 | self.user = cf.get('user') 17 | self.password = cf.get('password') 18 | try: 19 | self.client = pymongo.MongoClient(self.host, port=int(self.port)) 20 | except: 21 | print('数据库连接失败') 22 | 23 | def getConnection(self, table_name, connection_name): 24 | db = self.client.get_database(table_name) 25 | svod = db.get_collection(connection_name) 26 | return svod 27 | 28 | 29 | if __name__ =='__main__': 30 | db =DB() 31 | print(db.host) -------------------------------------------------------------------------------- /drivers/IEDriverServer.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smarthaut/Daemon_AutoFramework/49dd148173b294ff33079c7ac284ae00723b82ed/drivers/IEDriverServer.exe -------------------------------------------------------------------------------- /drivers/chromedriver.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smarthaut/Daemon_AutoFramework/49dd148173b294ff33079c7ac284ae00723b82ed/drivers/chromedriver.exe -------------------------------------------------------------------------------- /drivers/phantomjs.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smarthaut/Daemon_AutoFramework/49dd148173b294ff33079c7ac284ae00723b82ed/drivers/phantomjs.exe -------------------------------------------------------------------------------- /emaill/mail.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2018/4/16 10:03 4 | # @Author : huanghe 5 | # @Site : 6 | # @File : mail.py 7 | # @Software: PyCharm 8 | import smtplib 9 | from email.mime.text import MIMEText 10 | from email import encoders 11 | from email.header import Header 12 | from email.mime.multipart import MIMEMultipart 13 | from email.mime.base import MIMEBase 14 | from email.utils import parseaddr,formataddr 15 | 16 | 17 | 18 | class Email: 19 | def __init__(self,server,sender,password,receiver,subject,title=None,message=None,path=None): 20 | self.server = server 21 | self.sender = sender 22 | self.password = password 23 | self.receiver = receiver 24 | self.subject = subject 25 | self.msg = MIMEMultipart() 26 | #self.msg = MIMEText(msg,'plain','utf-8') 27 | 28 | def _format_addr(self,s): 29 | name,addr = parseaddr(s) 30 | return formataddr((Header(name,'utf-8').encode(),addr)) 31 | 32 | def send(self): 33 | server = smtplib.SMTP(self.server,25) 34 | server.set_debuglevel(1) 35 | server.login(self.sender,self.password) 36 | server.sendmail(self.sender,[self.receiver],self.msg.as_string()) 37 | server.quit() 38 | 39 | def add_fujian(self,filepath): 40 | with open(filepath,'rb')as f: 41 | mime = MIMEBase('image','png',filename='test.png') 42 | mime.add_header('Content-Disposition', 'attachment',filename='test.png') 43 | mime.add_header('Content-ID', '<0>') 44 | mime.add_header('X-Attachment-Id', '0') 45 | mime.set_payload(f.read()) 46 | encoders.encode_base64(mime) 47 | self.msg.attach(mime) 48 | 49 | def set_content(self,msg): 50 | self.msg['From'] = self._format_addr('发件人<{}>'.format(self.sender)) 51 | self.msg['To'] = self._format_addr('收件人<{}>'.format(self.receiver)) 52 | self.msg['Subject'] = Header(self.subject, 'utf-8').encode() 53 | self.msg.attach(MIMEText(msg,'plain','utf-8')) 54 | 55 | 56 | if __name__ == '__main__': 57 | msg = 'helllo' 58 | email = Email(server='mail.xor-media.tv',sender='he.huang@xor-media.tv',password='2953653ABCDE' 59 | ,receiver='943298665@qq.com',subject='主题') 60 | email.set_content(msg) 61 | email.add_fujian('test.png') 62 | #name,addr = parseaddr('Python爱好者') 63 | #print(formataddr((Header(name,'utf-8').encode(),addr))) 64 | email.send() -------------------------------------------------------------------------------- /htmltestrunner/HTMLTestRunner.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2017/12/28 11:43 4 | # @Author : huanghe 5 | # @Site : 6 | # @File : HTMLTestRunner.py 7 | # @Software: PyCharm 8 | #coding=utf-8 9 | """ 10 | A TestRunner for use with the Python unit testing framework. It 11 | generates a HTML report to show the result at a glance. 12 | 13 | The simplest way to use this is to invoke its main method. E.g. 14 | 15 | import unittest 16 | import HTMLTestRunner 17 | 18 | ... define your tests ... 19 | 20 | if __name__ == '__main__': 21 | HTMLTestRunner.main() 22 | 23 | 24 | For more customization options, instantiates a HTMLTestRunner object. 25 | HTMLTestRunner is a counterpart to unittest's TextTestRunner. E.g. 26 | 27 | # output to a file 28 | fp = file('my_report.html', 'wb') 29 | runner = HTMLTestRunner.HTMLTestRunner( 30 | stream=fp, 31 | title='My unit test', 32 | description='This demonstrates the report output by HTMLTestRunner.' 33 | ) 34 | 35 | # Use an external stylesheet. 36 | # See the Template_mixin class for more customizable options 37 | runner.STYLESHEET_TMPL = '' 38 | 39 | # run the test 40 | runner.run(my_test_suite) 41 | 42 | 43 | ------------------------------------------------------------------------ 44 | Copyright (c) 2004-2007, Wai Yip Tung 45 | All rights reserved. 46 | 47 | Redistribution and use in source and binary forms, with or without 48 | modification, are permitted provided that the following conditions are 49 | met: 50 | 51 | * Redistributions of source code must retain the above copyright notice, 52 | this list of conditions and the following disclaimer. 53 | * Redistributions in binary form must reproduce the above copyright 54 | notice, this list of conditions and the following disclaimer in the 55 | documentation and/or other materials provided with the distribution. 56 | * Neither the name Wai Yip Tung nor the names of its contributors may be 57 | used to endorse or promote products derived from this software without 58 | specific prior written permission. 59 | 60 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 61 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 62 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 63 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 64 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 65 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 66 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 67 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 68 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 69 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 70 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 71 | """ 72 | 73 | # URL: http://tungwaiyip.info/software/HTMLTestRunner.html 74 | 75 | __author__ = "Wai Yip Tung, Findyou" 76 | __version__ = "0.8.2.2" 77 | 78 | 79 | """ 80 | Change History 81 | Version 0.8.2.2-huanghe 82 | *添加截图展示功能 83 | 84 | Version 0.8.2.1 -Findyou 85 | * 改为支持python3 86 | 87 | Version 0.8.2.1 -Findyou 88 | * 支持中文,汉化 89 | * 调整样式,美化(需要连入网络,使用的百度的Bootstrap.js) 90 | * 增加 通过分类显示、测试人员、通过率的展示 91 | * 优化“详细”与“收起”状态的变换 92 | * 增加返回顶部的锚点 93 | 94 | Version 0.8.2 95 | * Show output inline instead of popup window (Viorel Lupu). 96 | 97 | Version in 0.8.1 98 | * Validated XHTML (Wolfgang Borgert). 99 | * Added description of test classes and test cases. 100 | 101 | Version in 0.8.0 102 | * Define Template_mixin class for customization. 103 | * Workaround a IE 6 bug that it does not treat 213 | 214 | %(stylesheet)s 215 | 216 | 217 | 302 | %(heading)s 303 | %(report)s 304 | %(ending)s 305 | 306 | 307 | 308 | """ 309 | # variables: (title, generator, stylesheet, heading, report, ending) 310 | 311 | 312 | # ------------------------------------------------------------------------ 313 | # Stylesheet 314 | # 315 | # alternatively use a for external style sheet, e.g. 316 | # 317 | 318 | STYLESHEET_TMPL = """ 319 | 342 | """ 343 | 344 | # ------------------------------------------------------------------------ 345 | # Heading 346 | # 347 | 348 | HEADING_TMPL = """
349 |

%(title)s

350 | %(parameters)s 351 |

%(description)s

352 |
353 | 354 | """ # variables: (title, parameters, description) 355 | 356 | HEADING_ATTRIBUTE_TMPL = """

%(name)s : %(value)s

357 | """ # variables: (name, value) 358 | 359 | 360 | 361 | # ------------------------------------------------------------------------ 362 | # Report 363 | # 364 | # 汉化,加美化效果 --Findyou 365 | REPORT_TMPL = """ 366 |

367 | 概要{ %(passrate)s } 368 | 失败{ %(fail)s } 369 | 通过{ %(Pass)s } 370 | 所有{ %(count)s } 371 |

372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | %(test_list)s 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 |
用例集/测试用例总计通过失败错误详细
总计%(count)s%(Pass)s%(fail)s%(error)s通过率:%(passrate)s
399 | """ # variables: (test_list, count, Pass, fail, error ,passrate) 400 | 401 | REPORT_CLASS_TMPL = r""" 402 | 403 | %(desc)s 404 | %(count)s 405 | %(Pass)s 406 | %(fail)s 407 | %(error)s 408 | 详细 409 | 410 | """ # variables: (style, desc, count, Pass, fail, error, cid) 411 | 412 | #失败 的样式,去掉原来JS效果,美化展示效果 -Findyou 413 | REPORT_TEST_WITH_OUTPUT_TMPL = r""" 414 | 415 |
%(desc)s
416 | 417 | 420 | 421 | 422 | 423 |
424 |
425 |     %(script)s
426 |     
427 |
428 | 429 | 430 | """ # variables: (tid, Class, style, desc, status) 431 | 432 | # 通过 的样式,加标签效果 -Findyou 433 | REPORT_TEST_NO_OUTPUT_TMPL=r""" 434 | 435 |
%(desc)s
436 | 437 | 440 | 441 | 442 | 443 |
444 |
445 |     %(script)s
446 |     
447 |
448 | 449 | 450 | """ 451 | REPORT_TEST_NO_OUTPUT_TMPL01 = r""" 452 | 453 |
%(desc)s
454 | %(status)s 455 | 456 | 457 | """ # variables: (tid, Class, style, desc, status) 458 | 459 | REPORT_TEST_OUTPUT_TMPL = r""" 460 | %(id)s: %(output)s测试通过 461 | picture_shot 462 | picture_shot 463 | """ # variables: (id, output) 464 | 465 | # ------------------------------------------------------------------------ 466 | # ENDING 467 | # 468 | # 增加返回顶部按钮 --Findyou 469 | ENDING_TMPL = """
 
470 |
471 |
473 | """ 474 | 475 | # -------------------- The end of the Template class ------------------- 476 | 477 | 478 | TestResult = unittest.TestResult 479 | 480 | class _TestResult(TestResult): 481 | # note: _TestResult is a pure representation of results. 482 | # It lacks the output and reporting ability compares to unittest._TextTestResult. 483 | 484 | def __init__(self, verbosity=1): 485 | TestResult.__init__(self) 486 | self.stdout0 = None 487 | self.stderr0 = None 488 | self.success_count = 0 489 | self.failure_count = 0 490 | self.error_count = 0 491 | self.verbosity = verbosity 492 | 493 | # result is a list of result in 4 tuple 494 | # ( 495 | # result code (0: success; 1: fail; 2: error), 496 | # TestCase object, 497 | # Test output (byte string), 498 | # stack trace, 499 | # ) 500 | self.result = [] 501 | #增加一个测试通过率 --Findyou 502 | self.passrate=float(0) 503 | 504 | 505 | def startTest(self, test): 506 | TestResult.startTest(self, test) 507 | # just one buffer for both stdout and stderr 508 | self.outputBuffer = io.StringIO() 509 | stdout_redirector.fp = self.outputBuffer 510 | stderr_redirector.fp = self.outputBuffer 511 | self.stdout0 = sys.stdout 512 | self.stderr0 = sys.stderr 513 | sys.stdout = stdout_redirector 514 | sys.stderr = stderr_redirector 515 | 516 | 517 | def complete_output(self): 518 | """ 519 | Disconnect output redirection and return buffer. 520 | Safe to call multiple times. 521 | """ 522 | if self.stdout0: 523 | sys.stdout = self.stdout0 524 | sys.stderr = self.stderr0 525 | self.stdout0 = None 526 | self.stderr0 = None 527 | return self.outputBuffer.getvalue() 528 | 529 | 530 | def stopTest(self, test): 531 | # Usually one of addSuccess, addError or addFailure would have been called. 532 | # But there are some path in unittest that would bypass this. 533 | # We must disconnect stdout in stopTest(), which is guaranteed to be called. 534 | self.complete_output() 535 | 536 | 537 | def addSuccess(self, test): 538 | self.success_count += 1 539 | TestResult.addSuccess(self, test) 540 | output = self.complete_output() 541 | self.result.append((0, test, output, '')) 542 | if self.verbosity > 1: 543 | sys.stderr.write('ok ') 544 | sys.stderr.write(str(test)) 545 | sys.stderr.write('\n') 546 | else: 547 | sys.stderr.write('.') 548 | 549 | def addError(self, test, err): 550 | self.error_count += 1 551 | TestResult.addError(self, test, err) 552 | _, _exc_str = self.errors[-1] 553 | output = self.complete_output() 554 | self.result.append((2, test, output, _exc_str)) 555 | if self.verbosity > 1: 556 | sys.stderr.write('E ') 557 | sys.stderr.write(str(test)) 558 | sys.stderr.write('\n') 559 | else: 560 | sys.stderr.write('E') 561 | 562 | def addFailure(self, test, err): 563 | self.failure_count += 1 564 | TestResult.addFailure(self, test, err) 565 | _, _exc_str = self.failures[-1] 566 | output = self.complete_output() 567 | self.result.append((1, test, output, _exc_str)) 568 | if self.verbosity > 1: 569 | sys.stderr.write('F ') 570 | sys.stderr.write(str(test)) 571 | sys.stderr.write('\n') 572 | else: 573 | sys.stderr.write('F') 574 | 575 | 576 | class HTMLTestRunner(Template_mixin): 577 | """ 578 | """ 579 | def __init__(self, stream=sys.stdout, verbosity=1,title=None,description=None,tester=None): 580 | self.stream = stream 581 | self.verbosity = verbosity 582 | if title is None: 583 | self.title = self.DEFAULT_TITLE 584 | else: 585 | self.title = title 586 | if description is None: 587 | self.description = self.DEFAULT_DESCRIPTION 588 | else: 589 | self.description = description 590 | if tester is None: 591 | self.tester = self.DEFAULT_TESTER 592 | else: 593 | self.tester = tester 594 | 595 | self.startTime = datetime.datetime.now() 596 | 597 | 598 | def run(self, test): 599 | "Run the given test case or test suite." 600 | result = _TestResult(self.verbosity) 601 | test(result) 602 | self.stopTime = datetime.datetime.now() 603 | self.generateReport(test, result) 604 | print('\nTime Elapsed: %s' % (self.stopTime-self.startTime), file=sys.stderr) 605 | return result 606 | 607 | 608 | def sortResult(self, result_list): 609 | # unittest does not seems to run in any particular order. 610 | # Here at least we want to group them together by class. 611 | rmap = {} 612 | classes = [] 613 | for n,t,o,e in result_list: 614 | cls = t.__class__ 615 | if cls not in rmap: 616 | rmap[cls] = [] 617 | classes.append(cls) 618 | rmap[cls].append((n,t,o,e)) 619 | r = [(cls, rmap[cls]) for cls in classes] 620 | return r 621 | 622 | #替换测试结果status为通过率 --Findyou 623 | def getReportAttributes(self, result): 624 | """ 625 | Return report attributes as a list of (name, value). 626 | Override this to add custom attributes. 627 | """ 628 | startTime = str(self.startTime)[:19] 629 | duration = str(self.stopTime - self.startTime) 630 | status = [] 631 | status.append('共 %s' % (result.success_count + result.failure_count + result.error_count)) 632 | if result.success_count: status.append('通过 %s' % result.success_count) 633 | if result.failure_count: status.append('失败 %s' % result.failure_count) 634 | if result.error_count: status.append('错误 %s' % result.error_count ) 635 | if status: 636 | status = ','.join(status) 637 | self.passrate = str("%.2f%%" % (float(result.success_count) / float(result.success_count + result.failure_count + result.error_count) * 100)) 638 | else: 639 | status = 'none' 640 | return [ 641 | ('测试人员', self.tester), 642 | ('开始时间',startTime), 643 | ('合计耗时',duration), 644 | ('测试结果',status + ",通过率= "+self.passrate), 645 | ] 646 | 647 | 648 | def generateReport(self, test, result): 649 | report_attrs = self.getReportAttributes(result) 650 | generator = 'HTMLTestRunner %s' % __version__ 651 | stylesheet = self._generate_stylesheet() 652 | heading = self._generate_heading(report_attrs) 653 | report = self._generate_report(result) 654 | ending = self._generate_ending() 655 | output = self.HTML_TMPL % dict( 656 | title = saxutils.escape(self.title), 657 | generator = generator, 658 | stylesheet = stylesheet, 659 | heading = heading, 660 | report = report, 661 | ending = ending, 662 | ) 663 | self.stream.write(output.encode('utf8')) 664 | 665 | 666 | def _generate_stylesheet(self): 667 | return self.STYLESHEET_TMPL 668 | 669 | #增加Tester显示 -Findyou 670 | def _generate_heading(self, report_attrs): 671 | a_lines = [] 672 | for name, value in report_attrs: 673 | line = self.HEADING_ATTRIBUTE_TMPL % dict( 674 | name = saxutils.escape(name), 675 | value = saxutils.escape(value), 676 | ) 677 | a_lines.append(line) 678 | heading = self.HEADING_TMPL % dict( 679 | title = saxutils.escape(self.title), 680 | parameters = ''.join(a_lines), 681 | description = saxutils.escape(self.description), 682 | tester= saxutils.escape(self.tester), 683 | ) 684 | return heading 685 | 686 | #生成报告 --Findyou添加注释 687 | def _generate_report(self, result): 688 | rows = [] 689 | sortedResult = self.sortResult(result.result) 690 | for cid, (cls, cls_results) in enumerate(sortedResult): 691 | # subtotal for a class 692 | np = nf = ne = 0 693 | for n,t,o,e in cls_results: 694 | if n == 0: np += 1 695 | elif n == 1: nf += 1 696 | else: ne += 1 697 | 698 | # format class description 699 | if cls.__module__ == "__main__": 700 | name = cls.__name__ 701 | else: 702 | name = "%s.%s" % (cls.__module__, cls.__name__) 703 | doc = cls.__doc__ and cls.__doc__.split("\n")[0] or "" 704 | desc = doc and '%s: %s' % (name, doc) or name 705 | 706 | row = self.REPORT_CLASS_TMPL % dict( 707 | style = ne > 0 and 'errorClass' or nf > 0 and 'failClass' or 'passClass', 708 | desc = desc, 709 | count = np+nf+ne, 710 | Pass = np, 711 | fail = nf, 712 | error = ne, 713 | cid = 'c%s' % (cid+1), 714 | ) 715 | rows.append(row) 716 | 717 | for tid, (n,t,o,e) in enumerate(cls_results): 718 | self._generate_report_test(rows, cid, tid, n, t, o, e) 719 | 720 | report = self.REPORT_TMPL % dict( 721 | test_list = ''.join(rows), 722 | count = str(result.success_count+result.failure_count+result.error_count), 723 | Pass = str(result.success_count), 724 | fail = str(result.failure_count), 725 | error = str(result.error_count), 726 | passrate =self.passrate, 727 | ) 728 | return report 729 | 730 | 731 | def _generate_report_test(self, rows, cid, tid, n, t, o, e): 732 | #o print的内容 733 | #e 抛出的异常信息 734 | #t 具体的测试用例情况 735 | # e.g. 'pt1.1', 'ft1.1', etc 736 | unum = -1 737 | imguo = None 738 | #has_output = bool(o or e) 739 | has_output = bool(e) 740 | #当有print输入或者有异常抛出时都采用REPORT_TEST_WITH_OUTPUT_TMPL 741 | #has_output = bool(o and e) 742 | # ID修改点为下划线,支持Bootstrap折叠展开特效 - Findyou 743 | tid = (n == 0 and 'p' or 'f') + 't%s_%s' % (cid+1,tid+1) 744 | #tid = '%s_%s' % (cid+1,tid+1) 745 | name = t.id().split('.')[-1] 746 | doc = t.shortDescription() or "" 747 | desc = doc and ('%s: %s' % (name, doc)) or name 748 | tmpl = has_output and self.REPORT_TEST_WITH_OUTPUT_TMPL or self.REPORT_TEST_NO_OUTPUT_TMPL 749 | 750 | # utf-8 支持中文 - Findyou 751 | # o and e should be byte string because they are collected from stdout and stderr? 752 | if isinstance(o, str): 753 | # TODO: some problem with 'string_escape': it escape \n and mess up formating 754 | # uo = unicode(o.encode('string_escape')) 755 | # uo = o.decode('latin-1') 756 | uo = o 757 | else: 758 | uo = o 759 | if isinstance(e, str): 760 | # TODO: some problem with 'string_escape': it escape \n and mess up formating 761 | # ue = unicode(e.encode('string_escape')) 762 | # ue = e.decode('latin-1') 763 | ue = e 764 | else: 765 | ue = e 766 | '''helist = ['DEBUG','INFO','WARNING','ERROR','CRITICAL'] 767 | for i in range(5): 768 | numt = str(uo).find(helist[i]) 769 | if numt: 770 | print(uo)''' 771 | hidde_status = '''hidden="hidden"''' 772 | image_url = '' 773 | for heuo in str(uo).split('\n'): 774 | if heuo.find('screenpicture') != -1: 775 | hidde_status = '' 776 | image_url = 'file:///'+heuo 777 | else: 778 | print(heuo) 779 | hidde_status = hidde_status 780 | image_url = image_url 781 | # 插入图片 782 | #unum = str(uo).find('screenpicture') 783 | 784 | #if (uo and unum != -1): 785 | 786 | script = self.REPORT_TEST_OUTPUT_TMPL % dict( 787 | id = tid[2:], 788 | #output = saxutils.escape(uo+ue), 789 | output = saxutils.escape(ue), 790 | hidde=hidde_status, 791 | image=image_url, 792 | ) 793 | 794 | row = tmpl % dict( 795 | tid = tid, 796 | Class = (n == 0 and 'hiddenRow' or 'none'), 797 | style = n == 2 and 'errorCase' or (n == 1 and 'failCase' or 'passCase'), 798 | desc = desc, 799 | script = script, 800 | hidde = hidde_status, 801 | image = image_url, 802 | status = self.STATUS[n], 803 | ) 804 | rows.append(row) 805 | if not has_output: 806 | return 807 | 808 | def _generate_ending(self): 809 | return self.ENDING_TMPL 810 | 811 | 812 | ############################################################################## 813 | # Facilities for running tests from the command line 814 | ############################################################################## 815 | 816 | # Note: Reuse unittest.TestProgram to launch test. In the future we may 817 | # build our own launcher to support more specific command line 818 | # parameters like test title, CSS, etc. 819 | class TestProgram(unittest.TestProgram): 820 | """ 821 | A variation of the unittest.TestProgram. Please refer to the base 822 | class for command line parameters. 823 | """ 824 | def runTests(self): 825 | # Pick HTMLTestRunner as the default test runner. 826 | # base class's testRunner parameter is not useful because it means 827 | # we have to instantiate HTMLTestRunner before we know self.verbosity. 828 | if self.testRunner is None: 829 | self.testRunner = HTMLTestRunner(verbosity=self.verbosity) 830 | unittest.TestProgram.runTests(self) 831 | 832 | main = TestProgram 833 | 834 | ############################################################################## 835 | # Executing this module from the command line 836 | ############################################################################## 837 | 838 | if __name__ == "__main__": 839 | main(module=None) 840 | -------------------------------------------------------------------------------- /htmltestrunner/HTMLTestRunner_in.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 | 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 = '' 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, Findyou" 69 | __version__ = "0.8.2.2" 70 | 71 | 72 | """ 73 | Change History 74 | Version 0.8.2.1 -Findyou 75 | * 改为支持python3 76 | 77 | Version 0.8.2.1 -Findyou 78 | * 支持中文,汉化 79 | * 调整样式,美化(需要连入网络,使用的百度的Bootstrap.js) 80 | * 增加 通过分类显示、测试人员、通过率的展示 81 | * 优化“详细”与“收起”状态的变换 82 | * 增加返回顶部的锚点 83 | 84 | Version 0.8.2 85 | * Show output inline instead of popup window (Viorel Lupu). 86 | 87 | Version in 0.8.1 88 | * Validated XHTML (Wolfgang Borgert). 89 | * Added description of test classes and test cases. 90 | 91 | Version in 0.8.0 92 | * Define Template_mixin class for customization. 93 | * Workaround a IE 6 bug that it does not treat 204 | 205 | %(stylesheet)s 206 | 207 | 208 | 293 | %(heading)s 294 | %(report)s 295 | %(ending)s 296 | 297 | 298 | 299 | """ 300 | # variables: (title, generator, stylesheet, heading, report, ending) 301 | 302 | 303 | # ------------------------------------------------------------------------ 304 | # Stylesheet 305 | # 306 | # alternatively use a for external style sheet, e.g. 307 | # 308 | 309 | STYLESHEET_TMPL = """ 310 | 333 | """ 334 | 335 | # ------------------------------------------------------------------------ 336 | # Heading 337 | # 338 | 339 | HEADING_TMPL = """
340 |

%(title)s

341 | %(parameters)s 342 |

%(description)s

343 |
344 | 345 | """ # variables: (title, parameters, description) 346 | 347 | HEADING_ATTRIBUTE_TMPL = """

%(name)s : %(value)s

348 | """ # variables: (name, value) 349 | 350 | 351 | 352 | # ------------------------------------------------------------------------ 353 | # Report 354 | # 355 | # 汉化,加美化效果 --Findyou 356 | REPORT_TMPL = """ 357 |

358 | 概要{ %(passrate)s } 359 | 失败{ %(fail)s } 360 | 通过{ %(Pass)s } 361 | 所有{ %(count)s } 362 |

363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | %(test_list)s 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 |
用例集/测试用例总计通过失败错误详细
总计%(count)s%(Pass)s%(fail)s%(error)s通过率:%(passrate)s
390 | """ # variables: (test_list, count, Pass, fail, error ,passrate) 391 | 392 | REPORT_CLASS_TMPL = r""" 393 | 394 | %(desc)s 395 | %(count)s 396 | %(Pass)s 397 | %(fail)s 398 | %(error)s 399 | 详细 400 | 401 | """ # variables: (style, desc, count, Pass, fail, error, cid) 402 | 403 | #失败 的样式,去掉原来JS效果,美化展示效果 -Findyou 404 | REPORT_TEST_WITH_OUTPUT_TMPL = r""" 405 | 406 |
%(desc)s
407 | 408 | 411 | 412 | 413 | 414 |
415 |
416 |     %(script)s
417 |     
418 |
419 | 420 | 421 | """ # variables: (tid, Class, style, desc, status) 422 | 423 | # 通过 的样式,加标签效果 -Findyou 424 | REPORT_TEST_NO_OUTPUT_TMPL = r""" 425 | 426 |
%(desc)s
427 | %(status)s 428 | 429 | """ # variables: (tid, Class, style, desc, status) 430 | 431 | REPORT_TEST_OUTPUT_TMPL = r""" 432 | %(id)s: %(output)s 433 | """ # variables: (id, output) 434 | 435 | # ------------------------------------------------------------------------ 436 | # ENDING 437 | # 438 | # 增加返回顶部按钮 --Findyou 439 | ENDING_TMPL = """
 
440 |
441 |
443 | """ 444 | 445 | # -------------------- The end of the Template class ------------------- 446 | 447 | 448 | TestResult = unittest.TestResult 449 | 450 | class _TestResult(TestResult): 451 | # note: _TestResult is a pure representation of results. 452 | # It lacks the output and reporting ability compares to unittest._TextTestResult. 453 | 454 | def __init__(self, verbosity=1): 455 | TestResult.__init__(self) 456 | self.stdout0 = None 457 | self.stderr0 = None 458 | self.success_count = 0 459 | self.failure_count = 0 460 | self.error_count = 0 461 | self.verbosity = verbosity 462 | 463 | # result is a list of result in 4 tuple 464 | # ( 465 | # result code (0: success; 1: fail; 2: error), 466 | # TestCase object, 467 | # Test output (byte string), 468 | # stack trace, 469 | # ) 470 | self.result = [] 471 | #增加一个测试通过率 --Findyou 472 | self.passrate=float(0) 473 | 474 | 475 | def startTest(self, test): 476 | TestResult.startTest(self, test) 477 | # just one buffer for both stdout and stderr 478 | self.outputBuffer = io.StringIO() 479 | stdout_redirector.fp = self.outputBuffer 480 | stderr_redirector.fp = self.outputBuffer 481 | self.stdout0 = sys.stdout 482 | self.stderr0 = sys.stderr 483 | sys.stdout = stdout_redirector 484 | sys.stderr = stderr_redirector 485 | 486 | 487 | def complete_output(self): 488 | """ 489 | Disconnect output redirection and return buffer. 490 | Safe to call multiple times. 491 | """ 492 | if self.stdout0: 493 | sys.stdout = self.stdout0 494 | sys.stderr = self.stderr0 495 | self.stdout0 = None 496 | self.stderr0 = None 497 | return self.outputBuffer.getvalue() 498 | 499 | 500 | def stopTest(self, test): 501 | # Usually one of addSuccess, addError or addFailure would have been called. 502 | # But there are some path in unittest that would bypass this. 503 | # We must disconnect stdout in stopTest(), which is guaranteed to be called. 504 | self.complete_output() 505 | 506 | 507 | def addSuccess(self, test): 508 | self.success_count += 1 509 | TestResult.addSuccess(self, test) 510 | output = self.complete_output() 511 | self.result.append((0, test, output, '')) 512 | if self.verbosity > 1: 513 | sys.stderr.write('ok ') 514 | sys.stderr.write(str(test)) 515 | sys.stderr.write('\n') 516 | else: 517 | sys.stderr.write('.') 518 | 519 | def addError(self, test, err): 520 | self.error_count += 1 521 | TestResult.addError(self, test, err) 522 | _, _exc_str = self.errors[-1] 523 | output = self.complete_output() 524 | self.result.append((2, test, output, _exc_str)) 525 | if self.verbosity > 1: 526 | sys.stderr.write('E ') 527 | sys.stderr.write(str(test)) 528 | sys.stderr.write('\n') 529 | else: 530 | sys.stderr.write('E') 531 | 532 | def addFailure(self, test, err): 533 | self.failure_count += 1 534 | TestResult.addFailure(self, test, err) 535 | _, _exc_str = self.failures[-1] 536 | output = self.complete_output() 537 | self.result.append((1, test, output, _exc_str)) 538 | if self.verbosity > 1: 539 | sys.stderr.write('F ') 540 | sys.stderr.write(str(test)) 541 | sys.stderr.write('\n') 542 | else: 543 | sys.stderr.write('F') 544 | 545 | 546 | class HTMLTestRunner(Template_mixin): 547 | """ 548 | """ 549 | def __init__(self, stream=sys.stdout, verbosity=1,title=None,description=None,tester=None): 550 | self.stream = stream 551 | self.verbosity = verbosity 552 | if title is None: 553 | self.title = self.DEFAULT_TITLE 554 | else: 555 | self.title = title 556 | if description is None: 557 | self.description = self.DEFAULT_DESCRIPTION 558 | else: 559 | self.description = description 560 | if tester is None: 561 | self.tester = self.DEFAULT_TESTER 562 | else: 563 | self.tester = tester 564 | 565 | self.startTime = datetime.datetime.now() 566 | 567 | 568 | def run(self, test): 569 | "Run the given test case or test suite." 570 | result = _TestResult(self.verbosity) 571 | test(result) 572 | self.stopTime = datetime.datetime.now() 573 | self.generateReport(test, result) 574 | print('\nTime Elapsed: %s' % (self.stopTime-self.startTime), file=sys.stderr) 575 | return result 576 | 577 | 578 | def sortResult(self, result_list): 579 | # unittest does not seems to run in any particular order. 580 | # Here at least we want to group them together by class. 581 | rmap = {} 582 | classes = [] 583 | for n,t,o,e in result_list: 584 | cls = t.__class__ 585 | if cls not in rmap: 586 | rmap[cls] = [] 587 | classes.append(cls) 588 | rmap[cls].append((n,t,o,e)) 589 | r = [(cls, rmap[cls]) for cls in classes] 590 | return r 591 | 592 | #替换测试结果status为通过率 --Findyou 593 | def getReportAttributes(self, result): 594 | """ 595 | Return report attributes as a list of (name, value). 596 | Override this to add custom attributes. 597 | """ 598 | startTime = str(self.startTime)[:19] 599 | duration = str(self.stopTime - self.startTime) 600 | status = [] 601 | status.append('共 %s' % (result.success_count + result.failure_count + result.error_count)) 602 | if result.success_count: status.append('通过 %s' % result.success_count) 603 | if result.failure_count: status.append('失败 %s' % result.failure_count) 604 | if result.error_count: status.append('错误 %s' % result.error_count ) 605 | if status: 606 | status = ','.join(status) 607 | self.passrate = str("%.2f%%" % (float(result.success_count) / float(result.success_count + result.failure_count + result.error_count) * 100)) 608 | else: 609 | status = 'none' 610 | return [ 611 | ('测试人员', self.tester), 612 | ('开始时间',startTime), 613 | ('合计耗时',duration), 614 | ('测试结果',status + ",通过率= "+self.passrate), 615 | ] 616 | 617 | 618 | def generateReport(self, test, result): 619 | report_attrs = self.getReportAttributes(result) 620 | generator = 'HTMLTestRunner %s' % __version__ 621 | stylesheet = self._generate_stylesheet() 622 | heading = self._generate_heading(report_attrs) 623 | report = self._generate_report(result) 624 | ending = self._generate_ending() 625 | output = self.HTML_TMPL % dict( 626 | title = saxutils.escape(self.title), 627 | generator = generator, 628 | stylesheet = stylesheet, 629 | heading = heading, 630 | report = report, 631 | ending = ending, 632 | ) 633 | self.stream.write(output.encode('utf8')) 634 | 635 | 636 | def _generate_stylesheet(self): 637 | return self.STYLESHEET_TMPL 638 | 639 | #增加Tester显示 -Findyou 640 | def _generate_heading(self, report_attrs): 641 | a_lines = [] 642 | for name, value in report_attrs: 643 | line = self.HEADING_ATTRIBUTE_TMPL % dict( 644 | name = saxutils.escape(name), 645 | value = saxutils.escape(value), 646 | ) 647 | a_lines.append(line) 648 | heading = self.HEADING_TMPL % dict( 649 | title = saxutils.escape(self.title), 650 | parameters = ''.join(a_lines), 651 | description = saxutils.escape(self.description), 652 | tester= saxutils.escape(self.tester), 653 | ) 654 | return heading 655 | 656 | #生成报告 --Findyou添加注释 657 | def _generate_report(self, result): 658 | rows = [] 659 | sortedResult = self.sortResult(result.result) 660 | for cid, (cls, cls_results) in enumerate(sortedResult): 661 | # subtotal for a class 662 | np = nf = ne = 0 663 | for n,t,o,e in cls_results: 664 | if n == 0: np += 1 665 | elif n == 1: nf += 1 666 | else: ne += 1 667 | 668 | # format class description 669 | if cls.__module__ == "__main__": 670 | name = cls.__name__ 671 | else: 672 | name = "%s.%s" % (cls.__module__, cls.__name__) 673 | doc = cls.__doc__ and cls.__doc__.split("\n")[0] or "" 674 | desc = doc and '%s: %s' % (name, doc) or name 675 | 676 | row = self.REPORT_CLASS_TMPL % dict( 677 | style = ne > 0 and 'errorClass' or nf > 0 and 'failClass' or 'passClass', 678 | desc = desc, 679 | count = np+nf+ne, 680 | Pass = np, 681 | fail = nf, 682 | error = ne, 683 | cid = 'c%s' % (cid+1), 684 | ) 685 | rows.append(row) 686 | 687 | for tid, (n,t,o,e) in enumerate(cls_results): 688 | self._generate_report_test(rows, cid, tid, n, t, o, e) 689 | 690 | report = self.REPORT_TMPL % dict( 691 | test_list = ''.join(rows), 692 | count = str(result.success_count+result.failure_count+result.error_count), 693 | Pass = str(result.success_count), 694 | fail = str(result.failure_count), 695 | error = str(result.error_count), 696 | passrate =self.passrate, 697 | ) 698 | return report 699 | 700 | 701 | def _generate_report_test(self, rows, cid, tid, n, t, o, e): 702 | # e.g. 'pt1.1', 'ft1.1', etc 703 | has_output = bool(o or e) 704 | # ID修改点为下划线,支持Bootstrap折叠展开特效 - Findyou 705 | tid = (n == 0 and 'p' or 'f') + 't%s_%s' % (cid+1,tid+1) 706 | name = t.id().split('.')[-1] 707 | doc = t.shortDescription() or "" 708 | desc = doc and ('%s: %s' % (name, doc)) or name 709 | tmpl = has_output and self.REPORT_TEST_WITH_OUTPUT_TMPL or self.REPORT_TEST_NO_OUTPUT_TMPL 710 | 711 | # utf-8 支持中文 - Findyou 712 | # o and e should be byte string because they are collected from stdout and stderr? 713 | if isinstance(o, str): 714 | # TODO: some problem with 'string_escape': it escape \n and mess up formating 715 | # uo = unicode(o.encode('string_escape')) 716 | # uo = o.decode('latin-1') 717 | uo = o 718 | else: 719 | uo = o 720 | if isinstance(e, str): 721 | # TODO: some problem with 'string_escape': it escape \n and mess up formating 722 | # ue = unicode(e.encode('string_escape')) 723 | # ue = e.decode('latin-1') 724 | ue = e 725 | else: 726 | ue = e 727 | 728 | script = self.REPORT_TEST_OUTPUT_TMPL % dict( 729 | id = tid, 730 | output = saxutils.escape(uo+ue), 731 | ) 732 | 733 | row = tmpl % dict( 734 | tid = tid, 735 | Class = (n == 0 and 'hiddenRow' or 'none'), 736 | style = n == 2 and 'errorCase' or (n == 1 and 'failCase' or 'passCase'), 737 | desc = desc, 738 | script = script, 739 | status = self.STATUS[n], 740 | ) 741 | rows.append(row) 742 | if not has_output: 743 | return 744 | 745 | def _generate_ending(self): 746 | return self.ENDING_TMPL 747 | 748 | 749 | ############################################################################## 750 | # Facilities for running tests from the command line 751 | ############################################################################## 752 | 753 | # Note: Reuse unittest.TestProgram to launch test. In the future we may 754 | # build our own launcher to support more specific command line 755 | # parameters like test title, CSS, etc. 756 | class TestProgram(unittest.TestProgram): 757 | """ 758 | A variation of the unittest.TestProgram. Please refer to the base 759 | class for command line parameters. 760 | """ 761 | def runTests(self): 762 | # Pick HTMLTestRunner as the default test runner. 763 | # base class's testRunner parameter is not useful because it means 764 | # we have to instantiate HTMLTestRunner before we know self.verbosity. 765 | if self.testRunner is None: 766 | self.testRunner = HTMLTestRunner(verbosity=self.verbosity) 767 | unittest.TestProgram.runTests(self) 768 | 769 | main = TestProgram 770 | 771 | ############################################################################## 772 | # Executing this module from the command line 773 | ############################################################################## 774 | 775 | if __name__ == "__main__": 776 | main(module=None) 777 | -------------------------------------------------------------------------------- /htmltestrunner/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2018/4/11 11:19 4 | # @Author : huanghe 5 | # @Site : 6 | # @File : __init__.py.py 7 | # @Software: PyCharm -------------------------------------------------------------------------------- /report/2018-04-13 11_27_17_result.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Aquapaas WEB ADV Test Report 6 | 7 | 8 | 9 | 10 | 11 | 12 | 35 | 36 | 37 | 38 | 123 |
124 |

Aquapaas WEB ADV Test Report

125 |

测试人员 : QAHE

126 |

开始时间 : 2018-04-13 11:27:17

127 |

合计耗时 : 0:00:11.696170

128 |

测试结果 : 共 1,通过 1,通过率= 100.00%

129 | 130 |

Implementation Example with:

131 |
132 | 133 | 134 | 135 |

136 | 概要{ 100.00% } 137 | 失败{ 0 } 138 | 通过{ 1 } 139 | 所有{ 1 } 140 |

141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 |
用例集/测试用例总计通过失败错误详细
test_baidu.SearchTest1100详细
test_search
171 | 174 | 175 | 176 | 177 |
178 |
179 |     
180 | 1_1: 
181 | picture_shot
182 | picture_shot
183 | 
184 |     
185 |
186 |
总计1100通过率:100.00%
198 | 199 |
 
200 |
201 |
203 | 204 | 205 | 206 | 207 | -------------------------------------------------------------------------------- /report/2018-04-13 11_33_34_result.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Aquapaas WEB ADV Test Report 6 | 7 | 8 | 9 | 10 | 11 | 12 | 35 | 36 | 37 | 38 | 123 |
124 |

Aquapaas WEB ADV Test Report

125 |

测试人员 : QAHE

126 |

开始时间 : 2018-04-13 11:33:34

127 |

合计耗时 : 0:00:16.781000

128 |

测试结果 : 共 1,通过 1,通过率= 100.00%

129 | 130 |

Implementation Example with:

131 |
132 | 133 | 134 | 135 |

136 | 概要{ 100.00% } 137 | 失败{ 0 } 138 | 通过{ 1 } 139 | 所有{ 1 } 140 |

141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 |
用例集/测试用例总计通过失败错误详细
test_baidu.SearchTest1100详细
test_search
171 | 174 | 175 | 176 | 177 |
178 |
179 |     
180 | 1_1: 
181 | picture_shot
182 | picture_shot
183 | 
184 |     
185 |
186 |
总计1100通过率:100.00%
198 | 199 |
 
200 |
201 |
203 | 204 | 205 | 206 | 207 | -------------------------------------------------------------------------------- /report/2018-04-13 11_34_55_result.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Aquapaas WEB ADV Test Report 6 | 7 | 8 | 9 | 10 | 11 | 12 | 35 | 36 | 37 | 38 | 123 |
124 |

Aquapaas WEB ADV Test Report

125 |

测试人员 : QAHE

126 |

开始时间 : 2018-04-13 11:34:55

127 |

合计耗时 : 0:00:11.299000

128 |

测试结果 : 共 1,通过 1,通过率= 100.00%

129 | 130 |

Implementation Example with:

131 |
132 | 133 | 134 | 135 |

136 | 概要{ 100.00% } 137 | 失败{ 0 } 138 | 通过{ 1 } 139 | 所有{ 1 } 140 |

141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 |
用例集/测试用例总计通过失败错误详细
test_baidu.SearchTest1100详细
test_search
171 | 174 | 175 | 176 | 177 |
178 |
179 |     
180 | 1_1: 
181 | picture_shot
182 | picture_shot
183 | 
184 |     
185 |
186 |
总计1100通过率:100.00%
198 | 199 |
 
200 |
201 |
203 | 204 | 205 | 206 | 207 | -------------------------------------------------------------------------------- /report/2018-04-13 13_06_08_result.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Aquapaas WEB ADV Test Report 6 | 7 | 8 | 9 | 10 | 11 | 12 | 35 | 36 | 37 | 38 | 123 |
124 |

Aquapaas WEB ADV Test Report

125 |

测试人员 : QAHE

126 |

开始时间 : 2018-04-13 13:06:08

127 |

合计耗时 : 0:00:53.984547

128 |

测试结果 : 共 1,通过 1,通过率= 100.00%

129 | 130 |

Implementation Example with:

131 |
132 | 133 | 134 | 135 |

136 | 概要{ 100.00% } 137 | 失败{ 0 } 138 | 通过{ 1 } 139 | 所有{ 1 } 140 |

141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 |
用例集/测试用例总计通过失败错误详细
test_baidu.SearchTest1100详细
test_search
171 | 174 | 175 | 176 | 177 |
178 |
179 |     
180 | 1_1: 
181 | picture_shot
182 | picture_shot
183 | 
184 |     
185 |
186 |
总计1100通过率:100.00%
198 | 199 |
 
200 |
201 |
203 | 204 | 205 | 206 | 207 | -------------------------------------------------------------------------------- /report/screenpicture/20180413112728.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smarthaut/Daemon_AutoFramework/49dd148173b294ff33079c7ac284ae00723b82ed/report/screenpicture/20180413112728.png -------------------------------------------------------------------------------- /report/screenpicture/20180413113348.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smarthaut/Daemon_AutoFramework/49dd148173b294ff33079c7ac284ae00723b82ed/report/screenpicture/20180413113348.png -------------------------------------------------------------------------------- /report/screenpicture/20180413113506.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smarthaut/Daemon_AutoFramework/49dd148173b294ff33079c7ac284ae00723b82ed/report/screenpicture/20180413113506.png -------------------------------------------------------------------------------- /report/screenpicture/20180413130657.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smarthaut/Daemon_AutoFramework/49dd148173b294ff33079c7ac284ae00723b82ed/report/screenpicture/20180413130657.png -------------------------------------------------------------------------------- /run.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2018/4/11 11:21 4 | # @Author : huanghe 5 | # @Site : 6 | # @File : run.py 7 | # @Software: PyCharm 8 | 9 | import time 10 | import unittest 11 | from htmltestrunner.HTMLTestRunner import HTMLTestRunner 12 | 13 | test_dir = './src/test/case' 14 | discover = unittest.defaultTestLoader.discover(test_dir,pattern='test_ad_*.py') 15 | 16 | if __name__ == '__main__': 17 | now = time.strftime("%Y-%m-%d %H_%M_%S") 18 | filename = './report/' + now + '_result.html' 19 | fp = open(filename, 'wb') 20 | runner = HTMLTestRunner(stream=fp, 21 | title='Aquapaas WEB ADV Test Report', 22 | description='Implementation Example with: ' 23 | 24 | ) 25 | run = HTMLTestRunner() 26 | runner.run(discover) 27 | fp.close() -------------------------------------------------------------------------------- /src/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2018/4/11 10:34 4 | # @Author : huanghe 5 | # @Site : 6 | # @File : __init__.py.py 7 | # @Software: PyCharm -------------------------------------------------------------------------------- /src/test/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2018/4/11 10:33 4 | # @Author : huanghe 5 | # @Site : 6 | # @File : __init__.py.py 7 | # @Software: PyCharm -------------------------------------------------------------------------------- /src/test/case/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2018/4/11 10:35 4 | # @Author : huanghe 5 | # @Site : 6 | # @File : __init__.py.py 7 | # @Software: PyCharm -------------------------------------------------------------------------------- /src/test/case/geckodriver.log: -------------------------------------------------------------------------------- 1 | 1523510447127 geckodriver INFO geckodriver 0.18.0 2 | 1523510447135 geckodriver INFO Listening on 127.0.0.1:50406 3 | 1523510449201 geckodriver::marionette INFO Starting browser D:\firefox55\firefox.exe with args ["-marionette"] 4 | 1523510450318 addons.xpi WARN Error parsing extensions state: [Exception... "Component returned failure code: 0x80520012 (NS_ERROR_FILE_NOT_FOUND) [amIAddonManagerStartup.readStartupData]" nsresult: "0x80520012 (NS_ERROR_FILE_NOT_FOUND)" location: "JS frame :: resource://gre/modules/addons/XPIProvider.jsm :: loadExtensionState :: line 1596" data: no] Stack trace: loadExtensionState()@resource://gre/modules/addons/XPIProvider.jsm:1596 < getInstallState()@resource://gre/modules/addons/XPIProvider.jsm:1631 < checkForChanges()@resource://gre/modules/addons/XPIProvider.jsm:3152 < startup()@resource://gre/modules/addons/XPIProvider.jsm:2246 < callProvider()@resource://gre/modules/AddonManager.jsm:271 < _startProvider()@resource://gre/modules/AddonManager.jsm:741 < startup()@resource://gre/modules/AddonManager.jsm:908 < startup()@resource://gre/modules/AddonManager.jsm:3122 < observe()@jar:file:///D:/firefox55/omni.ja!/components/addonManager.js:65 5 | 1523510451113 Marionette INFO Enabled via --marionette 6 | [GPU 11740] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 7 | 1523510455595 Marionette INFO Listening on port 50412 8 | 1523510455664 Marionette INFO Listening on port 50412 9 | 1523510456574 Marionette WARN TLS certificate errors will be ignored for this session 10 | 1523510456643 Marionette DEBUG loaded listener.js 11 | 1523510456699 Marionette DEBUG Received DOM event "beforeunload" for "about:blank" 12 | 1523510456952 Marionette DEBUG Received DOM event "pagehide" for "about:blank" 13 | 1523510456952 Marionette DEBUG Received DOM event "unload" for "about:blank" 14 | JavaScript warning: http://10.50.4.115:8080/paasadv/js/common.js, line 281: unreachable code after return statement 15 | 1523510457402 Marionette DEBUG Received DOM event "DOMContentLoaded" for "http://10.50.4.115:8080/paasadv/" 16 | 1523510457414 Marionette DEBUG Received DOM event "pageshow" for "http://10.50.4.115:8080/paasadv/" 17 | 1523510457986 Marionette DEBUG Canceled page load listener because no navigation has been detected 18 | 1523510458203 Marionette INFO New connections will no longer be accepted 19 | 1523524158987 geckodriver INFO geckodriver 0.18.0 20 | 1523524159016 geckodriver INFO Listening on 127.0.0.1:55933 21 | 1523524160912 geckodriver::marionette INFO Starting browser D:\firefox55\firefox.exe with args ["-marionette"] 22 | 1523524161827 addons.xpi WARN Error parsing extensions state: [Exception... "Component returned failure code: 0x80520012 (NS_ERROR_FILE_NOT_FOUND) [amIAddonManagerStartup.readStartupData]" nsresult: "0x80520012 (NS_ERROR_FILE_NOT_FOUND)" location: "JS frame :: resource://gre/modules/addons/XPIProvider.jsm :: loadExtensionState :: line 1596" data: no] Stack trace: loadExtensionState()@resource://gre/modules/addons/XPIProvider.jsm:1596 < getInstallState()@resource://gre/modules/addons/XPIProvider.jsm:1631 < checkForChanges()@resource://gre/modules/addons/XPIProvider.jsm:3152 < startup()@resource://gre/modules/addons/XPIProvider.jsm:2246 < callProvider()@resource://gre/modules/AddonManager.jsm:271 < _startProvider()@resource://gre/modules/AddonManager.jsm:741 < startup()@resource://gre/modules/AddonManager.jsm:908 < startup()@resource://gre/modules/AddonManager.jsm:3122 < observe()@jar:file:///D:/firefox55/omni.ja!/components/addonManager.js:65 23 | 1523524162839 Marionette INFO Enabled via --marionette 24 | [GPU 18904] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 25 | 1523524166400 Marionette INFO Listening on port 55939 26 | 1523524166413 Marionette INFO Listening on port 55939 27 | 1523524166728 Marionette WARN TLS certificate errors will be ignored for this session 28 | 1523524166783 Marionette DEBUG loaded listener.js 29 | 1523524166832 Marionette DEBUG Received DOM event "beforeunload" for "about:blank" 30 | 1523524166907 Marionette DEBUG Received DOM event "pagehide" for "about:blank" 31 | 1523524166907 Marionette DEBUG Received DOM event "unload" for "about:blank" 32 | JavaScript error: https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/plugins/every_cookie_4644b13.js, line 4: ReferenceError: c is not defined 33 | 1523524167324 Marionette DEBUG Received DOM event "DOMContentLoaded" for "https://www.baidu.com/" 34 | 1523524167396 Marionette DEBUG Received DOM event "pageshow" for "https://www.baidu.com/" 35 | [GPU 18904] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 36 | [GPU 18904] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 37 | [Child 19372] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 38 | [Child 19372] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 39 | [GPU 18904] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 40 | 41 | ###!!! [Child][MessageChannel::SendAndWait] Error: Channel error: cannot send/recv 42 | 43 | m:271 < _startProvider()@resource://gre/modules/AddonManager.jsm:741 < startup()@resource://gre/modules/AddonManager.jsm:908 < startup()@resource://gre/modules/AddonManager.jsm:3122 < observe()@jar:file:///D:/firefox55/omni.ja!/components/addonManager.js:65 44 | 1523524171391 Marionette INFO Enabled via --marionette 45 | [GPU 20456] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 46 | [Child 20076] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 47 | 1523524184884 Marionette INFO Listening on port 55982 48 | 1523524185055 Marionette INFO Listening on port 55982 49 | 1523524185323 Marionette WARN TLS certificate errors will be ignored for this session 50 | 1523524187364 Marionette DEBUG loaded listener.js 51 | 1523524187420 Marionette DEBUG Received DOM event "beforeunload" for "about:blank" 52 | 1523524187547 Marionette DEBUG Received DOM event "pagehide" for "about:blank" 53 | 1523524187548 Marionette DEBUG Received DOM event "unload" for "about:blank" 54 | JavaScript error: https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/plugins/every_cookie_4644b13.js, line 4: ReferenceError: c is not defined 55 | 1523524188186 Marionette DEBUG Received DOM event "DOMContentLoaded" for "https://www.baidu.com/" 56 | 1523524188369 Marionette DEBUG Received DOM event "pageshow" for "https://www.baidu.com/" 57 | JavaScript error: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=se&json=1&p=3&sid=1424_25809_21087_22160&req=2&csor=2&pwd=s&cb=jQuery1102097761785179075_1523524188058&_=1523524188061, line 1: TypeError: jQuery1102097761785179075_1523524188058 is not a function 58 | JavaScript error: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=s&json=1&p=3&sid=1424_25809_21087_22160&req=2&csor=1&cb=jQuery1102097761785179075_1523524188058&_=1523524188060, line 1: TypeError: jQuery1102097761785179075_1523524188058 is not a function 59 | JavaScript error: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=sel&json=1&p=3&sid=1424_25809_21087_22160&req=2&csor=3&pwd=se&cb=jQuery1102097761785179075_1523524188058&_=1523524188062, line 1: TypeError: jQuery1102097761785179075_1523524188058 is not a function 60 | JavaScript error: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=sele&json=1&p=3&sid=1424_25809_21087_22160&req=2&csor=4&pwd=sel&cb=jQuery1102097761785179075_1523524188058&_=1523524188063, line 1: TypeError: jQuery1102097761785179075_1523524188058 is not a function 61 | JavaScript error: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=selen&json=1&p=3&sid=1424_25809_21087_22160&req=2&csor=5&pwd=sele&cb=jQuery1102097761785179075_1523524188058&_=1523524188064, line 1: TypeError: jQuery1102097761785179075_1523524188058 is not a function 62 | JavaScript error: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=seleni&json=1&p=3&sid=1424_25809_21087_22160&req=2&csor=6&pwd=selen&cb=jQuery1102097761785179075_1523524188058&_=1523524188065, line 1: TypeError: jQuery1102097761785179075_1523524188058 is not a function 63 | JavaScript error: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=seleniu&json=1&p=3&sid=1424_25809_21087_22160&req=2&csor=7&pwd=seleni&cb=jQuery1102097761785179075_1523524188058&_=1523524188066, line 1: TypeError: jQuery1102097761785179075_1523524188058 is not a function 64 | JavaScript error: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=selenium%20%E7%81%B0%E8%93%9D&json=1&p=3&sid=1424_25809_21087_22160&req=2&csor=11&pwd=selenium%20%E7%81%B0&cb=jQuery1102097761785179075_1523524188058&_=1523524188070, line 1: TypeError: jQuery1102097761785179075_1523524188058 is not a function 65 | JavaScript error: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=selenium%20%E7%81%B0&json=1&p=3&sid=1424_25809_21087_22160&req=2&csor=10&pwd=selenium%20&cb=jQuery1102097761785179075_1523524188058&_=1523524188069, line 1: TypeError: jQuery1102097761785179075_1523524188058 is not a function 66 | JavaScript error: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=selenium&json=1&p=3&sid=1424_25809_21087_22160&req=2&csor=8&pwd=seleniu&cb=jQuery1102097761785179075_1523524188058&_=1523524188067, line 1: TypeError: jQuery1102097761785179075_1523524188058 is not a function 67 | JavaScript error: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=selenium%20&json=1&p=3&sid=1424_25809_21087_22160&req=2&csor=9&pwd=selenium&cb=jQuery1102097761785179075_1523524188058&_=1523524188068, line 1: TypeError: jQuery1102097761785179075_1523524188058 is not a function 68 | 1523524189590 Marionette DEBUG Canceled page load listener because no navigation has been detected 69 | 1523524191750 Marionette INFO New connections will no longer be accepted 70 | 1523524192525 geckodriver INFO geckodriver 0.18.0 71 | 1523524192537 geckodriver INFO Listening on 127.0.0.1:56061 72 | 1523524194677 geckodriver::marionette INFO Starting browser D:\firefox55\firefox.exe with args ["-marionette"] 73 | 1523524197232 addons.xpi WARN Error parsing extensions state: [Exception... "Component returned failure code: 0x80520012 (NS_ERROR_FILE_NOT_FOUND) [amIAddonManagerStartup.readStartupData]" nsresult: "0x80520012 (NS_ERROR_FILE_NOT_FOUND)" location: "JS frame :: resource://gre/modules/addons/XPIProvider.jsm :: loadExtensionState :: line 1596" data: no] Stack trace: loadExtensionState()@resource://gre/modules/addons/XPIProvider.jsm:1596 < getInstallState()@resource://gre/modules/addons/XPIProvider.jsm:1631 < checkForChanges()@resource://gre/modules/addons/XPIProvider.jsm:3152 < startup()@resource://gre/modules/addons/XPIProvider.jsm:2246 < callProvider()@resource://gre/modules/AddonManager.jsm:271 < _startProvider()@resource://gre/modules/AddonManager.jsm:741 < startup()@resource://gre/modules/AddonManager.jsm:908 < startup()@resource://gre/modules/AddonManager.jsm:3122 < observe()@jar:file:///D:/firefox55/omni.ja!/components/addonManager.js:65 74 | 1523524198151 Marionette INFO Enabled via --marionette 75 | [Child 13640] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 76 | 1523524205506 Marionette INFO Listening on port 56067 77 | 1523524205514 Marionette INFO Listening on port 56067 78 | 1523524206247 Marionette WARN TLS certificate errors will be ignored for this session 79 | 1523524209449 Marionette DEBUG loaded listener.js 80 | 1523524209554 Marionette DEBUG Received DOM event "beforeunload" for "about:blank" 81 | 1523524209639 Marionette DEBUG Received DOM event "pagehide" for "about:blank" 82 | 1523524209640 Marionette DEBUG Received DOM event "unload" for "about:blank" 83 | JavaScript error: https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/plugins/every_cookie_4644b13.js, line 4: ReferenceError: c is not defined 84 | 1523524209956 Marionette DEBUG Received DOM event "DOMContentLoaded" for "https://www.baidu.com/" 85 | 1523524210040 Marionette DEBUG Received DOM event "pageshow" for "https://www.baidu.com/" 86 | JavaScript error: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=P&json=1&p=3&sid=1461_21117_18559_20930&req=2&csor=1&cb=jQuery110205569721155852609_1523524209801&_=1523524209803, line 1: TypeError: jQuery110205569721155852609_1523524209801 is not a function 87 | JavaScript error: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=Pyth&json=1&p=3&sid=1461_21117_18559_20930&req=2&csor=4&pwd=Pyt&cb=jQuery110205569721155852609_1523524209801&_=1523524209806, line 1: TypeError: jQuery110205569721155852609_1523524209801 is not a function 88 | JavaScript error: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=Pytho&json=1&p=3&sid=1461_21117_18559_20930&req=2&csor=5&pwd=Pyth&cb=jQuery110205569721155852609_1523524209801&_=1523524209807, line 1: TypeError: jQuery110205569721155852609_1523524209801 is not a function 89 | JavaScript error: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=Pyt&json=1&p=3&sid=1461_21117_18559_20930&req=2&csor=3&pwd=Py&cb=jQuery110205569721155852609_1523524209801&_=1523524209805, line 1: TypeError: jQuery110205569721155852609_1523524209801 is not a function 90 | JavaScript error: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=Python&json=1&p=3&sid=1461_21117_18559_20930&req=2&csor=6&pwd=Pytho&cb=jQuery110205569721155852609_1523524209801&_=1523524209808, line 1: TypeError: jQuery110205569721155852609_1523524209801 is not a function 91 | JavaScript error: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=Py&json=1&p=3&sid=1461_21117_18559_20930&req=2&csor=2&pwd=P&cb=jQuery110205569721155852609_1523524209801&_=1523524209804, line 1: TypeError: jQuery110205569721155852609_1523524209801 is not a function 92 | JavaScript error: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=Python%20&json=1&p=3&sid=1461_21117_18559_20930&req=2&csor=7&pwd=Python&cb=jQuery110205569721155852609_1523524209801&_=1523524209809, line 1: TypeError: jQuery110205569721155852609_1523524209801 is not a function 93 | JavaScript error: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=Python%20s&json=1&p=3&sid=1461_21117_18559_20930&req=2&csor=8&pwd=Python%20&cb=jQuery110205569721155852609_1523524209801&_=1523524209810, line 1: TypeError: jQuery110205569721155852609_1523524209801 is not a function 94 | JavaScript error: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=Python%20se&json=1&p=3&sid=1461_21117_18559_20930&req=2&csor=9&pwd=Python%20s&cb=jQuery110205569721155852609_1523524209801&_=1523524209811, line 1: TypeError: jQuery110205569721155852609_1523524209801 is not a function 95 | JavaScript error: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=Python%20sel&json=1&p=3&sid=1461_21117_18559_20930&req=2&csor=10&pwd=Python%20se&cb=jQuery110205569721155852609_1523524209801&_=1523524209812, line 1: TypeError: jQuery110205569721155852609_1523524209801 is not a function 96 | JavaScript error: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=Python%20sele&json=1&p=3&sid=1461_21117_18559_20930&req=2&csor=11&pwd=Python%20sel&cb=jQuery110205569721155852609_1523524209801&_=1523524209813, line 1: TypeError: jQuery110205569721155852609_1523524209801 is not a function 97 | JavaScript error: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=Python%20selen&json=1&p=3&sid=1461_21117_18559_20930&req=2&csor=12&pwd=Python%20sele&cb=jQuery110205569721155852609_1523524209801&_=1523524209814, line 1: TypeError: jQuery110205569721155852609_1523524209801 is not a function 98 | JavaScript error: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=Python%20seleni&json=1&p=3&sid=1461_21117_18559_20930&req=2&csor=13&pwd=Python%20selen&cb=jQuery110205569721155852609_1523524209801&_=1523524209815, line 1: TypeError: jQuery110205569721155852609_1523524209801 is not a function 99 | JavaScript error: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=Python%20seleniu&json=1&p=3&sid=1461_21117_18559_20930&req=2&csor=14&pwd=Python%20seleni&cb=jQuery110205569721155852609_1523524209801&_=1523524209816, line 1: TypeError: jQuery110205569721155852609_1523524209801 is not a function 100 | JavaScript error: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=Python%20selenium&json=1&p=3&sid=1461_21117_18559_20930&req=2&csor=15&pwd=Python%20seleniu&cb=jQuery110205569721155852609_1523524209801&_=1523524209817, line 1: TypeError: jQuery110205569721155852609_1523524209801 is not a function 101 | 1523524210689 Marionette DEBUG Canceled page load listener because no navigation has been detected 102 | 1523524212783 Marionette INFO New connections will no longer be accepted 103 | 1523598988211 geckodriver INFO geckodriver 0.18.0 104 | 1523598988237 geckodriver INFO Listening on 127.0.0.1:62407 105 | 1523598989886 geckodriver::marionette INFO Starting browser D:\firefox55\firefox.exe with args ["-marionette"] 106 | 1523598992757 addons.xpi WARN Error parsing extensions state: [Exception... "Component returned failure code: 0x80520012 (NS_ERROR_FILE_NOT_FOUND) [amIAddonManagerStartup.readStartupData]" nsresult: "0x80520012 (NS_ERROR_FILE_NOT_FOUND)" location: "JS frame :: resource://gre/modules/addons/XPIProvider.jsm :: loadExtensionState :: line 1596" data: no] Stack trace: loadExtensionState()@resource://gre/modules/addons/XPIProvider.jsm:1596 < getInstallState()@resource://gre/modules/addons/XPIProvider.jsm:1631 < checkForChanges()@resource://gre/modules/addons/XPIProvider.jsm:3152 < startup()@resource://gre/modules/addons/XPIProvider.jsm:2246 < callProvider()@resource://gre/modules/AddonManager.jsm:271 < _startProvider()@resource://gre/modules/AddonManager.jsm:741 < startup()@resource://gre/modules/AddonManager.jsm:908 < startup()@resource://gre/modules/AddonManager.jsm:3122 < observe()@jar:file:///D:/firefox55/omni.ja!/components/addonManager.js:65 107 | 1523598995819 Marionette INFO Enabled via --marionette 108 | [GPU 18416] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 109 | 1523599010172 Marionette INFO Listening on port 62414 110 | [Child 9580] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 111 | 1523599010486 Marionette WARN TLS certificate errors will be ignored for this session 112 | 1523599010556 Marionette INFO Listening on port 62414 113 | 1523599010567 Marionette DEBUG loaded listener.js 114 | 1523599011355 Marionette DEBUG Received DOM event "beforeunload" for "about:blank" 115 | 1523599011448 Marionette DEBUG Received DOM event "pagehide" for "about:blank" 116 | 1523599011448 Marionette DEBUG Received DOM event "unload" for "about:blank" 117 | JavaScript warning: http://10.50.4.115:8080/paasadv/js/common.js, line 281: unreachable code after return statement 118 | 1523599011939 Marionette DEBUG Received DOM event "DOMContentLoaded" for "http://10.50.4.115:8080/paasadv/" 119 | 1523599011966 Marionette DEBUG Received DOM event "pageshow" for "http://10.50.4.115:8080/paasadv/" 120 | 1523599013781 Marionette DEBUG Canceled page load listener because no navigation has been detected 121 | 1523599031924 addons.productaddons WARN Failed downloading via XHR, status: 0, reason: error 122 | JavaScript warning: http://10.50.4.115:8080/paasadv/content/su_cai/aquadatacenter.js, line 861: unreachable code after return statement 123 | JavaScript warning: http://10.50.4.115:8080/paasadv/content/su_cai/aquadatacenter.js, line 861: unreachable code after return statement 124 | JavaScript warning: http://10.50.4.115:8080/paasadv/content/su_cai/aquadatacenter.js, line 861: unreachable code after return statement 125 | [GPU 18416] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 126 | [GPU 18416] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 127 | JavaScript error: resource://gre/modules/commonjs/toolkit/loader.js -> resource://devtools/client/netmonitor/src/connector/firefox-connector.js, line 91: TypeError: this.tabTarget is null 128 | [Child 14460] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 129 | 130 | ###!!! [Child][MessageChannel::SendAndWait] Error: Channel error: cannot send/recv 131 | 132 | 1523932973420 geckodriver INFO geckodriver 0.18.0 133 | 1523932973479 geckodriver INFO Listening on 127.0.0.1:55915 134 | 1523932975605 geckodriver::marionette INFO Starting browser D:\firefox55\firefox.exe with args ["-marionette"] 135 | 1523932981811 addons.xpi WARN Error parsing extensions state: [Exception... "Component returned failure code: 0x80520012 (NS_ERROR_FILE_NOT_FOUND) [amIAddonManagerStartup.readStartupData]" nsresult: "0x80520012 (NS_ERROR_FILE_NOT_FOUND)" location: "JS frame :: resource://gre/modules/addons/XPIProvider.jsm :: loadExtensionState :: line 1596" data: no] Stack trace: loadExtensionState()@resource://gre/modules/addons/XPIProvider.jsm:1596 < getInstallState()@resource://gre/modules/addons/XPIProvider.jsm:1631 < checkForChanges()@resource://gre/modules/addons/XPIProvider.jsm:3152 < startup()@resource://gre/modules/addons/XPIProvider.jsm:2246 < callProvider()@resource://gre/modules/AddonManager.jsm:271 < _startProvider()@resource://gre/modules/AddonManager.jsm:741 < startup()@resource://gre/modules/AddonManager.jsm:908 < startup()@resource://gre/modules/AddonManager.jsm:3122 < observe()@jar:file:///D:/firefox55/omni.ja!/components/addonManager.js:65 136 | 1523932985531 Marionette INFO Enabled via --marionette 137 | [GPU 6768] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 138 | 1523933000682 Marionette INFO Listening on port 55922 139 | 1523933000864 Marionette WARN TLS certificate errors will be ignored for this session 140 | 1523933000892 Marionette INFO Listening on port 55922 141 | 1523933000936 Marionette DEBUG loaded listener.js 142 | 1523933001503 Marionette DEBUG Received DOM event "beforeunload" for "about:blank" 143 | 1523933001850 Marionette DEBUG Received DOM event "pagehide" for "about:blank" 144 | 1523933001851 Marionette DEBUG Received DOM event "unload" for "about:blank" 145 | JavaScript error: https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/plugins/every_cookie_4644b13.js, line 4: ReferenceError: c is not defined 146 | 1523933004900 Marionette DEBUG Received DOM event "DOMContentLoaded" for "https://www.baidu.com/" 147 | 1523933005318 Marionette DEBUG Received DOM event "pageshow" for "https://www.baidu.com/" 148 | JavaScript error: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B&json=1&p=3&sid=1448_13290_21094_18559_22158&req=2&csor=4&pwd=%E8%87%AA%E5%8A%A8%E5%8C%96&cb=jQuery1102000682863240938969_1523933003896&_=1523933003901, line 1: TypeError: jQuery1102000682863240938969_1523933003896 is not a function 149 | JavaScript error: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=%E8%87%AA%E5%8A%A8&json=1&p=3&sid=1448_13290_21094_18559_22158&req=2&csor=2&pwd=%E8%87%AA&cb=jQuery1102000682863240938969_1523933003896&_=1523933003899, line 1: TypeError: jQuery1102000682863240938969_1523933003896 is not a function 150 | JavaScript error: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95&json=1&p=3&sid=1448_13290_21094_18559_22158&req=2&csor=5&pwd=%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B&cb=jQuery1102000682863240938969_1523933003896&_=1523933003902, line 1: TypeError: jQuery1102000682863240938969_1523933003896 is not a function 151 | JavaScript error: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=%E8%87%AA%E5%8A%A8%E5%8C%96&json=1&p=3&sid=1448_13290_21094_18559_22158&req=2&csor=3&pwd=%E8%87%AA%E5%8A%A8&cb=jQuery1102000682863240938969_1523933003896&_=1523933003900, line 1: TypeError: jQuery1102000682863240938969_1523933003896 is not a function 152 | 1523933007159 Marionette DEBUG Canceled page load listener because no navigation has been detected 153 | JavaScript warning: http://10.50.4.115:8080/paasadv/js/common.js, line 281: unreachable code after return statement 154 | [GPU 6768] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 155 | [GPU 6768] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 156 | [GPU 6768] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 157 | JavaScript error: resource://gre/modules/commonjs/toolkit/loader.js -> resource://devtools/client/netmonitor/src/connector/firefox-connector.js, line 91: TypeError: this.tabTarget is null 158 | IPDL protocol error: Handler returned error code! 159 | 160 | ###!!! [Parent][DispatchAsyncMessage] Error: PLayerTransaction::Msg_ReleaseLayer Processing error: message was deserialized, but the handler returned false (indicating failure) 161 | 162 | IPDL protocol error: Handler returned error code! 163 | 164 | ###!!! [Parent][DispatchAsyncMessage] Error: PLayerTransaction::Msg_ReleaseLayer Processing error: message was deserialized, but the handler returned false (indicating failure) 165 | 166 | IPDL protocol error: Handler returned error code! 167 | 168 | ###!!! [Parent][DispatchAsyncMessage] Error: PLayerTransaction::Msg_ReleaseLayer Processing error: message was deserialized, but the handler returned false (indicating failure) 169 | 170 | IPDL protocol error: Handler returned error code! 171 | 172 | ###!!! [Parent][DispatchAsyncMessage] Error: PLayerTransaction::Msg_ReleaseLayer Processing error: message was deserialized, but the handler returned false (indicating failure) 173 | 174 | IPDL protocol error: Handler returned error code! 175 | 176 | ###!!! [Parent][DispatchAsyncMessage] Error: PLayerTransaction::Msg_ReleaseLayer Processing error: message was deserialized, but the handler returned false (indicating failure) 177 | 178 | [Child 3288] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 179 | [Child 3288] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 180 | 181 | ###!!! [Child][MessageChannel::SendAndWait] Error: Channel error: cannot send/recv 182 | 183 | -------------------------------------------------------------------------------- /src/test/case/test_ad_position.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2018/4/26 14:01 4 | # @Author : huanghe 5 | # @Site : 6 | # @File : test_ad_position.py 7 | # @Software: PyCharm 8 | import unittest 9 | 10 | from src.test.suit.aquapaasADV.login_page import LoginPage 11 | from src.utils.browser import Browser 12 | from src.utils.config import Config 13 | import time 14 | 15 | class AquaPaasAdvTest(unittest.TestCase): 16 | def setUp(self): 17 | self.driver = Browser().get_browserdriver() 18 | login_page = LoginPage(self.driver) 19 | login_page.url = Config().get('URL') 20 | login_page.visit() 21 | # time.sleep(10) 22 | login_page.wait(10) 23 | login_page.set_value(element=login_page.rec_user_input(), text=Config().get('USER')) 24 | login_page.set_value(element=login_page.rec_passwd_input(), text=Config().get('PASSWORD')) 25 | login_page.click_login_btn() 26 | self.main_page = login_page.get_main_page() 27 | 28 | def tearDown(self): 29 | self.driver.quit() 30 | 31 | def test_create_tuwen_ad_position(self): 32 | now = time.strftime("%Y%m%d%H%M%S") 33 | self.adposition_oage = self.main_page.click_ad_position_btn() 34 | -------------------------------------------------------------------------------- /src/test/case/test_baidu.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2018/4/12 16:29 4 | # @Author : huanghe 5 | # @Site : 6 | # @File : test_baidu.py 7 | # @Software: PyCharm 8 | import time 9 | import unittest 10 | from src.test.suit.baidu.search_page import SearchPage 11 | from src.utils.browser import Browser 12 | from src.utils.config import Config 13 | from src.utils.file_reader import ExcelReader 14 | from src.utils.config import DATA_PATH 15 | 16 | excel = DATA_PATH 17 | dates = ExcelReader(DATA_PATH).data 18 | 19 | class SearchTest(unittest.TestCase): 20 | 21 | 22 | def setUp(self): 23 | self.driver =Browser().get_browserdriver() 24 | self.search_page = SearchPage(self.driver) 25 | self.search_page.url = Config().get('BaiDuURl') 26 | self.search_page.visit() 27 | 28 | def tearDown(self): 29 | pass 30 | #self.search_page.quit_browser() 31 | 32 | def test_search(self): 33 | self.search_page.set_value(element=self.search_page.rec_search_input(), text=dates[1]['search']) 34 | self.search_page.click_search_btn() 35 | self.search_page.get_windows_img() 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/test/case/test_login.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2018/4/11 10:36 4 | # @Author : huanghe 5 | # @Site : 6 | # @File : test_login.py 7 | # @Software: PyCharm 8 | import unittest 9 | 10 | from src.test.suit.aquapaasADV.login_page import LoginPage 11 | from src.utils.browser import Browser 12 | from src.utils.config import Config 13 | 14 | 15 | class LoginTest(unittest.TestCase): 16 | 17 | def setUp(self): 18 | self.driver = Browser().get_browserdriver() 19 | 20 | def tearDown(self): 21 | self.driver.quit() 22 | 23 | def test_login(self): 24 | login_page = LoginPage(self.driver) 25 | login_page.url = Config().get('URL') 26 | login_page.visit() 27 | # time.sleep(10) 28 | login_page.wait(10) 29 | login_page.set_value(element=login_page.rec_user_input(), text=Config().get('USER')) 30 | login_page.set_value(element=login_page.rec_passwd_input(), text=Config().get('PASSWORD')) 31 | login_page.click_login_btn() 32 | login_page.get_windows_img() 33 | 34 | 35 | if __name__ == '__main__': 36 | LoginTest() 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/test/common/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2018/4/11 10:35 4 | # @Author : huanghe 5 | # @Site : 6 | # @File : __init__.py.py 7 | # @Software: PyCharm -------------------------------------------------------------------------------- /src/test/common/base_page.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2018/2/24 14:38 4 | # @Author : huanghe 5 | # @Site : 6 | # @File : base_page.py 7 | # @Software: PyCharm 8 | import time 9 | from selenium.common.exceptions import NoSuchElementException 10 | from src.utils.log import Logger 11 | 12 | class Basepage(object): 13 | url = None 14 | '''' 15 | 定义一个基类,封装常用的页面方法 16 | ''' 17 | def __init__(self,driver): 18 | self.driver = driver 19 | self.classname = self.__class__.__name__ 20 | 21 | #浏览器最大化 22 | def max_browser(self): 23 | self.driver.maximize_window() 24 | 25 | #设置浏览器的宽,高 26 | def set_width(self,width,height): 27 | self.driver.set_window_size(width,height) 28 | 29 | #关闭浏览器 30 | def quit_browser(self): 31 | self.driver.quit() 32 | 33 | #浏览器前进 34 | def forward(self): 35 | self.driver.forward() 36 | 37 | #浏览器后退 38 | def back(self): 39 | self.driver.back() 40 | 41 | # 隐式等待 42 | def wait(self,seconds): 43 | self.driver.implicitly_wait(seconds) 44 | 45 | # 关闭当前窗口 46 | def close(self): 47 | try: 48 | self.driver.close() 49 | except NameError as e: 50 | print('Failed to close') 51 | 52 | def visit(self): 53 | self.driver.get(self.url) 54 | 55 | 56 | # 保存图片 57 | def get_windows_img(self): 58 | file_path = r'D:/python/Daemon_/report/screenpicture/' 59 | rq = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time())) 60 | screen_name = file_path + rq + '.png' 61 | try: 62 | self.driver.get_screenshot_as_file(screen_name) 63 | self.logger.info("Had take screenshot and save to folder : /screenshots") 64 | print(screen_name) 65 | except NameError as e: 66 | self.logger.error("Failed to take screenpicture! {}".format(e)) 67 | self.get_windows_img() 68 | 69 | # 定位元素方法 70 | def find_element(self,selector): 71 | self.logger = Logger(loggername=self.classname).get_logger() 72 | element = '' 73 | if '=>' not in selector: 74 | return self.driver.find_element_by_id(selector) 75 | selector_by = selector.split('=>')[0] 76 | selector_value = selector.split('=>')[1] 77 | 78 | if selector_by == "i" or selector_by == 'id': 79 | try: 80 | element = self.driver.find_element_by_id(selector_value) 81 | self.logger.info("Had find the element {}successful " 82 | "by {} via value: {} ".format(element.text, selector_by, selector_value)) 83 | except NoSuchElementException as e: 84 | self.logger.error("NoSuchElementException: {}".format(e)) 85 | self.get_windows_img() # take screenshot 86 | elif selector_by == "n" or selector_by == 'name': 87 | element = self.driver.find_element_by_name(selector_value) 88 | elif selector_by == "c" or selector_by == 'class_name': 89 | element = self.driver.find_element_by_class_name(selector_value) 90 | elif selector_by == "l" or selector_by == 'link_text': 91 | element = self.driver.find_element_by_link_text(selector_value) 92 | elif selector_by == "p" or selector_by == 'partial_link_text': 93 | element = self.driver.find_element_by_partial_link_text(selector_value) 94 | elif selector_by == "t" or selector_by == 'tag_name': 95 | element = self.driver.find_element_by_tag_name(selector_value) 96 | elif selector_by == "x" or selector_by == 'xpath': 97 | try: 98 | element = self.driver.find_element_by_xpath(selector_value) 99 | self.logger.info("Had find the element {} successful " 100 | "by {} via value: {} ".format(element.text, selector_by, selector_value)) 101 | except NoSuchElementException as e: 102 | self.logger.error("NoSuchElementException: {}".format(e)) 103 | self.get_windows_img() 104 | elif selector_by == "s" or selector_by == 'css_selector': 105 | element = self.driver.find_element_by_css_selector(selector_value) 106 | else: 107 | raise NameError("Please enter a valid type of targeting elements.") 108 | 109 | return element 110 | 111 | # 文本框输入 112 | def set_value(self,element,text): 113 | self.logger = Logger(loggername=self.classname).get_logger() 114 | element.clear() 115 | try: 116 | element.send_keys(text) 117 | self.logger.info("Had type {} in inputBox".format(text)) 118 | except NameError as e: 119 | self.logger.error("Failed to type in input box with {}".format(e)) 120 | self.get_windows_img() 121 | 122 | # 文本框清除 123 | def clear(self,selector): 124 | self.logger = Logger(loggername=self.classname).get_logger() 125 | el = self.find_element(selector) 126 | try: 127 | el.clear() 128 | self.logger.info("Clear text in input box before typing.") 129 | except NameError as e: 130 | self.logger.error("Failed to clear in input box with {}".format(e)) 131 | self.get_windows_img() 132 | 133 | # 点击元素 134 | def click_sel(self, selector): 135 | self.logger = Logger(loggername=self.classname).get_logger() 136 | el = self.find_element(selector) 137 | try: 138 | self.logger.info("The element {} was clicked." .format(el.text)) 139 | el.click() 140 | except NameError as e: 141 | self.logger.error("Failed to click the element with {}".format(e)) 142 | 143 | # 获取网页标题 144 | def get_page_title(self): 145 | self.logger = Logger(loggername=self.classname).get_logger() 146 | self.logger.info("Current page title is {}".format(self.driver.title)) 147 | return self.driver.title 148 | 149 | #sleep 150 | def sleep(self,seconds): 151 | self.logger = Logger(loggername=self.classname).get_logger() 152 | time.sleep(seconds) 153 | self.logger.info("Sleep for {} seconds" .format(seconds)) 154 | 155 | # 156 | def switch_alert(self): 157 | alert = self.driver.switch_to_alert() 158 | alert.accept() 159 | 160 | #frame切换 161 | def switch_frame(self,elem): 162 | pass 163 | 164 | -------------------------------------------------------------------------------- /src/test/suit/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2018/4/11 10:35 4 | # @Author : huanghe 5 | # @Site : 6 | # @File : __init__.py.py 7 | # @Software: PyCharm -------------------------------------------------------------------------------- /src/test/suit/aquapaasADV/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2018/4/11 11:35 4 | # @Author : huanghe 5 | # @Site : 6 | # @File : __init__.py.py 7 | # @Software: PyCharm -------------------------------------------------------------------------------- /src/test/suit/aquapaasADV/ad_position_page.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2018/4/26 13:45 4 | # @Author : huanghe 5 | # @Site : 6 | # @File : ad_position_page.py 7 | # @Software: PyCharm 8 | from src.utils.log import Logger 9 | from src.test.common.base_page import Basepage 10 | 11 | class AdPosition(Basepage): 12 | def rec_picture_btn(self): 13 | self.logger = Logger(loggername=self.__class__.__name__).get_logger() 14 | self.logger.debug(u'找到图文按钮') 15 | return self.find_element('css_selector=>div#adPos_adKind_tuwen') 16 | 17 | def click_picture_btn(self): 18 | self.rec_picture_btn().click() 19 | self.logger.debug(u'点击图文按钮') 20 | return Picture(self.driver) 21 | 22 | class Picture(Basepage): 23 | def rec_create_btn(self): 24 | self.logger = Logger(loggername=self.__class__.__name__).get_logger() 25 | self.logger.debug(u'找到新建广告位按钮') 26 | return self.find_element('css_selector=>div.panel_page_button_text') 27 | def click_create_btn(self): 28 | self.rec_create_btn().click() 29 | self.logger.debug(u'点击新建广告位按钮') 30 | -------------------------------------------------------------------------------- /src/test/suit/aquapaasADV/login_page.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2018/2/24 15:26 4 | # @Author : huanghe 5 | # @Site : 6 | # @File : login_pag.py 7 | # @Software: PyCharm 8 | from src.utils.log import Logger 9 | from src.test.common.base_page import Basepage 10 | from src.test.suit.aquapaasADV.main_page import MainPage 11 | 12 | class LoginPage(Basepage): 13 | 14 | def rec_user_input(self): 15 | self.logger = Logger(loggername=self.__class__.__name__).get_logger() 16 | self.logger.debug(u'找到"登录用户名"输入input.') 17 | return self.find_element(selector='id=>login_dialog_input_user_mail') 18 | 19 | def rec_passwd_input(self): 20 | self.logger = Logger(loggername=self.__class__.__name__).get_logger() 21 | self.logger.debug(u'找到"密码"输入input.') 22 | return self.find_element(selector='id=>login_dialog_input_user_pwd') 23 | 24 | def rec_rmb_user_btn(self): 25 | self.logger = Logger(loggername=self.__class__.__name__).get_logger() 26 | self.logger.debug(u'找到"记住用户名"按钮.') 27 | return self.find_element(selector='id=>login_dialog_rmb_user') 28 | 29 | def rec_rmb_pwd_btn(self): 30 | self.logger = Logger(loggername=self.__class__.__name__).get_logger() 31 | self.logger.debug(u'找到"记住密码"按钮.') 32 | return self.find_element(selector='id=>login_dialog_rmb_pwd') 33 | 34 | def rec_login_btn(self): 35 | self.logger = Logger(loggername=self.__class__.__name__).get_logger() 36 | self.logger.debug(u'找到"立即登录"按钮.') 37 | return self.find_element(selector='id=>login_dialog_login_button') 38 | 39 | def click_login_btn(self): 40 | self.logger = Logger(loggername=self.__class__.__name__).get_logger() 41 | self.logger.debug(u'点击"立即登录 "按钮.') 42 | self.click_sel(selector='id=>login_dialog_login_button') 43 | 44 | def get_main_page(self): 45 | return MainPage(self.driver) 46 | 47 | -------------------------------------------------------------------------------- /src/test/suit/baidu/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2018/4/12 16:28 4 | # @Author : huanghe 5 | # @Site : 6 | # @File : __init__.py.py 7 | # @Software: PyCharm -------------------------------------------------------------------------------- /src/test/suit/baidu/search_page.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2018/4/12 16:32 4 | # @Author : huanghe 5 | # @Site : 6 | # @File : search_page.py 7 | # @Software: PyCharm 8 | from src.utils.log import Logger 9 | from src.test.common.base_page import Basepage 10 | 11 | class SearchPage(Basepage): 12 | 13 | def rec_search_input(self): 14 | self.logger = Logger(loggername=self.__class__.__name__).get_logger() 15 | self.logger.debug(u'找到搜索Input.') 16 | return self.find_element(selector='id=>kw') 17 | 18 | def rec_search_btn(self): 19 | self.logger = Logger(loggername=self.__class__.__name__).get_logger() 20 | self.logger.debug(u'找到百度一下Input.') 21 | return self.find_element(selector='id=>su') 22 | 23 | def click_search_btn(self): 24 | self.rec_search_btn().click() 25 | self.logger = Logger(loggername=self.__class__.__name__).get_logger() 26 | self.logger.debug(u'点击"立即登录 "按钮.') 27 | 28 | -------------------------------------------------------------------------------- /src/test/suit/docker_interface/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2018/4/13 13:08 4 | # @Author : huanghe 5 | # @Site : 6 | # @File : __init__.py.py 7 | # @Software: PyCharm -------------------------------------------------------------------------------- /src/utils/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2018/4/11 10:33 4 | # @Author : huanghe 5 | # @Site : 6 | # @File : __init__.py.py 7 | # @Software: PyCharm -------------------------------------------------------------------------------- /src/utils/browser.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2018/2/24 10:46 4 | # @Author : huanghe 5 | # @Site : 6 | # @File : browser.py 7 | # @Software: PyCharm 8 | import os 9 | from selenium import webdriver 10 | from src.utils.config import DRIVER_PATH 11 | 12 | CHROMEDRIVER_PATH = DRIVER_PATH + '\chromedriver.exe' 13 | IEDRIVER_PATH = DRIVER_PATH + '\IEDriverServer.exe' 14 | PHANTOMJSDRIVER_PATH = DRIVER_PATH + '\phantomjs.exe' 15 | 16 | TYPES = {'firefox': webdriver.Firefox, 'chrome': webdriver.Chrome, 'ie': webdriver.Ie, 'phantomjs': webdriver.PhantomJS} 17 | EXECUTABLE_PATH = {'firefox': 'geckodriver', 'chrome': CHROMEDRIVER_PATH, 'ie': IEDRIVER_PATH, 'phantomjs': PHANTOMJSDRIVER_PATH} 18 | 19 | 20 | class Browser(object): 21 | def __init__(self, browser_type='firefox'): 22 | self._type = browser_type.lower() 23 | if self._type in TYPES: 24 | self.browser = TYPES[self._type] 25 | else: 26 | raise UnSupportBrowserTypeError('仅支持%s!' % ', '.join(TYPES.keys())) 27 | self.driver = None 28 | 29 | def get_browserdriver(self,*args,**kwargs): 30 | self.driver = self.browser(executable_path=EXECUTABLE_PATH[self._type],*args,**kwargs) 31 | return self.driver 32 | 33 | 34 | def close(self): 35 | self.driver.close() 36 | 37 | def quit(self): 38 | self.driver.quit() 39 | 40 | 41 | class UnSupportBrowserTypeError(Exception): 42 | pass 43 | 44 | 45 | if __name__ == '__main__': 46 | driver = Browser().get_browserdriver() 47 | driver.get('http://www.baidu.com') 48 | elem = driver.find_element_by_id('kw') 49 | print(elem.text) 50 | 51 | -------------------------------------------------------------------------------- /src/utils/config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2018/4/11 10:58 4 | # @Author : huanghe 5 | # @Site : 6 | # @File : config.py 7 | # @Software: PyCharm 8 | import os 9 | 10 | from src.utils.file_reader import YamlReader 11 | 12 | BASE_PATH = os.path.split(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))[0] 13 | CONFIG_FILE = os.path.join(BASE_PATH, 'config', 'config.yml') 14 | LOG_PATH = os.path.join(BASE_PATH, 'log') 15 | PIR_PATH = os.path.join(BASE_PATH,'report','screenpicture\\') 16 | DATA_PATH = os.path.join(BASE_PATH,'data','baidu.xlsx') 17 | DRIVER_PATH = os.path.join(BASE_PATH,'drivers') 18 | MONGOD_PATH = os.path.join(BASE_PATH,'config','db_config.ini') 19 | 20 | class Config: 21 | def __init__(self,config=CONFIG_FILE): 22 | self.config = YamlReader(config).data 23 | 24 | def get(self,element,index=0): 25 | return self.config[index].get(element) 26 | 27 | 28 | if __name__ == '__main__': 29 | c = Config() 30 | print(BASE_PATH) -------------------------------------------------------------------------------- /src/utils/file_reader.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2018/4/11 10:45 4 | # @Author : huanghe 5 | # @Site : 6 | # @File : file_reader.py 7 | # @Software: PyCharm 8 | 9 | """" 10 | 文件读取,YamlReader读取yaml文件,ExcelReader读取excel文件。后续可添加其他类 11 | """ 12 | import yaml 13 | import os 14 | from xlrd import open_workbook 15 | import configparser as cparser 16 | 17 | class YamlReader: 18 | def __init__(self,yaml): 19 | if os.path.exists(yaml): 20 | self.yaml = yaml 21 | else: 22 | raise FileNotFoundError('配置文件不存在') 23 | self._data = None 24 | @property 25 | def data(self): 26 | if not self._data: 27 | with open(self.yaml,'rb')as f: 28 | self._data = list(yaml.safe_load_all(f)) 29 | return self._data 30 | 31 | class SheetTypeError(Exception): 32 | pass 33 | 34 | class ExcelReader: 35 | """ 36 | 读取excel文件中的内容。返回list。 37 | 38 | 如: 39 | excel中内容为: 40 | | A | B | C | 41 | | A1 | B1 | C1 | 42 | | A2 | B2 | C2 | 43 | 44 | 如果 print(ExcelReader(excel, title_line=True).data),输出结果: 45 | [{A: A1, B: B1, C:C1}, {A:A2, B:B2, C:C2}] 46 | 47 | 如果 print(ExcelReader(excel, title_line=False).data),输出结果: 48 | [[A,B,C], [A1,B1,C1], [A2,B2,C2]] 49 | 50 | 可以指定sheet,通过index或者name: 51 | ExcelReader(excel, sheet=2) 52 | ExcelReader(excel, sheet='BaiDuTest') 53 | 可用于做接口自动化 54 | """ 55 | def __init__(self, excel, sheet=0, title_line=True): 56 | if os.path.exists(excel): 57 | self.excel = excel 58 | else: 59 | raise FileNotFoundError('文件不存在!') 60 | self.sheet = sheet 61 | self.title_line = title_line 62 | self._data = list() 63 | 64 | @property 65 | def data(self): 66 | if not self._data: 67 | workbook = open_workbook(self.excel) 68 | if type(self.sheet) not in [int, str]: 69 | raise SheetTypeError('Please pass in or , not {0}'.format(type(self.sheet))) 70 | elif type(self.sheet) == int: 71 | s = workbook.sheet_by_index(self.sheet) 72 | else: 73 | s = workbook.sheet_by_name(self.sheet) 74 | 75 | if self.title_line: 76 | title = s.row_values(0) # 首行为title 77 | for col in range(1, s.nrows): 78 | # 依次遍历其余行,与首行组成dict,拼到self._data中 79 | self._data.append(dict(zip(title, s.row_values(col)))) 80 | else: 81 | for col in range(0, s.nrows): 82 | # 遍历所有行,拼到self._data中 83 | self._data.append(s.row_values(col)) 84 | return self._data 85 | 86 | 87 | -------------------------------------------------------------------------------- /src/utils/geckodriver.log: -------------------------------------------------------------------------------- 1 | 1523588460542 geckodriver INFO geckodriver 0.18.0 2 | 1523588460553 geckodriver INFO Listening on 127.0.0.1:59284 3 | 1523588462258 geckodriver::marionette INFO Starting browser D:\firefox55\firefox.exe with args ["-marionette"] 4 | 1523588464298 addons.xpi WARN Error parsing extensions state: [Exception... "Component returned failure code: 0x80520012 (NS_ERROR_FILE_NOT_FOUND) [amIAddonManagerStartup.readStartupData]" nsresult: "0x80520012 (NS_ERROR_FILE_NOT_FOUND)" location: "JS frame :: resource://gre/modules/addons/XPIProvider.jsm :: loadExtensionState :: line 1596" data: no] Stack trace: loadExtensionState()@resource://gre/modules/addons/XPIProvider.jsm:1596 < getInstallState()@resource://gre/modules/addons/XPIProvider.jsm:1631 < checkForChanges()@resource://gre/modules/addons/XPIProvider.jsm:3152 < startup()@resource://gre/modules/addons/XPIProvider.jsm:2246 < callProvider()@resource://gre/modules/AddonManager.jsm:271 < _startProvider()@resource://gre/modules/AddonManager.jsm:741 < startup()@resource://gre/modules/AddonManager.jsm:908 < startup()@resource://gre/modules/AddonManager.jsm:3122 < observe()@jar:file:///D:/firefox55/omni.ja!/components/addonManager.js:65 5 | 1523588467160 Marionette INFO Enabled via --marionette 6 | [Child 11364] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 7 | [Child 11364] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 8 | 1523588486924 Marionette INFO Listening on port 59291 9 | 1523588487166 Marionette INFO Listening on port 59291 10 | 1523588487292 Marionette WARN TLS certificate errors will be ignored for this session 11 | 1523588487352 Marionette DEBUG loaded listener.js 12 | 1523588487829 Marionette DEBUG Received DOM event "beforeunload" for "about:blank" 13 | 1523588487997 Marionette DEBUG Received DOM event "pagehide" for "about:blank" 14 | 1523588487998 Marionette DEBUG Received DOM event "unload" for "about:blank" 15 | 1523588489695 Marionette DEBUG Received DOM event "DOMContentLoaded" for "http://www.baidu.com/" 16 | 1523588490045 Marionette DEBUG Received DOM event "pageshow" for "http://www.baidu.com/" 17 | [GPU 19676] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 18 | 1523588493242 addons.productaddons WARN Failed downloading via XHR, status: 0, reason: error 19 | [Child 16564] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 20 | [Child 16564] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 21 | [GPU 19676] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 22 | 23 | ###!!! [Child][MessageChannel::SendAndWait] Error: Channel error: cannot send/recv 24 | 25 | 1523589549786 geckodriver INFO geckodriver 0.18.0 26 | 1523589549800 geckodriver INFO Listening on 127.0.0.1:59585 27 | 1523589551318 geckodriver::marionette INFO Starting browser D:\firefox55\firefox.exe with args ["-marionette"] 28 | 1523589553248 addons.xpi WARN Error parsing extensions state: [Exception... "Component returned failure code: 0x80520012 (NS_ERROR_FILE_NOT_FOUND) [amIAddonManagerStartup.readStartupData]" nsresult: "0x80520012 (NS_ERROR_FILE_NOT_FOUND)" location: "JS frame :: resource://gre/modules/addons/XPIProvider.jsm :: loadExtensionState :: line 1596" data: no] Stack trace: loadExtensionState()@resource://gre/modules/addons/XPIProvider.jsm:1596 < getInstallState()@resource://gre/modules/addons/XPIProvider.jsm:1631 < checkForChanges()@resource://gre/modules/addons/XPIProvider.jsm:3152 < startup()@resource://gre/modules/addons/XPIProvider.jsm:2246 < callProvider()@resource://gre/modules/AddonManager.jsm:271 < _startProvider()@resource://gre/modules/AddonManager.jsm:741 < startup()@resource://gre/modules/AddonManager.jsm:908 < startup()@resource://gre/modules/AddonManager.jsm:3122 < observe()@jar:file:///D:/firefox55/omni.ja!/components/addonManager.js:65 29 | 1523589555371 Marionette INFO Enabled via --marionette 30 | 1523589563452 Marionette INFO Listening on port 59591 31 | 1523589563469 Marionette INFO Listening on port 59591 32 | 1523589563925 Marionette WARN TLS certificate errors will be ignored for this session 33 | 1523589563969 Marionette DEBUG loaded listener.js 34 | 1523589564011 Marionette DEBUG Received DOM event "beforeunload" for "about:blank" 35 | 1523589564041 Marionette DEBUG Received DOM event "pagehide" for "about:blank" 36 | 1523589564042 Marionette DEBUG Received DOM event "unload" for "about:blank" 37 | 1523589564175 Marionette DEBUG Received DOM event "DOMContentLoaded" for "http://www.baidu.com/" 38 | 1523589564804 Marionette DEBUG Received DOM event "pageshow" for "http://www.baidu.com/" 39 | [GPU 18980] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 40 | [GPU 18980] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 41 | 1523589569441 addons.productaddons WARN Failed downloading via XHR, status: 0, reason: error 42 | [GPU 18980] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 43 | 44 | ###!!! [Child][MessageChannel::SendAndWait] Error: Channel error: cannot send/recv 45 | 46 | 1523590174072 geckodriver INFO geckodriver 0.18.0 47 | 1523590174111 geckodriver INFO Listening on 127.0.0.1:59914 48 | 1523590175919 geckodriver::marionette INFO Starting browser D:\firefox55\firefox.exe with args ["-marionette"] 49 | 1523590177248 addons.xpi WARN Error parsing extensions state: [Exception... "Component returned failure code: 0x80520012 (NS_ERROR_FILE_NOT_FOUND) [amIAddonManagerStartup.readStartupData]" nsresult: "0x80520012 (NS_ERROR_FILE_NOT_FOUND)" location: "JS frame :: resource://gre/modules/addons/XPIProvider.jsm :: loadExtensionState :: line 1596" data: no] Stack trace: loadExtensionState()@resource://gre/modules/addons/XPIProvider.jsm:1596 < getInstallState()@resource://gre/modules/addons/XPIProvider.jsm:1631 < checkForChanges()@resource://gre/modules/addons/XPIProvider.jsm:3152 < startup()@resource://gre/modules/addons/XPIProvider.jsm:2246 < callProvider()@resource://gre/modules/AddonManager.jsm:271 < _startProvider()@resource://gre/modules/AddonManager.jsm:741 < startup()@resource://gre/modules/AddonManager.jsm:908 < startup()@resource://gre/modules/AddonManager.jsm:3122 < observe()@jar:file:///D:/firefox55/omni.ja!/components/addonManager.js:65 50 | 1523590178202 Marionette INFO Enabled via --marionette 51 | [Child 19536] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 52 | [Child 19536] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 53 | 1523590182587 Marionette INFO Listening on port 59921 54 | 1523590182618 Marionette INFO Listening on port 59921 55 | 1523590183256 Marionette WARN TLS certificate errors will be ignored for this session 56 | 1523590183302 Marionette DEBUG loaded listener.js 57 | 1523590183334 Marionette DEBUG Received DOM event "beforeunload" for "about:blank" 58 | 1523590183367 Marionette DEBUG Received DOM event "pagehide" for "about:blank" 59 | 1523590183367 Marionette DEBUG Received DOM event "unload" for "about:blank" 60 | 1523590183533 Marionette DEBUG Received DOM event "DOMContentLoaded" for "http://www.baidu.com/" 61 | 1523590183938 Marionette DEBUG Received DOM event "pageshow" for "http://www.baidu.com/" 62 | [GPU 20028] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 63 | 1523590203405 addons.productaddons WARN Failed downloading via XHR, status: 0, reason: error 64 | [Parent 19732] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 65 | [Child 12536] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 66 | [Child 12536] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 67 | [GPU 20028] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 68 | 69 | ###!!! [Child][MessageChannel::SendAndWait] Error: Channel error: cannot send/recv 70 | 71 | 1523590205772 geckodriver INFO geckodriver 0.18.0 72 | 1523590205781 geckodriver INFO Listening on 127.0.0.1:59969 73 | 1523590207820 geckodriver::marionette INFO Starting browser D:\firefox55\firefox.exe with args ["-marionette"] 74 | 1523590208276 addons.xpi WARN Error parsing extensions state: [Exception... "Component returned failure code: 0x80520012 (NS_ERROR_FILE_NOT_FOUND) [amIAddonManagerStartup.readStartupData]" nsresult: "0x80520012 (NS_ERROR_FILE_NOT_FOUND)" location: "JS frame :: resource://gre/modules/addons/XPIProvider.jsm :: loadExtensionState :: line 1596" data: no] Stack trace: loadExtensionState()@resource://gre/modules/addons/XPIProvider.jsm:1596 < getInstallState()@resource://gre/modules/addons/XPIProvider.jsm:1631 < checkForChanges()@resource://gre/modules/addons/XPIProvider.jsm:3152 < startup()@resource://gre/modules/addons/XPIProvider.jsm:2246 < callProvider()@resource://gre/modules/AddonManager.jsm:271 < _startProvider()@resource://gre/modules/AddonManager.jsm:741 < startup()@resource://gre/modules/AddonManager.jsm:908 < startup()@resource://gre/modules/AddonManager.jsm:3122 < observe()@jar:file:///D:/firefox55/omni.ja!/components/addonManager.js:65 75 | 1523590209324 Marionette INFO Enabled via --marionette 76 | 1523590212718 Marionette INFO Listening on port 59975 77 | 1523590212754 Marionette INFO Listening on port 59975 78 | 1523590213043 Marionette WARN TLS certificate errors will be ignored for this session 79 | 1523590213092 Marionette DEBUG loaded listener.js 80 | 1523590213180 Marionette DEBUG Received DOM event "beforeunload" for "about:blank" 81 | 1523590213229 Marionette DEBUG Received DOM event "pagehide" for "about:blank" 82 | 1523590213229 Marionette DEBUG Received DOM event "unload" for "about:blank" 83 | 1523590213319 Marionette DEBUG Received DOM event "DOMContentLoaded" for "http://www.baidu.com/" 84 | 1523590214006 Marionette DEBUG Received DOM event "pageshow" for "http://www.baidu.com/" 85 | [GPU 21284] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 86 | [Child 19100] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 87 | [Child 19100] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 88 | [GPU 21284] WARNING: pipe error: 109: file c:/builds/moz2_slave/m-rel-w32-00000000000000000000/build/src/ipc/chromium/src/chrome/common/ipc_channel_win.cc, line 346 89 | 90 | ###!!! [Child][MessageChannel::SendAndWait] Error: Channel error: cannot send/recv 91 | 92 | -------------------------------------------------------------------------------- /src/utils/log.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2018/4/11 14:51 4 | # @Author : huanghe 5 | # @Site : 6 | # @File : log.py 7 | # @Software: PyCharm 8 | import logging 9 | import os 10 | from logging.handlers import TimedRotatingFileHandler 11 | from src.utils.config import Config 12 | from src.utils.config import LOG_PATH 13 | 14 | 15 | class Logger(object): 16 | 17 | def __init__(self,loggername): 18 | self.logger = logging.getLogger(loggername) 19 | logging.root.setLevel(logging.NOTSET) 20 | c = Config().get('log') 21 | self.log_file_name = c.get('file_name') if c and c.get('file_name') else 'test.log' # 日志文件 22 | self.backup_count = c.get('backup') if c and c.get('backup') else 5 # 保留的日志数量 23 | # 日志输出级别 24 | self.console_output_level = c.get('console_level') if c and c.get('console_level') else 'WARNING' 25 | self.file_output_level = c.get('file_level') if c and c.get('file_level') else 'DEBUG' 26 | # 日志输出格式 27 | pattern = c.get('pattern') if c and c.get('pattern') else '%(asctime)s - %(name)s - %(levelname)s - %(message)s' 28 | self.formatter = logging.Formatter(pattern) 29 | 30 | def get_logger(self): 31 | """在logger中添加日志句柄并返回,如果logger已有句柄,则直接返回 32 | 我们这里添加两个句柄,一个输出日志到控制台,另一个输出到日志文件。 33 | 两个句柄的日志级别不同,在配置文件中可设置。 34 | """ 35 | if not self.logger.handlers: # 避免重复日志 36 | console_handler = logging.StreamHandler() 37 | console_handler.setFormatter(self.formatter) 38 | console_handler.setLevel(self.console_output_level) 39 | self.logger.addHandler(console_handler) 40 | 41 | # 每天重新创建一个日志文件,最多保留backup_count份 42 | file_handler = TimedRotatingFileHandler(filename=os.path.join(LOG_PATH, self.log_file_name), 43 | when='D', 44 | interval=1, 45 | backupCount=self.backup_count, 46 | delay=True, 47 | encoding='utf-8' 48 | ) 49 | file_handler.setFormatter(self.formatter) 50 | file_handler.setLevel(self.file_output_level) 51 | self.logger.addHandler(file_handler) 52 | return self.logger 53 | 54 | if __name__ == '__main__': 55 | 56 | logger = Logger(loggername='he').get_logger() 57 | logger.info('info message') 58 | logger.debug('debug message') 59 | logger.critical('ce message') 60 | logger.error('error meaagse') 61 | -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2018/4/12 10:43 4 | # @Author : huanghe 5 | # @Site : 6 | # @File : test.py 7 | # @Software: PyCharm 8 | '''a =3 9 | c =1 10 | b = 2 11 | d =b if b and a else c 12 | print(d) 13 | print(a and b) 14 | and 操作,a and b a为真输出b a为假输出a 15 | ''' 16 | '''import logging 17 | 18 | # 创建一个logger 19 | logger = logging.getLogger() 20 | 21 | # 创建一个handler,用于写入日志文件 22 | fh = logging.FileHandler('/tmp/test.log') 23 | 24 | # 再创建一个handler,用于输出到控制台 25 | ch = logging.StreamHandler() 26 | 27 | # 定义handler的输出格式formatter 28 | formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') 29 | fh.setFormatter(formatter) 30 | ch.setFormatter(formatter) 31 | 32 | #定义一个filter 33 | #filter = logging.Filter('mylogger.child1.child2') 34 | #fh.addFilter(filter) 35 | 36 | # 给logger添加handler 37 | #logger.addFilter(filter) 38 | logger.addHandler(fh) 39 | logger.addHandler(ch) 40 | 41 | 42 | 43 | # 记录一条日志 44 | logger.debug('logger debug message') 45 | logger.info('logger info message') 46 | logger.warning('logger warning message') 47 | logger.error('logger error message') 48 | logger.critical('logger critical message')''' 49 | 50 | '''from src.utils.file_reader import ExcelReader 51 | from src.utils.config import DATA_PATH 52 | 53 | dates = ExcelReader(DATA_PATH).data 54 | for date in dates: 55 | print(date) 56 | 57 | print(dates[1]['search'])''' 58 | #TYPES = {'firefox': webdriver.Firefox, 'chrome': webdriver.Chrome, 'ie': webdriver.Ie, 'phantomjs': webdriver.PhantomJS} 59 | a = 'Fdaer' 60 | print(a[::-1]) --------------------------------------------------------------------------------