├── action ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-36.pyc │ └── PageAction.cpython-36.pyc └── PageAction.py ├── config ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-36.pyc │ └── VarConfig.cpython-36.pyc └── VarConfig.py ├── log ├── __init__.py ├── 2019-08-03.txt └── log2019-03-28.txt ├── util ├── __init__.py ├── __pycache__ │ ├── log.cpython-36.pyc │ ├── DirAndTime.cpython-36.pyc │ ├── ObjectMap.cpython-36.pyc │ ├── ParseExcel.cpython-36.pyc │ ├── WaitUntil.cpython-36.pyc │ ├── __init__.cpython-36.pyc │ ├── KeyBoardUtil.cpython-36.pyc │ └── ClipboardUtil.cpython-36.pyc ├── ObjectMap.py ├── ClipboardUtil.py ├── DirAndTime.py ├── log.py ├── KeyBoardUtil.py ├── WaitUntil.py └── ParseExcel.py ├── testCases ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-36.pyc │ └── Test126SendMailWithAttachment.cpython-36.pyc └── Test126SendMailWithAttachment.py ├── testData ├── __init__.py ├── upload_file_for_test └── 126mailSend.xlsx ├── _config.yml ├── .gitignore ├── .gitattributes ├── requirements.txt ├── exceptionpictures ├── 2019-03-27 │ └── 15_50_48.png └── 2019-08-03 │ ├── 15_20_15.png │ ├── 15_21_54.png │ ├── 15_23_39.png │ ├── 15_30_02.png │ ├── 15_43_53.png │ ├── 15_47_44.png │ ├── 15_50_59.png │ ├── 15_53_27.png │ ├── 16_00_00.png │ └── 16_33_54.png ├── RunTest.py └── README.md /action/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /config/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /log/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /util/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /testCases/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /testData/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /testData/upload_file_for_test: -------------------------------------------------------------------------------- 1 | 测试添加附件所用的文件 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ##ignore these files## 2 | .idea 3 | *.log 4 | venv/ -------------------------------------------------------------------------------- /log/2019-08-03.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/13691579846/KeyWordDriverTestFrameWork/HEAD/log/2019-08-03.txt -------------------------------------------------------------------------------- /log/log2019-03-28.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/13691579846/KeyWordDriverTestFrameWork/HEAD/log/log2019-03-28.txt -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.py linguist-language=python 2 | *.html linguist-language=python 3 | *.xlsx linguist-language=python 4 | -------------------------------------------------------------------------------- /testData/126mailSend.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/13691579846/KeyWordDriverTestFrameWork/HEAD/testData/126mailSend.xlsx -------------------------------------------------------------------------------- /util/__pycache__/log.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/13691579846/KeyWordDriverTestFrameWork/HEAD/util/__pycache__/log.cpython-36.pyc -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | et-xmlfile==1.0.1 2 | jdcal==1.4.1 3 | openpyxl==2.6.2 4 | pypiwin32==223 5 | pywin32==224 6 | selenium==3.141.0 7 | urllib3==1.25.3 8 | -------------------------------------------------------------------------------- /action/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/13691579846/KeyWordDriverTestFrameWork/HEAD/action/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /config/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/13691579846/KeyWordDriverTestFrameWork/HEAD/config/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /exceptionpictures/2019-03-27/15_50_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/13691579846/KeyWordDriverTestFrameWork/HEAD/exceptionpictures/2019-03-27/15_50_48.png -------------------------------------------------------------------------------- /exceptionpictures/2019-08-03/15_20_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/13691579846/KeyWordDriverTestFrameWork/HEAD/exceptionpictures/2019-08-03/15_20_15.png -------------------------------------------------------------------------------- /exceptionpictures/2019-08-03/15_21_54.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/13691579846/KeyWordDriverTestFrameWork/HEAD/exceptionpictures/2019-08-03/15_21_54.png -------------------------------------------------------------------------------- /exceptionpictures/2019-08-03/15_23_39.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/13691579846/KeyWordDriverTestFrameWork/HEAD/exceptionpictures/2019-08-03/15_23_39.png -------------------------------------------------------------------------------- /exceptionpictures/2019-08-03/15_30_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/13691579846/KeyWordDriverTestFrameWork/HEAD/exceptionpictures/2019-08-03/15_30_02.png -------------------------------------------------------------------------------- /exceptionpictures/2019-08-03/15_43_53.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/13691579846/KeyWordDriverTestFrameWork/HEAD/exceptionpictures/2019-08-03/15_43_53.png -------------------------------------------------------------------------------- /exceptionpictures/2019-08-03/15_47_44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/13691579846/KeyWordDriverTestFrameWork/HEAD/exceptionpictures/2019-08-03/15_47_44.png -------------------------------------------------------------------------------- /exceptionpictures/2019-08-03/15_50_59.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/13691579846/KeyWordDriverTestFrameWork/HEAD/exceptionpictures/2019-08-03/15_50_59.png -------------------------------------------------------------------------------- /exceptionpictures/2019-08-03/15_53_27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/13691579846/KeyWordDriverTestFrameWork/HEAD/exceptionpictures/2019-08-03/15_53_27.png -------------------------------------------------------------------------------- /exceptionpictures/2019-08-03/16_00_00.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/13691579846/KeyWordDriverTestFrameWork/HEAD/exceptionpictures/2019-08-03/16_00_00.png -------------------------------------------------------------------------------- /exceptionpictures/2019-08-03/16_33_54.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/13691579846/KeyWordDriverTestFrameWork/HEAD/exceptionpictures/2019-08-03/16_33_54.png -------------------------------------------------------------------------------- /util/__pycache__/DirAndTime.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/13691579846/KeyWordDriverTestFrameWork/HEAD/util/__pycache__/DirAndTime.cpython-36.pyc -------------------------------------------------------------------------------- /util/__pycache__/ObjectMap.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/13691579846/KeyWordDriverTestFrameWork/HEAD/util/__pycache__/ObjectMap.cpython-36.pyc -------------------------------------------------------------------------------- /util/__pycache__/ParseExcel.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/13691579846/KeyWordDriverTestFrameWork/HEAD/util/__pycache__/ParseExcel.cpython-36.pyc -------------------------------------------------------------------------------- /util/__pycache__/WaitUntil.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/13691579846/KeyWordDriverTestFrameWork/HEAD/util/__pycache__/WaitUntil.cpython-36.pyc -------------------------------------------------------------------------------- /util/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/13691579846/KeyWordDriverTestFrameWork/HEAD/util/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /action/__pycache__/PageAction.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/13691579846/KeyWordDriverTestFrameWork/HEAD/action/__pycache__/PageAction.cpython-36.pyc -------------------------------------------------------------------------------- /config/__pycache__/VarConfig.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/13691579846/KeyWordDriverTestFrameWork/HEAD/config/__pycache__/VarConfig.cpython-36.pyc -------------------------------------------------------------------------------- /util/__pycache__/KeyBoardUtil.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/13691579846/KeyWordDriverTestFrameWork/HEAD/util/__pycache__/KeyBoardUtil.cpython-36.pyc -------------------------------------------------------------------------------- /testCases/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/13691579846/KeyWordDriverTestFrameWork/HEAD/testCases/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /util/__pycache__/ClipboardUtil.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/13691579846/KeyWordDriverTestFrameWork/HEAD/util/__pycache__/ClipboardUtil.cpython-36.pyc -------------------------------------------------------------------------------- /testCases/__pycache__/Test126SendMailWithAttachment.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/13691579846/KeyWordDriverTestFrameWork/HEAD/testCases/__pycache__/Test126SendMailWithAttachment.cpython-36.pyc -------------------------------------------------------------------------------- /RunTest.py: -------------------------------------------------------------------------------- 1 | """ 2 | ------------------------------------ 3 | @Time : 2019/8/3 14:20 4 | @Auth : linux超 5 | @File : RunTest.py 6 | @IDE : PyCharm 7 | @Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error! 8 | ------------------------------------ 9 | """ 10 | from testCases.Test126SendMailWithAttachment import test_126_mail_send_with_att 11 | 12 | 13 | if __name__ == '__main__': 14 | test_126_mail_send_with_att() 15 | -------------------------------------------------------------------------------- /config/VarConfig.py: -------------------------------------------------------------------------------- 1 | """ 2 | ------------------------------------ 3 | @Time : 2019/8/3 14:20 4 | @Auth : linux超 5 | @File : VarConfig.py 6 | @IDE : PyCharm 7 | @Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error! 8 | ------------------------------------ 9 | """ 10 | # 存储全局的变量 11 | import os 12 | 13 | # 项目根目录 14 | projectPath = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 15 | # 截图目录 16 | exceptionPath = projectPath + r'\exceptionpictures' 17 | 18 | # 驱动存放路径, 需要自己根据自己电脑的驱动为止修改 19 | iePath = '' 20 | chromePath = '' 21 | fireFox = '' 22 | 23 | # excel文件存放路径 24 | excelPath = projectPath + r'\testData\126mailSend.xlsx' 25 | # loh文件存放路径 26 | logPath = projectPath + '\\log\\' 27 | # 测试用例部分列对应的列号 28 | testCase_testCaseName = 2 29 | testCase_testStepName = 4 30 | testCase_testIsExecute = 5 31 | testCase_testRunEndTime = 6 32 | testCase_testResult = 7 33 | 34 | # 用例步骤对应的列号 35 | testStep_testNum = 1 36 | testStep_testStepDescribe = 2 37 | testStep_keyWord = 3 38 | testStep_elementBy = 4 39 | testStep_elementLocator = 5 40 | testStep_operateValue = 6 41 | testStep_testRunTime = 7 42 | testStep_testResult = 8 43 | testStep_testErrorInfo = 9 44 | testStep_testErrorPic = 10 45 | 46 | 47 | if __name__ == '__main__': 48 | print(projectPath) 49 | print(exceptionPath) 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 关键字驱动测试框架案例 2 | 3 | 框架分析: 4 | 1.使用外部测试数据文件,使用Excel管理测试用例的集合和每个测试用例的所有测试步骤 5 | ,实现一个文件中完成测试用例的维护 6 | 2.每个测试用例的测试结果在一个文件中查看和统计 7 | 3.通过定义关键字,操作元素的定位方式及定位表达式和操作值就可以实现每个测试用例步 8 | 骤的执行,可以更加灵活地实现自动化测试的需求 9 | 4.实现定位表达式和测试代码的分离,实现定位表达式直接在测试数据文件中进行维护。 10 | 5.框架提供日志功能,方便调试和监控自动化测试程序的执行 11 | 6.基于关键字测试框架,即使不懂开发技术的测试人员也可以实施自动化测试,便于在整个 12 | 测试团队中推广和使用自动化测试技术,降低自动化测试实施的技术门槛 13 | 7.基于关键字的方式,可以进行任意关键字的扩展,以满足更加复杂项目的自动化测试需求 14 | 15 | 运行框架: 16 | .确保您的本地环境已配置chrome/firefox/ie浏览器及对应版本驱动 17 | .cd D:\KeyWordDriverTestFrameWork 18 | .python RunTest.py 19 | 说明: 20 | .本项目完全是为了学习使用,项目中的账户和密码我并没有删除,希望您不要使用我的邮箱做有违国家安全或者对我个人有害的事情,彼此的信任是最重要的不是嘛 21 | .如果您有好的建议或者改进,可以fork本项目后修改你认为可以改进的代码后发起pull requests给我哦 22 | .如果你有不同的想法, 且你的改进对本项目有帮助, 我很愿意使用你的代码提高本项目的完整性, 对此表示感谢! 23 | 修改说明: 24 | .modify by linuxchao at 2019.08.03 25 | .修改了整个项目代码编写规范 26 | .针对126邮箱升级后,修改了部分用例的逻辑,具体修改内容请查看项目原代码 27 | .针对126邮箱上传附件的用例, 放弃了模拟键盘和剪切板的操作部分(这个方法相对来说不稳定), 采用了最原始的send_keys方法实现 28 | .为了方便他人clone本项目后能够顺利的运行本项目, 我添加了环境管理文件requirements.txt,文件表明了本项目使用的所有第三方库 29 | 当你clone本项目后, 请使用命令pip install -r requirements.txt来安装所有依赖库 30 | .特别说明:防止您的本地环境和本项目环境冲突,最好为本项目创建虚拟环境,使用虚拟环境的pip工具执行安装依赖库 31 | -------------------------------------------------------------------------------- /util/ObjectMap.py: -------------------------------------------------------------------------------- 1 | """ 2 | ------------------------------------ 3 | @Time : 2019/8/3 14:20 4 | @Auth : linux超 5 | @File : ObjectMap.py 6 | @IDE : PyCharm 7 | @Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error! 8 | ------------------------------------ 9 | """ 10 | from selenium.webdriver.support.wait import WebDriverWait 11 | from selenium import webdriver 12 | import time 13 | 14 | 15 | def get_element(driver, by, locator): 16 | """查找单一元素""" 17 | try: 18 | element = WebDriverWait(driver, 30).until(lambda x: x.find_element(by, locator)) 19 | except Exception as e: 20 | raise e 21 | else: 22 | return element 23 | 24 | 25 | def get_elements(driver, by, locator): 26 | """获取一组元素""" 27 | try: 28 | elements = WebDriverWait(driver, 30).until(lambda x: x.find_element(by, locator)) 29 | except Exception as e: 30 | raise e 31 | else: 32 | return elements 33 | 34 | 35 | if __name__ == "__main__": 36 | d = webdriver.Firefox() 37 | d.get('https://mail.126.com') 38 | time.sleep(5) 39 | d.switch_to.frame(get_element(d, 'xpath', "//div[@id='loginDiv']/iframe")) 40 | username = get_element(d, 'xpath', "//input[@name='email']") 41 | username.send_keys('linuxxiaochao') 42 | d.switch_to.default_content() 43 | d.quit() 44 | -------------------------------------------------------------------------------- /util/ClipboardUtil.py: -------------------------------------------------------------------------------- 1 | """ 2 | ------------------------------------ 3 | @Time : 2019/8/3 14:20 4 | @Auth : linux超 5 | @File : ClipboardUtil.py 6 | @IDE : PyCharm 7 | @Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error! 8 | ------------------------------------ 9 | """ 10 | import win32clipboard as w 11 | import win32con 12 | from selenium import webdriver 13 | 14 | 15 | class Clipboard(object): 16 | 17 | @staticmethod 18 | def get_text(): 19 | """获取剪切板的内容""" 20 | try: 21 | # 打开剪切板 22 | w.OpenClipboard() 23 | # 读取数据 24 | value = w.GetClipboardData(win32con.CF_TEXT) 25 | # 关闭剪切板 26 | w.CloseClipboard() 27 | except Exception as e: 28 | raise e 29 | else: 30 | return value 31 | 32 | @staticmethod 33 | def set_text(value): 34 | """设置剪切板内容""" 35 | try: 36 | w.OpenClipboard() # 打开剪切板 37 | w.EmptyClipboard() # 清空剪切板 38 | w.SetClipboardData(win32con.CF_UNICODETEXT, value) # 设置内容 39 | w.CloseClipboard() # 关闭 40 | except Exception as e: 41 | raise e 42 | 43 | 44 | if __name__ == '__main__': 45 | data = 'python' 46 | driver = webdriver.Firefox() 47 | driver.get('http://www.baidu.com') 48 | query = driver.find_element_by_id('kw') 49 | Clipboard.set_text(data) 50 | clValue = Clipboard.get_text() 51 | query.send_keys(clValue.decode('utf-8')) 52 | -------------------------------------------------------------------------------- /util/DirAndTime.py: -------------------------------------------------------------------------------- 1 | """ 2 | ------------------------------------ 3 | @Time : 2019/8/3 14:20 4 | @Auth : linux超 5 | @File : DirAndTime.py 6 | @IDE : PyCharm 7 | @Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error! 8 | ------------------------------------ 9 | """ 10 | import os 11 | from datetime import datetime, date 12 | 13 | from config.VarConfig import exceptionPath 14 | 15 | 16 | class DirAndTime(object): 17 | 18 | @staticmethod 19 | def get_current_date(): 20 | """获取当前日期""" 21 | try: 22 | current_date = date.today() 23 | except Exception as e: 24 | raise e 25 | else: 26 | return str(current_date) 27 | 28 | @staticmethod 29 | def get_current_time(): 30 | """获取当前时间""" 31 | try: 32 | time = datetime.now() 33 | current_time = time.strftime('%H_%M_%S') 34 | except Exception as e: 35 | raise e 36 | else: 37 | return current_time 38 | 39 | @staticmethod 40 | def create_picture_path(): 41 | """创建图片存放路径路径""" 42 | try: 43 | picture_path = os.path.join(exceptionPath, DirAndTime.get_current_date()) 44 | if not os.path.exists(picture_path): 45 | os.makedirs(picture_path) # 生成多级目录 46 | except Exception as e: 47 | raise e 48 | else: 49 | return picture_path 50 | 51 | 52 | if __name__ == '__main__': 53 | print(DirAndTime.get_current_date()) 54 | print(DirAndTime.get_current_time()) 55 | print(DirAndTime.create_picture_path()) 56 | -------------------------------------------------------------------------------- /util/log.py: -------------------------------------------------------------------------------- 1 | """ 2 | ------------------------------------ 3 | @Time : 2019/8/3 14:20 4 | @Auth : linux超 5 | @File : log.py 6 | @IDE : PyCharm 7 | @Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error! 8 | ------------------------------------ 9 | """ 10 | import logging 11 | import time 12 | 13 | from config.VarConfig import logPath 14 | 15 | 16 | class Logger(object): 17 | """封装的日志模块""" 18 | 19 | def __init__(self, logger, CmdLevel=logging.INFO, FileLevel=logging.INFO): 20 | try: 21 | self.logger = logging.getLogger(logger) 22 | self.logger.setLevel(logging.DEBUG) # 设置日志输出的默认级别 23 | # 日志输出格式 24 | fmt = logging.Formatter('%(asctime)s - %(filename)s:[%(lineno)s] - [%(levelname)s] - %(message)s') 25 | # 日志文件名称 26 | # self.LogFileName = os.path.join(conf.log_path, "{0}.log.txt".format(time.strftime("%Y-%m-%d")))# %H_%M_%S 27 | curr_time = time.strftime("%Y-%m-%d") 28 | self.LogFileName = logPath + curr_time + '.txt' 29 | # 设置控制台输出 30 | # sh = logging.StreamHandler() 31 | # sh.setFormatter(fmt) 32 | # sh.setLevel(CmdLevel)# 日志级别 33 | 34 | # 设置文件输出 35 | fh = logging.FileHandler(self.LogFileName) 36 | fh.setFormatter(fmt) 37 | fh.setLevel(FileLevel) # 日志级别 38 | 39 | # self.logger.addHandler(sh) 40 | self.logger.addHandler(fh) 41 | except Exception as e: 42 | raise e 43 | 44 | 45 | if __name__ == '__main__': 46 | logger = Logger("fox", CmdLevel=logging.DEBUG, FileLevel=logging.DEBUG) 47 | logger.logger.debug("debug") 48 | logger.logger.log(logging.ERROR, '%(module)s %(info)s', {'module': 'log日志', 'info': 'error'}) # ERROR,log日志 error 49 | -------------------------------------------------------------------------------- /util/KeyBoardUtil.py: -------------------------------------------------------------------------------- 1 | """ 2 | ------------------------------------ 3 | @Time : 2019/8/3 14:20 4 | @Auth : linux超 5 | @File : KeyBoardUtil.py 6 | @IDE : PyCharm 7 | @Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error! 8 | ------------------------------------ 9 | """ 10 | import win32api 11 | import win32con 12 | from selenium import webdriver 13 | 14 | 15 | class KeyBoardKeys(object): 16 | """模拟键盘""" 17 | # 键盘编码 18 | vk_code = { 19 | 'enter': 0x0D, 20 | 'tab': 0x09, 21 | 'ctrl': 0x11, 22 | 'v': 0x56 23 | } 24 | 25 | @staticmethod 26 | def key_down(key_name): 27 | """模拟按下键""" 28 | try: 29 | win32api.keybd_event(KeyBoardKeys.vk_code[key_name], 0, 0, 0) 30 | except Exception as e: 31 | raise e 32 | 33 | @staticmethod 34 | def key_up(key_name): 35 | """释放键""" 36 | try: 37 | win32api.keybd_event(KeyBoardKeys.vk_code[key_name], 0, win32con.KEYEVENTF_KEYUP, 0) 38 | except Exception as e: 39 | raise e 40 | 41 | @staticmethod 42 | def one_key(key): 43 | """模拟单个按键""" 44 | try: 45 | KeyBoardKeys.key_down(key) 46 | KeyBoardKeys.key_up(key) 47 | except Exception as e: 48 | raise e 49 | 50 | @staticmethod 51 | def two_keys(key1, key2): 52 | """模拟组合按键""" 53 | try: 54 | KeyBoardKeys.key_down(key1) 55 | KeyBoardKeys.key_down(key2) 56 | KeyBoardKeys.key_up(key1) 57 | KeyBoardKeys.key_up(key2) 58 | except Exception as e: 59 | raise e 60 | 61 | 62 | if __name__ == '__main__': 63 | driver = webdriver.Firefox() 64 | driver.get('http://www.baidu.com') 65 | driver.find_element_by_id('kw').send_keys('python') 66 | KeyBoardKeys.one_key('enter') 67 | -------------------------------------------------------------------------------- /util/WaitUntil.py: -------------------------------------------------------------------------------- 1 | """ 2 | ------------------------------------ 3 | @Time : 2019/8/3 14:20 4 | @Auth : linux超 5 | @File : WaitUntil.py 6 | @IDE : PyCharm 7 | @Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error! 8 | ------------------------------------ 9 | """ 10 | from selenium.webdriver.common.by import By 11 | from selenium.webdriver.support.wait import WebDriverWait 12 | from selenium.webdriver.support import expected_conditions as ec 13 | from selenium import webdriver 14 | 15 | from util.ObjectMap import get_element 16 | 17 | 18 | class WaitUnit(object): 19 | def __init__(self, driver): 20 | self.byDic = { 21 | 'id': By.ID, 22 | 'name': By.NAME, 23 | 'class_name': By.CLASS_NAME, 24 | 'xpath': By.XPATH, 25 | 'link_text': By.LINK_TEXT 26 | } 27 | self.driver = driver 28 | self.wait = WebDriverWait(self.driver, 50) 29 | 30 | def presence_of_element_located(self, by, locator): 31 | """显示等待某个元素出现在dom中,不一定可见,存在返回元素对象""" 32 | try: 33 | if by.lower() in self.byDic: 34 | self.wait.until(ec.presence_of_element_located((self.byDic[by.lower()], locator))) 35 | else: 36 | raise TypeError('未找到定位方式,请确保定位方式正确') 37 | except Exception as e: 38 | raise e 39 | 40 | def frame_to_be_available_and_switch_to_it(self, by, locator): 41 | """检查frame是否存在,存在就切换到frame中""" 42 | try: 43 | if by.lower() in self.byDic: 44 | self.wait.until(ec.frame_to_be_available_and_switch_to_it((self.byDic[by.lower()], locator))) 45 | else: 46 | raise TypeError('未找到定位方式,请确保定位方式正确') 47 | except Exception as e: 48 | raise e 49 | 50 | def visibility_of_element_located(self, by, locator): 51 | """显示等待页面元素出现在dom中, 并且可见, 存在则返回该元素对象""" 52 | try: 53 | if by.lower() in self.byDic: 54 | self.wait.until(ec.visibility_of_element_located((self.byDic[by.lower()], locator))) 55 | else: 56 | raise TypeError('未找到定位方式,请确保定位方式正确') 57 | except Exception as e: 58 | raise e 59 | 60 | 61 | if __name__ == '__main__': 62 | d = webdriver.Firefox() 63 | d.get('https://mail.126.com') 64 | wait = WaitUnit(d) 65 | wait.frame_to_be_available_and_switch_to_it('xpath', "//div[@id='loginDiv']/iframe") 66 | wait.visibility_of_element_located('xpath', "//input[@name='email']") 67 | u_name = get_element(d, 'xpath', "//input[@name='email']") 68 | u_name.send_keys('python') 69 | d.quit() 70 | -------------------------------------------------------------------------------- /util/ParseExcel.py: -------------------------------------------------------------------------------- 1 | """ 2 | ------------------------------------ 3 | @Time : 2019/8/3 14:20 4 | @Auth : linux超 5 | @File : ParseExcel.py 6 | @IDE : PyCharm 7 | @Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error! 8 | ------------------------------------ 9 | """ 10 | from openpyxl import load_workbook 11 | from datetime import datetime 12 | 13 | from config.VarConfig import ( 14 | excelPath, 15 | testStep_testRunTime, 16 | testStep_testResult, 17 | testStep_testErrorInfo, 18 | testStep_testErrorPic 19 | ) 20 | 21 | 22 | class ParseExcel(object): 23 | """解析excel文件的封装""" 24 | 25 | def __init__(self): 26 | # 加载excel文件到内存 27 | self.wb = load_workbook(excelPath) 28 | 29 | def get_row_value(self, sheet_name, raw_no): 30 | """获取某一行的数据""" 31 | sh = self.wb[sheet_name] 32 | row_value_list = [] 33 | for y in range(2, sh.max_column + 1): 34 | value = sh.cell(raw_no, y).value 35 | row_value_list.append(value) 36 | return row_value_list 37 | 38 | def get_column_value(self, sheet_name, col_no): 39 | """获取某一列的数据""" 40 | sh = self.wb[sheet_name] 41 | col_value_list = [] 42 | for x in range(2, sh.max_row + 1): 43 | value = sh.cell(x, col_no).value 44 | col_value_list.append(value) 45 | return col_value_list 46 | 47 | def get_cell_of_value(self, sheet_name, raw_no, col_no): 48 | """获取某一个单元格的数据""" 49 | sh = self.wb[sheet_name] 50 | value = sh.cell(raw_no, col_no).value 51 | return value 52 | 53 | def write_cell(self, sheet_name, raw_no, col_no, value): 54 | """向某个单元格写入数据""" 55 | sh = self.wb[sheet_name] 56 | sh.cell(raw_no, col_no).value = value 57 | self.wb.save(excelPath) 58 | 59 | def write_current_time(self, sheet_name, raw_no, col_no): 60 | """向某个单元格写入当前时间""" 61 | sh = self.wb[sheet_name] 62 | time = datetime.now() 63 | current_time = time.strftime('%Y:%m:%d %H:%M:%S') 64 | sh.cell(raw_no, col_no).value = current_time 65 | self.wb.save(excelPath) 66 | 67 | def write_test_result(self, sheet_name, raw_no, result, error_info=None, error_pic=None): 68 | self.write_current_time(sheet_name, raw_no, testStep_testRunTime) 69 | self.write_cell(sheet_name, raw_no, testStep_testResult, result) 70 | if error_info and error_pic: 71 | self.write_cell(sheet_name, raw_no, testStep_testErrorInfo, error_info) 72 | self.write_cell(sheet_name, raw_no, testStep_testErrorPic, error_pic) 73 | else: 74 | self.write_cell(sheet_name, raw_no, testStep_testErrorInfo, '') 75 | self.write_cell(sheet_name, raw_no, testStep_testErrorPic, '') 76 | 77 | 78 | if __name__ == '__main__': 79 | p = ParseExcel() 80 | print(p.get_row_value('126account', 2)) 81 | print(p.get_column_value('126account', 3)) 82 | print(p.get_cell_of_value('126account', 2, 3)) 83 | -------------------------------------------------------------------------------- /testCases/Test126SendMailWithAttachment.py: -------------------------------------------------------------------------------- 1 | """ 2 | ------------------------------------ 3 | @Time : 2019/8/3 14:20 4 | @Auth : linux超 5 | @File : Test126SendMailWithAttachment.py 6 | @IDE : PyCharm 7 | @Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error! 8 | ------------------------------------ 9 | """ 10 | import traceback 11 | import logging 12 | 13 | from action.PageAction import * 14 | from config.VarConfig import ( 15 | testCase_testIsExecute, 16 | testCase_testStepName, 17 | testStep_testNum, 18 | testStep_testStepDescribe, 19 | testStep_keyWord, 20 | testStep_elementBy, 21 | testStep_elementLocator, 22 | testStep_operateValue, 23 | testCase_testResult 24 | ) 25 | from util.log import Logger 26 | from util.ParseExcel import ParseExcel 27 | 28 | 29 | log = Logger(__name__, CmdLevel=logging.INFO, FileLevel=logging.INFO) 30 | p = ParseExcel() 31 | sheetName = p.wb.sheetnames # 获取到excel的所有sheet名称 32 | 33 | 34 | def test_126_mail_send_with_att(): 35 | try: 36 | test_case_pass_num = 0 37 | required_case = 0 38 | is_execute_column_values = p.get_column_value(sheetName[0], testCase_testIsExecute) 39 | print(is_execute_column_values) 40 | # print(columnValues) 41 | for index, value in enumerate(is_execute_column_values): 42 | print(index, value) 43 | # 获取对应的步骤sheet名称 44 | step_sheet_name = p.get_cell_of_value(sheetName[0], index + 2, testCase_testStepName) 45 | print(step_sheet_name) 46 | if value.strip().lower() == 'y': 47 | required_case += 1 48 | test_step_pass_num = 0 49 | print('开始执行测试用例"{}"'.format(step_sheet_name)) 50 | log.logger.info('开始执行测试用例"{}"'.format(step_sheet_name)) 51 | # 如果用例被标记为执行y,切换到对应的sheet页 52 | # 获取对应的sheet表中的总步骤数,关键字,定位方式,定位表达式,操作值 53 | # 步骤总数 54 | values = p.get_column_value(step_sheet_name, testStep_testNum) # 第一列数据 55 | step_num = len(values) 56 | for step in range(2, step_num + 2): 57 | raw_value = p.get_row_value(step_sheet_name, step) 58 | # 执行步骤名称 59 | step_name = raw_value[testStep_testStepDescribe - 2] 60 | # 关键字 61 | key_word = raw_value[testStep_keyWord - 2] 62 | # 定位方式 63 | by = raw_value[testStep_elementBy - 2] 64 | # 定位表达式 65 | locator = raw_value[testStep_elementLocator - 2] 66 | # 操作值 67 | operate_value = raw_value[testStep_operateValue - 2] 68 | if key_word and by and locator and operate_value: 69 | func = \ 70 | key_word \ 71 | + '(' + '"' + by + '"' + ',' + '"' + locator + '"' + ',' + '"' + operate_value + '"' + ')' 72 | elif key_word and by and locator and operate_value is None: 73 | func = \ 74 | key_word \ 75 | + '(' + '"' + by + '"' + ',' + '"' + locator + '"' + ')' 76 | elif key_word and operate_value and type(operate_value) == str and by is None and locator is None: 77 | func = \ 78 | key_word \ 79 | + '(' + '"' + operate_value + '"' + ')' 80 | elif key_word and operate_value and type(operate_value) == int and by is None and locator is None: 81 | func = \ 82 | key_word \ 83 | + '(' + str(operate_value) + ')' 84 | else: 85 | func = \ 86 | key_word \ 87 | + '(' + ')' 88 | try: 89 | # 执行测试步骤 90 | eval(func) 91 | except Exception: 92 | # 截图 93 | pic_path = save_screen_shot() 94 | # 写回测试结果 95 | error_info = traceback.format_exc() 96 | p.write_test_result(step_sheet_name, step, 'Failed', error_info, pic_path) 97 | print('步骤"{}"执行失败'.format(step_name)) 98 | log.logger.info('步骤"{}"执行失败'.format(step_name)) 99 | else: 100 | print('步骤"{}"执行通过'.format(step_name)) 101 | log.logger.info('步骤"{}"执行通过'.format(step_name)) 102 | # 标记测试步骤为pass 103 | p.write_test_result(step_sheet_name, step, 'Pass') 104 | test_step_pass_num += 1 105 | # print('通过用例步数数:',testStepPassNum) 106 | if test_step_pass_num == step_num: 107 | # 标记测试用例sheet页的执行结果为pass 108 | p.write_cell(sheetName[0], index + 2, testCase_testResult, 'Pass') 109 | test_case_pass_num += 1 110 | else: 111 | p.write_cell(sheetName[0], index + 2, testCase_testResult, 'Failed') 112 | log.logger.info('共{}条用例,{}条需要被执行,本次执行通过{}条'. 113 | format(len(is_execute_column_values), required_case, test_case_pass_num)) 114 | except Exception as e: 115 | log.logger.info(e) 116 | 117 | 118 | if __name__ == '__main__': 119 | test_126_mail_send_with_att() 120 | -------------------------------------------------------------------------------- /action/PageAction.py: -------------------------------------------------------------------------------- 1 | """ 2 | ------------------------------------ 3 | @Time : 2019/8/3 14:20 4 | @Auth : linux超 5 | @File : PageAction.py 6 | @IDE : PyCharm 7 | @Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error! 8 | ------------------------------------ 9 | """ 10 | from config.VarConfig import iePath, chromePath 11 | from util.DirAndTime import DirAndTime 12 | from util.ObjectMap import get_element 13 | from util.ClipboardUtil import Clipboard 14 | from util.KeyBoardUtil import KeyBoardKeys 15 | from util.WaitUntil import WaitUnit 16 | 17 | from selenium import webdriver 18 | 19 | driver = None 20 | waitUtil = None 21 | 22 | 23 | # 打开浏览器 24 | def open_browser(browser): 25 | global driver, waitUtil 26 | try: 27 | if browser.lower() == 'ie': 28 | driver = webdriver.Ie(executable_path=iePath) 29 | elif browser.lower() == 'chrome': 30 | driver = webdriver.Chrome(executable_path=chromePath) 31 | else: 32 | # driver = webdriver.Firefox(executable_path=fireFox) 33 | driver = webdriver.Firefox() 34 | except Exception as e: 35 | raise e 36 | else: 37 | waitUtil = WaitUnit(driver) # driver 创建之后, 创建等待类实例对象 38 | 39 | 40 | # 浏览器窗口最大化 41 | def maximize_browser(): 42 | try: 43 | driver.maximize_window() 44 | except Exception as e: 45 | raise e 46 | 47 | 48 | # 加载网址 49 | def load_url(url): 50 | try: 51 | driver.get(url) 52 | except Exception as e: 53 | raise e 54 | 55 | 56 | # 强制等待 57 | def sleep(num): 58 | try: 59 | import time 60 | time.sleep(num) 61 | except Exception as e: 62 | raise e 63 | 64 | 65 | # 清除输入框的内容 66 | def clear(by, locator): 67 | try: 68 | get_element(driver, by, locator).clear() 69 | except Exception as e: 70 | raise e 71 | 72 | 73 | # 输入框中输入内容 74 | def input_value(by, locator, value): 75 | try: 76 | element = get_element(driver, by, locator) 77 | # element.click() 78 | element.send_keys(value) 79 | except Exception as e: 80 | raise e 81 | 82 | 83 | # 点击操作 84 | def click_btn(by, locator): 85 | try: 86 | get_element(driver, by, locator).click() 87 | except Exception as e: 88 | raise e 89 | 90 | 91 | # 断言页面的title 92 | def assert_title(title): 93 | try: 94 | assert title in driver.title, "%s not found in title!" % title 95 | except AssertionError as e: 96 | raise AssertionError(e) 97 | except Exception as e: 98 | raise e 99 | 100 | 101 | # 断言目标字符串是否包含在页面源码中 102 | def assert_string_in_page_source(string): 103 | try: 104 | assert string in driver.page_source, "%s not found in page source!" % string 105 | except AssertionError as e: 106 | raise AssertionError(e) 107 | except Exception as e: 108 | raise e 109 | 110 | 111 | def assert_error_info(by, locator, string): 112 | element = get_element(driver, by, locator) 113 | text = element.text 114 | assert text == string 115 | 116 | 117 | # 获取当前页面的title 118 | def get_title(): 119 | try: 120 | return driver.title 121 | except Exception as e: 122 | raise e 123 | 124 | 125 | # 获取页面源码 126 | def get_page_source(): 127 | try: 128 | return driver.page_source 129 | except Exception as e: 130 | raise e 131 | 132 | 133 | # 切换到frame里面 134 | def switch_to_frame(by, locator): 135 | try: 136 | driver.switch_to.frame(get_element(driver, by, locator)) 137 | except Exception as e: 138 | raise e 139 | 140 | 141 | # 跳到默认的frame 142 | def switch_to_default(): 143 | try: 144 | driver.switch_to.default_content() 145 | except Exception as e: 146 | raise e 147 | 148 | 149 | # 模拟ctrl+v键 150 | def ctrl_v(value): 151 | try: 152 | Clipboard.set_text(value) 153 | sleep(2) 154 | KeyBoardKeys.two_keys('ctrl', 'v') 155 | except Exception as e: 156 | raise e 157 | 158 | 159 | # 模拟tab键 160 | def tab_key(): 161 | try: 162 | KeyBoardKeys.one_key('tab') 163 | except Exception as e: 164 | raise e 165 | 166 | 167 | # 模拟enter键 168 | def enter_key(): 169 | try: 170 | KeyBoardKeys.one_key('enter') 171 | except Exception as e: 172 | raise e 173 | 174 | 175 | # 屏幕截图 176 | def save_screen_shot(): 177 | picture_name = DirAndTime.create_picture_path() + '\\' + DirAndTime.get_current_time() + '.png' 178 | try: 179 | driver.get_screenshot_as_file(picture_name) 180 | except Exception as e: 181 | raise e 182 | else: 183 | return picture_name 184 | 185 | 186 | def wait_presence_of_element_located(by, locator): 187 | """显示等待页面元素出现在DOM中,单并不一定可见""" 188 | waitUtil.presence_of_element_located(by, locator) 189 | 190 | 191 | def wait_frame_to_be_available_and_switch_to_it(by, locator): 192 | """检查frame是否存在,存在就切换到frame中""" 193 | waitUtil.frame_to_be_available_and_switch_to_it(by, locator) 194 | 195 | 196 | def wait_visibility_of_element_located(by, locator): 197 | """显示等待页面元素出现在DOM中,并且可见""" 198 | waitUtil.visibility_of_element_located(by, locator) 199 | 200 | 201 | # 关闭浏览器 202 | def quit_browser(): 203 | try: 204 | driver.quit() 205 | except Exception as e: 206 | raise e 207 | 208 | 209 | if __name__ == '__main__': 210 | open_browser('firefox') 211 | load_url('http://www.baidu.com') 212 | # inputValue('id', 'kw','python') 213 | # clear('id', 'kw') 214 | # inputValue('id', 'kw', 'python') 215 | # clickBtn('id', 'su') 216 | # sleep(3) 217 | # title = getTitle() 218 | # print(title) 219 | # assertTitle('python') 220 | # assert_string_in_page_source('python') 221 | ctrl_v('python') 222 | --------------------------------------------------------------------------------