├── .gitignore ├── .idea ├── UItestframework.iml ├── inspectionProfiles │ ├── Project_Default.xml │ └── profiles_settings.xml ├── misc.xml ├── modules.xml ├── vcs.xml └── workspace.xml ├── config ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-35.pyc │ └── globalparam.cpython-35.pyc ├── config.ini └── globalparam.py ├── data └── testdata │ └── searKey.xlsx ├── public ├── __init__.py ├── __pycache__ │ └── __init__.cpython-35.pyc ├── common │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-35.pyc │ │ ├── basepage.cpython-35.pyc │ │ ├── datainfo.cpython-35.pyc │ │ ├── log.cpython-35.pyc │ │ ├── mytest.cpython-35.pyc │ │ ├── pyselenium.cpython-35.pyc │ │ ├── readconfig.cpython-35.pyc │ │ └── sendmail.cpython-35.pyc │ ├── basepage.py │ ├── datainfo.py │ ├── log.py │ ├── mytest.py │ ├── publicfunction.py │ ├── pyselenium.py │ ├── readconfig.py │ └── sendmail.py └── pages │ ├── __init__.py │ ├── __pycache__ │ ├── __init__.cpython-35.pyc │ └── baiduIndexPage.cpython-35.pyc │ └── baiduIndexPage.py ├── readme.md ├── report ├── log │ └── 2016-11-08.log └── testreport │ └── TestResult2016-11-08_11_17_14.html ├── run.py └── testcase ├── __pycache__ └── test_baidu.cpython-35.pyc └── test_baidu.py /.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoshitoutester/UItestframework/b8d3125ed8ffacfd77fc271c6bf1e7105035c0c9/.gitignore -------------------------------------------------------------------------------- /.idea/UItestframework.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 74 | 75 | 76 | 78 | 79 | 100 | 101 | 102 | 103 | 104 | true 105 | DEFINITION_ORDER 106 | 107 | 108 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 145 | 146 | 147 | 148 | 151 | 152 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 198 | 199 | 216 | 217 | 234 | 235 | 252 | 253 | 270 | 271 | 290 | 291 | 292 | 293 | 294 | 307 | 308 | 321 | 322 | 339 | 340 | 352 | 353 | project 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 388 | 389 | 408 | 409 | 430 | 431 | 453 | 454 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 1478222299195 505 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 538 | 539 | 542 | 545 | 546 | 547 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 | 755 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | 766 | 767 | 768 | 769 | 770 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | 784 | 785 | 786 | 787 | 788 | 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 804 | 805 | -------------------------------------------------------------------------------- /config/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoshitoutester/UItestframework/b8d3125ed8ffacfd77fc271c6bf1e7105035c0c9/config/__init__.py -------------------------------------------------------------------------------- /config/__pycache__/__init__.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoshitoutester/UItestframework/b8d3125ed8ffacfd77fc271c6bf1e7105035c0c9/config/__pycache__/__init__.cpython-35.pyc -------------------------------------------------------------------------------- /config/__pycache__/globalparam.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoshitoutester/UItestframework/b8d3125ed8ffacfd77fc271c6bf1e7105035c0c9/config/__pycache__/globalparam.cpython-35.pyc -------------------------------------------------------------------------------- /config/config.ini: -------------------------------------------------------------------------------- 1 | [projectConfig] 2 | project_path=E:\Python-Project\UItestframework 3 | -------------------------------------------------------------------------------- /config/globalparam.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | 3 | import os 4 | from public.common.readconfig import ReadConfig 5 | 6 | # 读取配置文件 7 | config_file_path = os.path.split(os.path.realpath(__file__))[0] 8 | read_config = ReadConfig(os.path.join(config_file_path,'config.ini')) 9 | # 项目参数设置 10 | prj_path = read_config.getValue('projectConfig','project_path') 11 | # 日志路径 12 | log_path = os.path.join(prj_path, 'report', 'log') 13 | # 截图文件路径 14 | img_path = os.path.join(prj_path, 'report', 'image') 15 | # 测试报告路径 16 | report_path = os.path.join(prj_path, 'report', 'testreport') 17 | # 默认浏览器 18 | browser = 'firefox' 19 | 20 | # 测试数据路径 21 | data_path = os.path.join(prj_path, 'data', 'testdata') 22 | -------------------------------------------------------------------------------- /data/testdata/searKey.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoshitoutester/UItestframework/b8d3125ed8ffacfd77fc271c6bf1e7105035c0c9/data/testdata/searKey.xlsx -------------------------------------------------------------------------------- /public/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoshitoutester/UItestframework/b8d3125ed8ffacfd77fc271c6bf1e7105035c0c9/public/__init__.py -------------------------------------------------------------------------------- /public/__pycache__/__init__.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoshitoutester/UItestframework/b8d3125ed8ffacfd77fc271c6bf1e7105035c0c9/public/__pycache__/__init__.cpython-35.pyc -------------------------------------------------------------------------------- /public/common/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoshitoutester/UItestframework/b8d3125ed8ffacfd77fc271c6bf1e7105035c0c9/public/common/__init__.py -------------------------------------------------------------------------------- /public/common/__pycache__/__init__.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoshitoutester/UItestframework/b8d3125ed8ffacfd77fc271c6bf1e7105035c0c9/public/common/__pycache__/__init__.cpython-35.pyc -------------------------------------------------------------------------------- /public/common/__pycache__/basepage.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoshitoutester/UItestframework/b8d3125ed8ffacfd77fc271c6bf1e7105035c0c9/public/common/__pycache__/basepage.cpython-35.pyc -------------------------------------------------------------------------------- /public/common/__pycache__/datainfo.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoshitoutester/UItestframework/b8d3125ed8ffacfd77fc271c6bf1e7105035c0c9/public/common/__pycache__/datainfo.cpython-35.pyc -------------------------------------------------------------------------------- /public/common/__pycache__/log.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoshitoutester/UItestframework/b8d3125ed8ffacfd77fc271c6bf1e7105035c0c9/public/common/__pycache__/log.cpython-35.pyc -------------------------------------------------------------------------------- /public/common/__pycache__/mytest.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoshitoutester/UItestframework/b8d3125ed8ffacfd77fc271c6bf1e7105035c0c9/public/common/__pycache__/mytest.cpython-35.pyc -------------------------------------------------------------------------------- /public/common/__pycache__/pyselenium.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoshitoutester/UItestframework/b8d3125ed8ffacfd77fc271c6bf1e7105035c0c9/public/common/__pycache__/pyselenium.cpython-35.pyc -------------------------------------------------------------------------------- /public/common/__pycache__/readconfig.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoshitoutester/UItestframework/b8d3125ed8ffacfd77fc271c6bf1e7105035c0c9/public/common/__pycache__/readconfig.cpython-35.pyc -------------------------------------------------------------------------------- /public/common/__pycache__/sendmail.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoshitoutester/UItestframework/b8d3125ed8ffacfd77fc271c6bf1e7105035c0c9/public/common/__pycache__/sendmail.cpython-35.pyc -------------------------------------------------------------------------------- /public/common/basepage.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | 3 | class Page(object): 4 | """ 5 | This is a base page class for Page Object. 6 | """ 7 | def __init__(self, selenium_driver): 8 | self.dr = selenium_driver 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /public/common/datainfo.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | 3 | import codecs 4 | import os 5 | import xlrd 6 | from config import globalparam 7 | 8 | data_path = globalparam.data_path 9 | def get_xls_to_dict(xlsname, sheetname): 10 | """ 11 | 读取excel表结果为dict 12 | 第一行为字典的key,下面的为值 13 | return [{'title':'1','user':'root'},{'title':'2','user':'xiaoshitou'}] 14 | """ 15 | # dataresult = [] 16 | # result = [] 17 | datapath = os.path.join(data_path,xlsname) 18 | xls1 = xlrd.open_workbook(datapath) 19 | table = xls1.sheet_by_name(sheetname) 20 | # for i in range(0,table.nrows): 21 | # dataresult.append(table.row_values(i)) 22 | dataresult = [table.row_values(i) for i in range(0, tabl.nrows)] 23 | #将list转化成dict 24 | # for i in range(1,len(dataresult)): 25 | # temp = dict(zip(dataresult[0],dataresult[i])) 26 | # result.append(temp) 27 | 28 | result = [ dict(zip(dataresult[0], dataresult[i])) for i in range(1, len(dataresult))] 29 | return result 30 | 31 | def get_url_data(title): 32 | """ 33 | 读取txt文件,转化成dict;读取url和导航栏的对应关系 34 | 将txt转化成一个字典:下单=>/admin/order/index 35 | {'title1':'url1','下单':'/admin/order/index'} 36 | """ 37 | name = 'urlsource.txt' 38 | txtpath = os.path.join(data_path,name) 39 | with codecs.open(txtpath,'r',encoding='utf-8') as f: 40 | txtcontent = f.readlines() 41 | txtdict = dict([txt.strip().replace('\ufeff','').split('=>') for txt in txtcontent]) 42 | return txtdict[title] 43 | 44 | def get_xls_to_list(excelname, sheetname): 45 | """ 46 | 读取excel表,返回一个list,只是返回第一列的值 47 | return [1,2,3,4,5] 48 | """ 49 | datapath = os.path.join(data_path, excelname) 50 | excel = xlrd.open_workbook(datapath) 51 | table = excel.sheet_by_name(sheetname) 52 | result = [table.row_values(i)[0].strip() for i in range(1,table.nrows)] 53 | return result 54 | 55 | if __name__=='__main__': 56 | res = get_xls_to_list('addressParse.xlsx','Sheet1') 57 | res = get_xls_to_dict('admin_single_order.xlsx','ordermsg') 58 | print(res) 59 | 60 | 61 | -------------------------------------------------------------------------------- /public/common/log.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | 3 | import logging 4 | import time 5 | import os 6 | from config import globalparam 7 | 8 | log_path = globalparam.log_path 9 | class Log: 10 | def __init__(self): 11 | self.logname = os.path.join(log_path, '{0}.log'.format(time.strftime('%Y-%m-%d'))) 12 | 13 | def __printconsole(self, level, message): 14 | # 创建一个logger 15 | logger = logging.getLogger() 16 | logger.setLevel(logging.DEBUG) 17 | # 创建一个handler,用于写入日志文件 18 | fh = logging.FileHandler(self.logname,'a',encoding='utf-8') 19 | fh.setLevel(logging.DEBUG) 20 | # 再创建一个handler,用于输出到控制台 21 | ch = logging.StreamHandler() 22 | ch.setLevel(logging.DEBUG) 23 | # 定义handler的输出格式 24 | formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') 25 | fh.setFormatter(formatter) 26 | ch.setFormatter(formatter) 27 | # 给logger添加handler 28 | logger.addHandler(fh) 29 | logger.addHandler(ch) 30 | # 记录一条日志 31 | if level == 'info': 32 | logger.info(message) 33 | elif level == 'debug': 34 | logger.debug(message) 35 | elif level == 'warning': 36 | logger.warning(message) 37 | elif level == 'error': 38 | logger.error(message) 39 | logger.removeHandler(ch) 40 | logger.removeHandler(fh) 41 | # 关闭打开的文件 42 | fh.close() 43 | 44 | def debug(self,message): 45 | self.__printconsole('debug', message) 46 | 47 | def info(self,message): 48 | self.__printconsole('info', message) 49 | 50 | def warning(self,message): 51 | self.__printconsole('warning', message) 52 | 53 | def error(self,message): 54 | self.__printconsole('error', message) 55 | -------------------------------------------------------------------------------- /public/common/mytest.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | 3 | import unittest 4 | from public.common import pyselenium 5 | from config import globalparam 6 | from public.common.log import Log 7 | 8 | 9 | class MyTest(unittest.TestCase): 10 | """ 11 | The base class is for all testcase. 12 | """ 13 | def setUp(self): 14 | self.logger = Log() 15 | self.logger.info('############################### START ###############################') 16 | self.dr = pyselenium.PySelenium(globalparam.browser) 17 | self.dr.max_window() 18 | 19 | def tearDown(self): 20 | self.dr.quit() 21 | self.logger.info('############################### End ###############################') 22 | -------------------------------------------------------------------------------- /public/common/publicfunction.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | 3 | from config import globalparam 4 | 5 | 6 | # 截图放到report下的img目录下 7 | def get_img(dr, filename): 8 | path = globalparam.img_path + '\\' + filename 9 | dr.take_screenshot(path) 10 | 11 | -------------------------------------------------------------------------------- /public/common/pyselenium.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | 3 | import time 4 | from selenium import webdriver 5 | from selenium.webdriver.common.action_chains import ActionChains 6 | from selenium.webdriver.support import expected_conditions as EC 7 | from selenium.webdriver.support.ui import WebDriverWait 8 | from selenium.webdriver.common.by import By 9 | from selenium.webdriver.common.keys import Keys 10 | from selenium.common.exceptions import TimeoutException 11 | from public.common.log import Log 12 | 13 | success = "SUCCESS " 14 | fail = "FAIL " 15 | logger = Log() 16 | 17 | class PySelenium(object): 18 | """ 19 | pyselenium framework for the main class, the original 20 | selenium provided by the method of the two packaging, 21 | making it easier to use. 22 | """ 23 | 24 | def __init__(self, browser='ff', remoteAddress=None): 25 | """ 26 | remote consle: 27 | dr = PySelenium('RChrome','127.0.0.1:8080') 28 | """ 29 | t1 = time.time() 30 | dc = {'platform': 'ANY', 'browserName': 'chrome', 'version': '', 'javascriptEnabled': True} 31 | dr = None 32 | if remoteAddress is None: 33 | if browser == "firefox" or browser == "ff": 34 | dr = webdriver.Firefox() 35 | elif browser == "chrome" or browser == "Chrome": 36 | dr = webdriver.Chrome() 37 | elif browser == "internet explorer" or browser == "ie": 38 | dr = webdriver.Ie() 39 | elif browser == "opera": 40 | dr = webdriver.Opera() 41 | elif browser == "phantomjs": 42 | dr = webdriver.PhantomJS() 43 | elif browser == "edge": 44 | dr = webdriver.Edge() 45 | else: 46 | if browser == "RChrome": 47 | dr = webdriver.Remote(command_executor='http://' + remoteAddress + '/wd/hub', 48 | desired_capabilities=dc) 49 | elif browser == "RIE": 50 | dc['browserName'] = 'internet explorer' 51 | dr = webdriver.Remote(command_executor='http://' + remoteAddress + '/wd/hub', 52 | desired_capabilities=dc) 53 | elif browser == "RFirefox": 54 | dc['browserName'] = 'firefox' 55 | dc['marionette'] = False 56 | dr = webdriver.Remote(command_executor='http://' + remoteAddress + '/wd/hub', 57 | desired_capabilities=dc) 58 | try: 59 | self.driver = dr 60 | self.my_print("{0} Start a new browser: {1}, Spend {2} seconds".format(success,browser,time.time()-t1)) 61 | except Exception: 62 | raise NameError("Not found {0} browser,You can enter 'ie','ff'," 63 | "'chrome','RChrome','RIe' or 'RFirefox'.".format( browser)) 64 | 65 | def my_print(self,msg): 66 | logger.info(msg) 67 | 68 | def element_wait(self, css, secs=5): 69 | """ 70 | Waiting for an element to display. 71 | 72 | Usage: 73 | driver.element_wait("id->kw",10) 74 | """ 75 | if "->" not in css: 76 | raise NameError("Positioning syntax errors, lack of '->'.") 77 | 78 | by = css.split("->")[0].strip() 79 | value = css.split("->")[1].strip() 80 | messages = 'Element: {0} not found in {1} seconds.'.format(css, secs) 81 | 82 | if by == "id": 83 | WebDriverWait(self.driver, secs, 1).until(EC.presence_of_element_located((By.ID, value)), messages) 84 | elif by == "name": 85 | WebDriverWait(self.driver, secs, 1).until(EC.presence_of_element_located((By.NAME, value)), messages) 86 | elif by == "class": 87 | WebDriverWait(self.driver, secs, 1).until(EC.presence_of_element_located((By.CLASS_NAME, value)), messages) 88 | elif by == "link_text": 89 | WebDriverWait(self.driver, secs, 1).until(EC.presence_of_element_located((By.LINK_TEXT, value)), messages) 90 | elif by == "xpath": 91 | WebDriverWait(self.driver, secs, 1).until(EC.presence_of_element_located((By.XPATH, value)), messages) 92 | elif by == "css": 93 | WebDriverWait(self.driver, secs, 1).until(EC.presence_of_element_located((By.CSS_SELECTOR, value)),messages) 94 | else: 95 | raise NameError("Please enter the correct targeting elements,'id','name','class','link_text','xpaht','css'.") 96 | 97 | def get_element(self, css): 98 | """ 99 | Judge element positioning way, and returns the element. 100 | 101 | Usage: 102 | driver.get_element('id->kw') 103 | """ 104 | if "->" not in css: 105 | raise NameError("Positioning syntax errors, lack of '->'.") 106 | 107 | by = css.split("->")[0].strip() 108 | value = css.split("->")[1].strip() 109 | 110 | if by == "id": 111 | element = self.driver.find_element_by_id(value) 112 | elif by == "name": 113 | element = self.driver.find_element_by_name(value) 114 | elif by == "class": 115 | element = self.driver.find_element_by_class_name(value) 116 | elif by == "link_text": 117 | element = self.driver.find_element_by_link_text(value) 118 | elif by == "xpath": 119 | element = self.driver.find_element_by_xpath(value) 120 | elif by == "css": 121 | element = self.driver.find_element_by_css_selector(value) 122 | else: 123 | raise NameError("Please enter the correct targeting elements,'id','name','class','link_text','xpaht','css'.") 124 | return element 125 | 126 | def open(self, url): 127 | """ 128 | open url. 129 | 130 | Usage: 131 | driver.open("https://www.baidu.com") 132 | """ 133 | t1 = time.time() 134 | try: 135 | self.driver.get(url) 136 | self.my_print("{0} Navigated to {1}, Spend {2} seconds".format(success,url,time.time()-t1)) 137 | except Exception: 138 | self.my_print("{0} Unable to load {1}, Spend {2} seconds".format(fail, url, time.time() - t1)) 139 | raise 140 | 141 | def max_window(self): 142 | """ 143 | Set browser window maximized. 144 | 145 | Usage: 146 | driver.max_window() 147 | """ 148 | t1 = time.time() 149 | self.driver.maximize_window() 150 | self.my_print("{0} Set browser window maximized, Spend {1} seconds".format(success, time.time() - t1)) 151 | 152 | def set_window(self, wide, high): 153 | """ 154 | Set browser window wide and high. 155 | 156 | Usage: 157 | driver.set_window(wide,high) 158 | """ 159 | t1 = time.time() 160 | self.driver.set_window_size(wide, high) 161 | self.my_print("{0} Set browser window wide: {1},high: {2}, Spend {3} seconds".format(success, 162 | wide,high,time.time() - t1)) 163 | 164 | def type(self, css, text): 165 | """ 166 | Operation input box. 167 | 168 | Usage: 169 | driver.type("id->kw","selenium") 170 | """ 171 | t1 = time.time() 172 | try: 173 | self.element_wait(css) 174 | el = self.get_element(css) 175 | el.send_keys(text) 176 | self.my_print("{0} Typed element: <{1}> content: {2}, Spend {3} seconds".format(success, 177 | css,text,time.time() - t1)) 178 | except Exception: 179 | self.my_print("{0} Unable to type element: <{1}> content: {2}, Spend {3} seconds".format(fail, 180 | css, text, time.time() - t1)) 181 | raise 182 | 183 | def clear_type(self, css, text): 184 | """ 185 | Clear and input element. 186 | 187 | Usage: 188 | driver.clear_type("id->kw","selenium") 189 | """ 190 | t1 = time.time() 191 | try: 192 | self.element_wait(css) 193 | el = self.get_element(css) 194 | el.clear() 195 | el.send_keys(text) 196 | self.my_print("{0} Clear and type element: <{1}> content: {2}, Spend {3} seconds".format(success, 197 | css, text,time.time() - t1)) 198 | except Exception: 199 | self.my_print("{0} Unable to clear and type element: <{1}> content: {2}, Spend {3} seconds".format(fail, 200 | css, text,time.time() - t1)) 201 | raise 202 | 203 | def click(self, css): 204 | """ 205 | It can click any text / image can be clicked 206 | Connection, check box, radio buttons, and even drop-down box etc.. 207 | 208 | Usage: 209 | driver.click("id->kw") 210 | """ 211 | t1 = time.time() 212 | try: 213 | self.element_wait(css) 214 | el = self.get_element(css) 215 | el.click() 216 | self.my_print("{0} Clicked element: <{1}>, Spend {2} seconds".format(success,css,time.time() - t1)) 217 | except Exception: 218 | self.my_print("{0} Unable to click element: <{1}>, Spend {2} seconds".format(fail, css, time.time() - t1)) 219 | raise 220 | 221 | def right_click(self, css): 222 | """ 223 | Right click element. 224 | 225 | Usage: 226 | driver.right_click("id->kw") 227 | """ 228 | t1 = time.time() 229 | try: 230 | self.element_wait(css) 231 | el = self.get_element(css) 232 | ActionChains(self.driver).context_click(el).perform() 233 | self.my_print("{0} Right click element: <{1}>, Spend {2} seconds".format(success, css, time.time() - t1)) 234 | except Exception: 235 | self.my_print("{0} Unable to right click element: <{1}>, Spend {2} seconds".format(fail, css, time.time() - t1)) 236 | raise 237 | 238 | def move_to_element(self, css): 239 | """ 240 | Mouse over the element. 241 | 242 | Usage: 243 | driver.move_to_element("id->kw") 244 | """ 245 | t1 = time.time() 246 | try: 247 | self.element_wait(css) 248 | el = self.get_element(css) 249 | ActionChains(self.driver).move_to_element(el).perform() 250 | self.my_print("{0} Move to element: <{1}>, Spend {2} seconds".format(success, css, time.time() - t1)) 251 | except Exception: 252 | self.my_print("{0} unable move to element: <{1}>, Spend {2} seconds".format(fail, css, time.time() - t1)) 253 | raise 254 | 255 | def double_click(self, css): 256 | """ 257 | Double click element. 258 | 259 | Usage: 260 | driver.double_click("id->kw") 261 | """ 262 | t1 = time.time() 263 | try: 264 | self.element_wait(css) 265 | el = self.get_element(css) 266 | ActionChains(self.driver).double_click(el).perform() 267 | self.my_print("{0} Double click element: <{1}>, Spend {2} seconds".format(success, css, time.time() - t1)) 268 | except Exception: 269 | self.my_print("{0} Unable to double click element: <{1}>, Spend {2} seconds".format(fail, css, time.time() - t1)) 270 | raise 271 | 272 | def drag_and_drop(self, el_css, ta_css): 273 | """ 274 | Drags an element a certain distance and then drops it. 275 | 276 | Usage: 277 | driver.drag_and_drop("id->kw","id->su") 278 | """ 279 | t1 = time.time() 280 | try: 281 | self.element_wait(el_css) 282 | element = self.get_element(el_css) 283 | self.element_wait(ta_css) 284 | target = self.get_element(ta_css) 285 | ActionChains(driver).drag_and_drop(element, target).perform() 286 | self.my_print("{0} Drag and drop element: <{1}> to element: <{2}>, Spend {3} seconds".format(success, 287 | el_css,ta_css, time.time() - t1)) 288 | except Exception: 289 | self.my_print("{0} Unable to drag and drop element: <{1}> to element: <{2}>, Spend {3} seconds".format(fail, 290 | el_css, ta_css, time.time() - t1)) 291 | raise 292 | 293 | def click_text(self, text): 294 | """ 295 | Click the element by the link text 296 | 297 | Usage: 298 | driver.click_text("新闻") 299 | """ 300 | t1 = time.time() 301 | try: 302 | self.driver.find_element_by_partial_link_text(text).click() 303 | self.my_print("{0} Click by text content: {1}, Spend {2} seconds".format(success, text,time.time() - t1)) 304 | except Exception: 305 | self.my_print("{0} Unable to Click by text content: {1}, Spend {2} seconds".format(fail, text, time.time() - t1)) 306 | raise 307 | 308 | def close(self): 309 | """ 310 | Simulates the user clicking the "close" button in the titlebar of a popup 311 | window or tab. 312 | 313 | Usage: 314 | driver.close() 315 | """ 316 | t1 = time.time() 317 | self.driver.close() 318 | self.my_print("{0} Closed current window, Spend {1} seconds".format(success, time.time() - t1)) 319 | 320 | def quit(self): 321 | """ 322 | Quit the driver and close all the windows. 323 | 324 | Usage: 325 | driver.quit() 326 | """ 327 | t1 = time.time() 328 | self.driver.quit() 329 | self.my_print("{0} Closed all window and quit the driver, Spend {1} seconds".format(success, time.time() - t1)) 330 | 331 | def submit(self, css): 332 | """ 333 | Submit the specified form. 334 | 335 | Usage: 336 | driver.submit("id->kw") 337 | """ 338 | t1 = time.time() 339 | try: 340 | self.element_wait(css) 341 | el = self.get_element(css) 342 | el.submit() 343 | self.my_print("{0} Submit form args element: <{1}>, Spend {2} seconds".format(success,css, time.time() - t1)) 344 | except Exception: 345 | self.my_print("{0} Unable to submit form args element: <{1}>, Spend {2} seconds".format(fail, css, time.time() - t1)) 346 | raise 347 | 348 | def F5(self): 349 | """ 350 | Refresh the current page. 351 | 352 | Usage: 353 | driver.F5() 354 | """ 355 | t1 = time 356 | self.driver.refresh() 357 | self.my_print("{0} Refresh the current page, Spend {1} seconds".format(success, time.time() - t1)) 358 | 359 | def js(self, script): 360 | """ 361 | Execute JavaScript scripts. 362 | 363 | Usage: 364 | driver.js("window.scrollTo(200,1000);") 365 | """ 366 | t1 = time.time() 367 | try: 368 | self.driver.execute_script(script) 369 | self.my_print("{0} Execute javascript scripts: {1}, Spend {2} seconds".format(success,script, time.time() - t1)) 370 | except Exception: 371 | self.my_print("{0} Unable to execute javascript scripts: {1}, Spend {2} seconds".format(fail, 372 | script, time.time() - t1)) 373 | raise 374 | 375 | def get_attribute(self, css, attribute): 376 | """ 377 | Gets the value of an element attribute. 378 | 379 | Usage: 380 | driver.get_attribute("id->su","href") 381 | """ 382 | t1 = time.time() 383 | try: 384 | el = self.get_element(css) 385 | attr = el.get_attribute(attribute) 386 | self.my_print("{0} Get attribute element: <{1}>,attribute: {2}, Spend {3} seconds".format(success, 387 | css,attribute,time.time()-t1)) 388 | return attr 389 | except Exception: 390 | self.my_print("{0} Unable to get attribute element: <{1}>,attribute: {2}, Spend {3} seconds".format(fail, 391 | css, attribute,time.time() - t1)) 392 | raise 393 | 394 | def get_text(self, css): 395 | """ 396 | Get element text information. 397 | 398 | Usage: 399 | driver.get_text("id->kw") 400 | """ 401 | t1 = time.time() 402 | try: 403 | self.element_wait(css) 404 | text = self.get_element(css).text 405 | self.my_print("{0} Get element text element: <{1}>, Spend {2} seconds".format(success,css,time.time()-t1)) 406 | return text 407 | except Exception: 408 | self.my_print("{0} Unable to get element text element: <{1}>, Spend {2} seconds".format(fail, css, time.time() - t1)) 409 | raise 410 | 411 | def get_title(self): 412 | """ 413 | Get window title. 414 | 415 | Usage: 416 | driver.get_title() 417 | """ 418 | 419 | t1 = time.time() 420 | title = self.driver.title 421 | self.my_print("{0} Get current window title, Spend {1} seconds".format(success, time.time() - t1)) 422 | return title 423 | 424 | def get_url(self): 425 | """ 426 | Get the URL address of the current page. 427 | 428 | Usage: 429 | driver.get_url() 430 | """ 431 | t1 = time.time() 432 | url = self.driver.current_url 433 | self.my_print("{0} Get current window url, Spend {1} seconds".format(success, time.time() - t1)) 434 | return url 435 | 436 | def wait(self, secs): 437 | """ 438 | Implicitly wait.All elements on the page. 439 | 440 | Usage: 441 | driver.wait(10) 442 | """ 443 | t1 = time.time() 444 | self.driver.implicitly_wait(secs) 445 | self.my_print("{0} Set wait all element display in {1} seconds, Spend {2} seconds".format(success, 446 | secs,time.time() - t1)) 447 | 448 | def accept_alert(self): 449 | """ 450 | Accept warning box. 451 | 452 | Usage: 453 | driver.accept_alert() 454 | """ 455 | t1 = time.time() 456 | self.driver.switch_to.alert.accept() 457 | self.my_print("{0} Accept warning box, Spend {1} seconds".format(success, time.time() - t1)) 458 | 459 | def dismiss_alert(self): 460 | """ 461 | Dismisses the alert available. 462 | 463 | Usage: 464 | driver.dismiss_alert() 465 | """ 466 | t1 = time.time() 467 | self.driver.switch_to.alert.dismiss() 468 | self.my_print("{0} Dismisses the alert available, Spend {1} seconds".format(success, time.time() - t1)) 469 | 470 | def switch_to_frame(self, css): 471 | """ 472 | Switch to the specified frame. 473 | 474 | Usage: 475 | driver.switch_to_frame("id->kw") 476 | """ 477 | t1 = time.time() 478 | try: 479 | self.element_wait(css) 480 | iframe_el = self.get_element(css) 481 | self.driver.switch_to.frame(iframe_el) 482 | self.my_print("{0} Switch to frame element: <{1}>, Spend {2} seconds".format(success,css, time.time() - t1)) 483 | except Exception: 484 | self.my_print("{0} Unable switch to frame element: <{1}>, Spend {2} seconds".format(fail, css, time.time() - t1)) 485 | raise 486 | 487 | def switch_to_frame_out(self): 488 | """ 489 | Returns the current form machine form at the next higher level. 490 | Corresponding relationship with switch_to_frame () method. 491 | 492 | Usage: 493 | driver.switch_to_frame_out() 494 | """ 495 | t1 = time.time() 496 | self.driver.switch_to.default_content() 497 | self.my_print("{0} Switch to frame out, Spend {1} seconds".format(success, time.time() - t1)) 498 | 499 | def open_new_window(self, css): 500 | """ 501 | Open the new window and switch the handle to the newly opened window. 502 | 503 | Usage: 504 | driver.open_new_window("id->kw") 505 | """ 506 | t1 = time.time() 507 | try: 508 | original_windows = self.driver.current_window_handle 509 | el = self.get_element(css) 510 | el.click() 511 | all_handles = self.driver.window_handles 512 | for handle in all_handles: 513 | if handle != original_windows: 514 | self.driver.switch_to.window(handle) 515 | self.my_print("{0} Click element: <{1}> open a new window and swich into, Spend {2} seconds".format(success, 516 | css,time.time() - t1)) 517 | except Exception: 518 | self.my_print("{0} Click element: <{1}> open a new window and swich into, Spend {2} seconds".format(fail, 519 | css,time.time() - t1)) 520 | raise 521 | 522 | def element_exist(self, css): 523 | """ 524 | judge element is exist,The return result is true or false. 525 | 526 | Usage: 527 | driver.element_exist("id->kw") 528 | """ 529 | t1 = time.time() 530 | try: 531 | self.element_wait(css) 532 | self.my_print("{0} Element: <{1}> is exist, Spend {2} seconds".format(success,css, time.time() - t1)) 533 | return True 534 | except TimeoutException: 535 | self.my_print("{0} Element: <{1}> is not exist, Spend {2} seconds".format(fail, css, time.time() - t1)) 536 | return False 537 | 538 | def take_screenshot(self, file_path): 539 | """ 540 | Get the current window screenshot. 541 | 542 | Usage: 543 | driver.take_screenshot('c:/test.png') 544 | """ 545 | t1 = time.time() 546 | try: 547 | self.driver.get_screenshot_as_file(file_path) 548 | self.my_print("{0} Get the current window screenshot,path: {1}, Spend {2} seconds".format(success, 549 | file_path, time.time() - t1)) 550 | except Exception: 551 | self.my_print("{0} Unable to get the current window screenshot,path: {1}, Spend {2} seconds".format(fail, 552 | file_path,time.time() - t1)) 553 | raise 554 | 555 | def into_new_window(self): 556 | """ 557 | Into the new window. 558 | 559 | Usage: 560 | dirver.into_new_window() 561 | """ 562 | t1 = time.time() 563 | try: 564 | all_handle = self.driver.window_handles 565 | flag = 0 566 | while len(all_handle) < 2: 567 | time.sleep(1) 568 | all_handle = self.driver.window_handles 569 | flag += 1 570 | if flag == 5: 571 | break 572 | self.driver.switch_to.window(all_handle[-1]) 573 | self.my_print("{0} Switch to the new window,new window's url: {1}, Spend {2} seconds".format(success, 574 | self.driver.current_url,time.time() - t1)) 575 | except Exception: 576 | self.my_print("{0} Unable switch to the new window, Spend {1} seconds".format(fail, time.time() - t1)) 577 | raise 578 | 579 | def type_and_enter(self, css, text, secs=0.5): 580 | """ 581 | Operation input box. 1、input message,sleep 0.5s;2、input ENTER. 582 | 583 | Usage: 584 | driver.type_css_keys('id->kw','beck') 585 | """ 586 | t1 = time.time() 587 | try: 588 | self.element_wait(css) 589 | ele = self.get_element(css) 590 | ele.send_keys(text) 591 | time.sleep(secs) 592 | ele.send_keys(Keys.ENTER) 593 | self.my_print("{0} Element <{1}> type content: {2},and sleep {3} seconds,input ENTER key, Spend {4} seconds".format( 594 | success,css,text,secs,time.time() - t1)) 595 | except Exception: 596 | self.my_print("{0} Unable element <{1}> type content: {2},and sleep {3} seconds,input ENTER key, Spend {4} seconds". 597 | format(fail, css, text, secs, time.time() - t1)) 598 | raise 599 | 600 | def js_click(self, css): 601 | """ 602 | Input a css selecter,use javascript click element. 603 | 604 | Usage: 605 | driver.js_click('#buttonid') 606 | """ 607 | t1 = time.time() 608 | js_str = "$('{0}').click()".format(css) 609 | try: 610 | self.driver.execute_script(js_str) 611 | self.my_print("{0} Use javascript click element: {1}, Spend {2} seconds".format(success,js_str,time.time()-t1)) 612 | except Exception: 613 | self.my_print("{0} Unable to use javascript click element: {1}, Spend {2} seconds".format(fail, 614 | js_str, time.time() - t1)) 615 | raise 616 | 617 | @property 618 | def origin_driver(self): 619 | """ 620 | Return the original driver,Can use webdriver API. 621 | 622 | Usage: 623 | driver.origin_driver 624 | """ 625 | return self.driver 626 | 627 | 628 | if __name__ == '__main__': 629 | driver = PySelenium("chrome") 630 | -------------------------------------------------------------------------------- /public/common/readconfig.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | 3 | import configparser 4 | import codecs 5 | 6 | class ReadConfig: 7 | """ 8 | 专门读取配置文件的,.ini文件格式 9 | """ 10 | def __init__(self, filename): 11 | # configpath = os.path.join(prjDir,filename) 12 | configpath = filename 13 | # print(configpath) 14 | fd = open(configpath) 15 | data = fd.read() 16 | # remove BOM 17 | if data[:3] == codecs.BOM_UTF8: 18 | data = data[3:] 19 | files = codecs.open(configpath, "w") 20 | files.write(data) 21 | files.close() 22 | fd.close() 23 | 24 | self.cf = configparser.ConfigParser() 25 | self.cf.read(configpath) 26 | 27 | def getValue(self, env, name): 28 | """ 29 | [projectConfig] 30 | project_path=E:/Python-Project/UItestframework 31 | :param env:[projectConfig] 32 | :param name:project_path 33 | :return:E:/Python-Project/UItestframework 34 | """ 35 | return self.cf.get(env,name) 36 | 37 | -------------------------------------------------------------------------------- /public/common/sendmail.py: -------------------------------------------------------------------------------- 1 | #coding:utf-8 2 | 3 | import os 4 | import smtplib 5 | import time 6 | from email.mime.text import MIMEText 7 | from email.mime.multipart import MIMEMultipart 8 | from public.common.log import Log 9 | from config import globalparam 10 | 11 | # 测试报告的路径 12 | reportPath = globalparam.report_path 13 | logger = Log() 14 | # 配置收发件人 15 | recvaddress = ['xxx.xx@xxx.com','xxxx@qq.com'] 16 | # 163的用户名和密码 17 | sendaddr_name = 'xxxxx@163.com' 18 | sendaddr_pswd = 'xxxxx' 19 | 20 | class SendMail: 21 | def __init__(self,recver=None): 22 | """接收邮件的人:list or tuple""" 23 | if recver is None: 24 | self.sendTo = recvaddress 25 | else: 26 | self.sendTo = recver 27 | 28 | def __get_report(self): 29 | """获取最新测试报告""" 30 | dirs = os.listdir(reportPath) 31 | dirs.sort() 32 | newreportname = dirs[-1] 33 | print('The new report name: {0}'.format(newreportname)) 34 | return newreportname 35 | 36 | def __take_messages(self): 37 | """生成邮件的内容,和html报告附件""" 38 | newreport = self.__get_report() 39 | self.msg = MIMEMultipart() 40 | self.msg['Subject'] = '测试报告主题' 41 | self.msg['date'] = time.strftime('%a, %d %b %Y %H:%M:%S %z') 42 | 43 | with open(os.path.join(reportPath,newreport), 'rb') as f: 44 | mailbody = f.read() 45 | html = MIMEText(mailbody,_subtype='html',_charset='utf-8') 46 | self.msg.attach(html) 47 | 48 | # html附件 49 | att1 = MIMEText(mailbody, 'base64', 'gb2312') 50 | att1["Content-Type"] = 'application/octet-stream' 51 | att1["Content-Disposition"] = 'attachment; filename="TestReport.html"'#这里的filename可以任意写,写什么名字,邮件中显示什么名字 52 | self.msg.attach(att1) 53 | 54 | def send(self): 55 | """发送邮件""" 56 | self.__take_messages() 57 | self.msg['from'] = sendaddr_name 58 | try: 59 | smtp = smtplib.SMTP('smtp.163.com',25) 60 | smtp.login(sendaddr_name,sendaddr_pswd) 61 | smtp.sendmail(self.msg['from'], self.sendTo,self.msg.as_string()) 62 | smtp.close() 63 | logger.info("发送邮件成功") 64 | except Exception: 65 | logger.error('发送邮件失败') 66 | raise 67 | 68 | if __name__ == '__main__': 69 | sendMail = SendMail() 70 | sendMail.send() 71 | 72 | 73 | -------------------------------------------------------------------------------- /public/pages/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoshitoutester/UItestframework/b8d3125ed8ffacfd77fc271c6bf1e7105035c0c9/public/pages/__init__.py -------------------------------------------------------------------------------- /public/pages/__pycache__/__init__.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoshitoutester/UItestframework/b8d3125ed8ffacfd77fc271c6bf1e7105035c0c9/public/pages/__pycache__/__init__.cpython-35.pyc -------------------------------------------------------------------------------- /public/pages/__pycache__/baiduIndexPage.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoshitoutester/UItestframework/b8d3125ed8ffacfd77fc271c6bf1e7105035c0c9/public/pages/__pycache__/baiduIndexPage.cpython-35.pyc -------------------------------------------------------------------------------- /public/pages/baiduIndexPage.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | 3 | from public.common import basepage 4 | 5 | class BaiduIndexPage(basepage.Page): 6 | 7 | def into_baidu_page(self): 8 | """打开百度首页""" 9 | self.dr.open('http://www.baidu.com') 10 | def input_search_key(self,values): 11 | """输入搜索关键词""" 12 | self.dr.clear_type('id->kw',values) 13 | 14 | def click_search_button(self): 15 | """点击搜索按钮""" 16 | self.dr.click('id->su') 17 | 18 | def return_title(self): 19 | """返回该页面的title""" 20 | return self.dr.get_title() -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 |
UItestframework项目目前具有以下功能:
1、对webdriver进行了第二次的简单封装,使用更加方便 public/common/pyselenium.py
(ps:这个是在虫师的pyse基础加了打印日志功能,参考:https://github.com/defnngj/pyse)
2、可以对excel表进行数据读取,完成数据驱动:public/common/datainfo.py
3、具有打印日志的功能,打印在控制台和文件中:public/common/log.py,日志保存在report/log/目录下
4、读取配置文件(.ini文件):public/common/readconfig.py
5、具有发邮件的功能:public/common/sendmail.py
6、生成测试报告:html测试报告的路径:report/testreport/目录下
7、使用了PageObject模式来编写测试脚本

整个项目的目录结构:
├─config 配置文件的目录
│ │ config.ini 存放配置文件
│ │ globalparam.py 重要的全局参数,如log、report的路径配置等
│ │ __init__.py
│ │

├─data 测试数据
│ ├─formaldata # 正式环境测试数据
│ └─testdata # 测试环境的数据
│ searKey.xlsx

├─public 公共的文件库
│ │ __init__.py
│ │
│ ├─common 封装的公共方法
│ │ │ basepage.py
│ │ │ datainfo.py
│ │ │ log.py
│ │ │ mytest.py
│ │ │ publicfunction.py
│ │ │ pyselenium.py
│ │ │ pyselenium20161107.py
│ │ │ readconfig.py
│ │ │ sendmail.py
│ │ │ __init__.py
│ │ │
│ │
│ ├─pages 使用pageobject模式编写测试脚本,存放page的目录
│ │ │ baiduIndexPage.py
│ │ │ __init__.py

├─report 测试报告
│ ├─image 截图目录
│ ├─log 日志目录
│ │ 2016-11-07.log
│ │
│ └─testreport html测试报告目录
│ TestResult2016-11-07_16_15_51.html

└─testcase 存放测试用例
│ test_baidu.py

使用说明:
安装响应的库: pip install xlrd,selenium,configparser
1、在config.ini中配置项目路径:project_path
2、测试数据放在data目录下面
3、使用pageobject,写page页面,在测试用例里面调用放在public/pages目录下
4、在testcase目录下面,编写测试用例,可以分模块编写,建相应的目录
5、执行run.py,就可以执行所有的测试用例
6、在report/log里面查看日志
7、在report/testreport里面查看html测试报告

关于pyselenium的使用:
该py文件是根据虫师的pyse改的,加了一个日志,根据自己的需要加了几个函数
可以参考虫师的pyse,github地址:https://github.com/defnngj/pyse
虫师的博客园地址:https://github.com/defnngj/pyse

导入PySlenium文件
import PySelenium
1、启动浏览器:
启动谷歌浏览器
dr = PySelenium.PySelenium('chrom')
启动远程浏览器比如使用grid施行分布式执行
dr = PySelenium.PySelenium(RChrome','127.0.0.1:8080')
2、在地址栏输入网址:
dr.open('http://www.baidu.com')
3、窗口最大化
dr.max_window()
4、设置浏览器的窗口的大小
dr.set_window(800,500)
5、不清除文本框的内容直接输入值(比如说:进行文件上传时,上传文件的路径,如果清除就会报错):
dr.type('id->su','小石头tester')
6、先清除文本框的内容,然后再输入值(用得很多):
dr.clear_type('name->su','虫师')
7、直接点击元素
dr.click('css->#kw')
8、右键点击元素:
dr.right_click('id->kw')
9、将鼠标移动到一个元素上
dr.move_to_element('clas->btn1.btn-green.btn-search')
10、双击元素
dr.double_click("id->kw")
11、将一个元素拖拽到另外一个元素上
dr.drag_and_drop('id->kw1','id->kw2')
12、根据连接的text来点击(<a href="http://www.baidu.com">百度</a>)
dr.click_text('百度')
13、关闭窗口,driver
dr.quit()
14、执行js脚本
dr.js('script')
15、获取元素的属性
dr.get_attribute("id->su","href")
16、获取元素的文本信息text
dr.get_text('id->su')
17、返回当前页面的title
dr.get_title()
18、返回当前页面的url
dr.get_url()
20、进入frame
dr.switch_to_frame('id->kw')
21、退出frame
dr.switch_to_frame_out()
22、判断元素是否存在
dr.element_exist('id->kw')
23、截图
dr.take_screenshot('file_path')
24、进入最新的table
dr.into_new_window()
25、输入内容并且回车
dr.type_and_enter('id->kw')
26、使用js来点击某个元素
dr.js_click('id->kw')
27、返回原生的webdriver,进行个性化需求
dr.origin_driver()
-------------------------------------------------------------------------------- /report/log/2016-11-08.log: -------------------------------------------------------------------------------- 1 | 2016-11-08 11:17:14,346 - root - INFO - ############################### START ############################### 2 | 2016-11-08 11:17:15,233 - root - INFO - SUCCESS Start a new browser: chrome, Spend 0.8860507011413574 seconds 3 | 2016-11-08 11:17:16,335 - root - INFO - SUCCESS Set browser window maximized, Spend 1.0990626811981201 seconds 4 | 2016-11-08 11:17:18,290 - root - INFO - SUCCESS Navigated to http://www.baidu.com, Spend 1.9541118144989014 seconds 5 | 2016-11-08 11:17:18,395 - root - INFO - SUCCESS Clear and type element: kw> content: 小石头tester, Spend 0.10500597953796387 seconds 6 | 2016-11-08 11:17:18,474 - root - INFO - SUCCESS Clicked element: su>, Spend 0.07900476455688477 seconds 7 | 2016-11-08 11:17:20,491 - root - INFO - SUCCESS Get current window title, Spend 0.014000654220581055 seconds 8 | 2016-11-08 11:17:21,731 - root - INFO - SUCCESS Closed all window and quit the driver, Spend 1.2390711307525635 seconds 9 | 2016-11-08 11:17:21,733 - root - INFO - ############################### End ############################### 10 | 2016-11-08 11:17:21,735 - root - INFO - ############################### START ############################### 11 | 2016-11-08 11:17:22,653 - root - INFO - SUCCESS Start a new browser: chrome, Spend 0.9170525074005127 seconds 12 | 2016-11-08 11:17:23,621 - root - INFO - SUCCESS Set browser window maximized, Spend 0.967055082321167 seconds 13 | 2016-11-08 11:17:25,663 - root - INFO - SUCCESS Navigated to http://www.baidu.com, Spend 2.032116174697876 seconds 14 | 2016-11-08 11:17:25,770 - root - INFO - SUCCESS Clear and type element: kw> content: webdriver, Spend 0.10600590705871582 seconds 15 | 2016-11-08 11:17:25,946 - root - INFO - SUCCESS Clicked element: su>, Spend 0.1760101318359375 seconds 16 | 2016-11-08 11:17:27,962 - root - INFO - SUCCESS Get current window title, Spend 0.014000892639160156 seconds 17 | 2016-11-08 11:17:28,313 - root - INFO - SUCCESS Navigated to http://www.baidu.com, Spend 0.3500199317932129 seconds 18 | 2016-11-08 11:17:28,398 - root - INFO - SUCCESS Clear and type element: kw> content: selenium, Spend 0.08300471305847168 seconds 19 | 2016-11-08 11:17:28,506 - root - INFO - SUCCESS Clicked element: su>, Spend 0.10800623893737793 seconds 20 | 2016-11-08 11:17:30,520 - root - INFO - SUCCESS Get current window title, Spend 0.012000799179077148 seconds 21 | 2016-11-08 11:17:30,865 - root - INFO - SUCCESS Navigated to http://www.baidu.com, Spend 0.34201955795288086 seconds 22 | 2016-11-08 11:17:30,948 - root - INFO - SUCCESS Clear and type element: kw> content: github, Spend 0.08000469207763672 seconds 23 | 2016-11-08 11:17:31,047 - root - INFO - SUCCESS Clicked element: su>, Spend 0.09800577163696289 seconds 24 | 2016-11-08 11:17:33,059 - root - INFO - SUCCESS Get current window title, Spend 0.010000467300415039 seconds 25 | 2016-11-08 11:17:33,365 - root - INFO - SUCCESS Navigated to http://www.baidu.com, Spend 0.3040175437927246 seconds 26 | 2016-11-08 11:17:33,451 - root - INFO - SUCCESS Clear and type element: kw> content: 小石头tester, Spend 0.08500480651855469 seconds 27 | 2016-11-08 11:17:33,556 - root - INFO - SUCCESS Clicked element: su>, Spend 0.10500597953796387 seconds 28 | 2016-11-08 11:17:35,569 - root - INFO - SUCCESS Get current window title, Spend 0.012000799179077148 seconds 29 | 2016-11-08 11:17:36,845 - root - INFO - SUCCESS Closed all window and quit the driver, Spend 1.2740728855133057 seconds 30 | 2016-11-08 11:17:36,847 - root - INFO - ############################### End ############################### 31 | 2016-11-08 11:17:43,322 - root - INFO - 发送邮件成功 32 | -------------------------------------------------------------------------------- /report/testreport/TestResult2016-11-08_11_17_14.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 测试报告 6 | 7 | 8 | 9 | 10 | 11 | 94 | 95 | 96 | 97 | 191 | 192 |
193 |

测试报告

194 |

Start Time: 2016-11-08 11:17:14

195 |

Duration: 0:00:22.500287

196 |

Status: Pass 2

197 | 198 |

Test the import testcase

199 |
200 | 201 | 202 | 203 |

Show 204 | Summary 205 | Failed 206 | All 207 |

208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 267 | 268 | 269 | 270 | 271 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 |
Test Group/Test caseCountPassFailErrorView
test_baidu.TestBaiduIndex: 百度搜索测试2200Detail
test_search: 直接搜索
238 | 239 | 240 | 241 | pass 242 | 243 | 264 | 265 | 266 |
test_search_excel: 使用数据驱动,进行测试
272 | 273 | 274 | 275 | pass 276 | 277 | 310 | 311 | 312 |
Total2200 
324 | 325 |
 
326 | 327 | 328 | 329 | -------------------------------------------------------------------------------- /run.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | 3 | import unittest 4 | import HTMLTestRunner 5 | import time 6 | from config import globalparam 7 | from public.common import sendmail 8 | 9 | def run(): 10 | test_dir = './testcase' 11 | suite = unittest.defaultTestLoader.discover(start_dir=test_dir,pattern='test*.py') 12 | 13 | now = time.strftime('%Y-%m-%d_%H_%M_%S') 14 | reportname = globalparam.report_path + '\\' + 'TestResult' + now + '.html' 15 | with open(reportname,'wb') as f: 16 | runner = HTMLTestRunner.HTMLTestRunner( 17 | stream=f, 18 | title='测试报告', 19 | description='Test the import testcase' 20 | ) 21 | runner.run(suite) 22 | time.sleep(3) 23 | # 发送邮件 24 | mail = sendmail.SendMail() 25 | mail.send() 26 | 27 | if __name__=='__main__': 28 | run() -------------------------------------------------------------------------------- /testcase/__pycache__/test_baidu.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoshitoutester/UItestframework/b8d3125ed8ffacfd77fc271c6bf1e7105035c0c9/testcase/__pycache__/test_baidu.cpython-35.pyc -------------------------------------------------------------------------------- /testcase/test_baidu.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | 3 | from time import sleep 4 | from public.common import mytest 5 | from public.pages import baiduIndexPage 6 | from public.common import datainfo 7 | 8 | 9 | class TestBaiduIndex(mytest.MyTest): 10 | """百度搜索测试""" 11 | 12 | def _search(self,searchKey): 13 | """封装百度搜索的函数""" 14 | baidupage = baiduIndexPage.BaiduIndexPage(self.dr) 15 | baidupage.into_baidu_page() 16 | baidupage.input_search_key(searchKey) 17 | baidupage.click_search_button() 18 | sleep(2) 19 | self.assertIn(searchKey, baidupage.return_title()) 20 | 21 | def test_search(self): 22 | """直接搜索""" 23 | baidupage = baiduIndexPage.BaiduIndexPage(self.dr) 24 | baidupage.into_baidu_page() 25 | baidupage.input_search_key('小石头tester') 26 | baidupage.click_search_button() 27 | sleep(2) 28 | self.assertIn('小石头',baidupage.return_title()) 29 | 30 | def test_search_excel(self): 31 | """使用数据驱动,进行测试""" 32 | datas = datainfo.get_xls_to_list('searKey.xlsx','Sheet1') 33 | for data in datas: 34 | self._search(data) 35 | 36 | --------------------------------------------------------------------------------