├── PageObject ├── __init__.py └── loginPage.py ├── test_case ├── __init__.py ├── test01_login.py └── reports │ └── 测试报告示例.html ├── models ├── __init__.py ├── url.py ├── mail.py └── osDriver.py ├── __init__.py ├── .gitattributes ├── Browser_Driver └── __init__.py ├── logs └── 1603157033.log ├── reports ├── XML测试报告示例.xml └── 测试报告示例.html ├── run.py ├── README.md └── LICENSE /PageObject/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test_case/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /models/__init__.py: -------------------------------------------------------------------------------- 1 | from .osDriver import osSystem 2 | from .url import Url -------------------------------------------------------------------------------- /models/url.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | """ 3 | 存储项目测试网站的地址 4 | """ 5 | class Url: 6 | baseUrl = 'https://www.baidu.com' -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | 更新时间:2020-08-27 3 | 版本说明: 4 | 1、seldom:1.6.0 5 | 2、poium:0.6.3 6 | 3、Python:3.7.4 7 | """ -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.md linguist-language=Python 2 | *.js linguist-language=python 3 | *.css linguist-language=python 4 | *.html linguist-language=python 5 | -------------------------------------------------------------------------------- /Browser_Driver/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | 注意检查 浏览器驱动 是否于本地浏览器版本一致 3 | Chrome浏览器驱动下载地址:http://npm.taobao.org/mirrors/chromedriver/ 4 | 5 | geckodriver(Firefox):https://github.com/mozilla/geckodriver/releases 6 | 7 | IEDriverServer(IE):http://selenium-release.storage.googleapis.com/index.html 8 | 9 | operadriver(Opera):https://github.com/operasoftware/operachromiumdriver/releases 10 | 11 | MicrosoftWebDriver(Edge):https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver 12 | """ -------------------------------------------------------------------------------- /models/mail.py: -------------------------------------------------------------------------------- 1 | from seldom import SMTP 2 | import time 3 | 4 | # 配置e-mail信息 5 | # user = 'you@126.com' # 发送者邮件账号 6 | # password = 'DINODMVPZVSBPYKA' # 发送者邮件授权码 7 | # host = 'smtp.126.com' # host路径 8 | # to = 'to@mail.com' # 邮件接收者,如有多个','英文逗号分割 9 | # subject = None 10 | 11 | 12 | def sendMail(user, password, host, to, subject=None): 13 | try: 14 | smtp = SMTP(user=user, password=password, host=host) 15 | time.sleep(3) 16 | smtp.sender(to=to, subject=subject) 17 | except Exception as error: 18 | return error 19 | -------------------------------------------------------------------------------- /PageObject/loginPage.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | # 用于登录页元素定位 3 | from models import Url 4 | from poium import Page, Element 5 | 6 | 7 | class login(Page): 8 | """ 项目用户登录、退出定位元素""" 9 | # url 10 | url = Url.baseUrl 11 | 12 | # 示例 13 | search_input_loc = Element(id_='kw') 14 | search_button_loc = Element(id_='su') 15 | 16 | # 操作方法封装 17 | def search_input(self, key): 18 | self.search_input_loc.clear() 19 | self.search_input_loc.send_keys(key) 20 | 21 | def search_button(self): 22 | self.search_button_loc.click() 23 | -------------------------------------------------------------------------------- /logs/1603157033.log: -------------------------------------------------------------------------------- 1 | 2020-10-20 09:23:53 [INFO] 当前操作系统:Mac OS 2 | 2020-10-20 09:23:53 [INFO] 正在检查本地ChromeDriver!!! 3 | 2020-10-20 09:23:53 [INFO] ❎检查不到Chromedriver,正在下载... 4 | 2020-10-20 09:23:54 [INFO] 线上最新版本:87.0.4280.20 5 | 2020-10-20 09:23:55 [INFO] Mac驱动下载成功!!! 6 | 2020-10-20 09:23:55 [INFO] 解压成功!!! 7 | 2020-10-20 09:23:55 [INFO] ChromeDriver驱动压缩包删除成功!!! 8 | 2020-10-20 09:23:56 [INFO] 当前版本号:87.0.4280.20 9 | 2020-10-20 09:23:56 [INFO] 线上最新版本:87.0.4280.20 10 | 2020-10-20 09:23:56 [INFO] ✅当前系统Chromedriver已经是最新版本 11 | 2020-10-20 09:24:00 [INFO] 12 | _ _ 13 | | | | | 14 | ___ ___ | | __| | ___ _ __ ___ 15 | / __| / _ \| | / _` | / _ \ | '_ ` _ \ 16 | \__ \| __/| || (_| || (_) || | | | | | 17 | |___/ \___||_| \__,_| \___/ |_| |_| |_| 18 | ----------------------------------------- 19 | @itest.info 20 |  21 | 2020-10-20 09:24:04 [INFO] 👀 assertText: 百度一下. 22 | 2020-10-20 09:24:06 [INFO] 👀 assertText: 百度一下. 23 | 2020-10-20 09:24:07 [INFO] 👀 assertText: 百度一下. 24 | 2020-10-20 09:24:09 [INFO] 👀 assertText: 百度一下. 25 | 2020-10-20 09:24:11 [INFO] 👀 assertText: 百度一下. 26 | 2020-10-20 09:24:11 [INFO] generated html file: file:////Users/yuanbaolei/work/GitHub/UIautoDemo/reports/2020_10_20_09_24_00_result.html 27 | 2020-10-20 09:24:15 [ERROR] ❌ Email failed to send!!(535, b'Error: authentication failed') 28 | -------------------------------------------------------------------------------- /reports/XML测试报告示例.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | 18 | 19 | 21 | 22 | 23 | 24 | 25 | 27 | 28 | 29 | 30 | 31 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /run.py: -------------------------------------------------------------------------------- 1 | """ 2 | main方法说明: 3 | path : 指定测试目录或文件, 4 | browser : 指定测试浏览器,默认Chrome, 5 | report : 自定义测试报告的名称,默认格式为2020_04_04_11_55_20_result.html, 6 | title : 指定测试报告标题, 7 | description : 指定测试报告描述, 8 | debug : debug模式,设置为True不生成测试HTML测试,默认为False, 9 | rerun : 设置失败重新运行次数,默认为 0, 10 | save_last_run : 设置只保存最后一次的结果,默认为False, 11 | driver_path : 设置浏览器驱动的绝对路径。要和 browser 设置保持一致;默认, 12 | grid_url : 设置远程节点,selenium Grid doc, 13 | timeout : 设置超时时间,默认10秒, 14 | xmlrunner : 默认False,True生成xml格式的测试报告,html与xml报告二者选一 15 | 16 | 17 | 邮件发送功能: 18 | 引入'from models.mail import sendMail' 19 | user = 'you@126.com' # 发送邮件账号 20 | password = 'ABC123' # 发送邮件密码 21 | host = 'smtp.126.com' # host路径 22 | to = 'receive@mail.com' # 邮件接受者,如有多个','英文逗号分割 23 | sendMail(user, password, host, to) 24 | """ 25 | 26 | 27 | import seldom 28 | from seldom import ChromeConfig 29 | from models.mail import sendMail 30 | from Cdriver import cdriver 31 | 32 | # 配置e-mail信息 33 | user = 'you@126.com' # 发送者邮件账号 34 | password = 'DINODMVPZVSBPYKA' # 发送者邮件授权码 35 | host = 'smtp.126.com' # host路径 36 | to = 'to@mail.com' # 邮件接收者,如有多个','英文逗号分割 37 | 38 | 39 | if __name__ == '__main__': 40 | ChromeConfig.headless = False 41 | ChromeConfig.executable_path = cdriver() # 默认根据操作系统自行选择Chromedriver驱动 42 | seldom.main( 43 | path='./test_case/test01_login.py', 44 | browser='chrome', 45 | debug=False, 46 | rerun=0, 47 | timeout=10, 48 | save_last_run=True, 49 | title='自动化测试报告', 50 | description='测试环境:Chrome' 51 | ) 52 | """mail邮件发送;关闭注释启用""" 53 | sendMail(user, password, host, to) -------------------------------------------------------------------------------- /test_case/test01_login.py: -------------------------------------------------------------------------------- 1 | """ 2 | 说明: 3 | # 调用的到的 第三方模块:seldom、sys、time 4 | # from seldom import Seldom 5 | # import seldom 6 | # 调用的到的 私有化模块:model/page_object/ 7 | """ 8 | 9 | import seldom 10 | from seldom import Seldom, ChromeConfig 11 | import os 12 | import sys 13 | sys.path.append(os.pardir) 14 | from models.osDriver import osSystem 15 | from PageObject.loginPage import login 16 | 17 | class test01_login(seldom.TestCase): 18 | def start(self): 19 | self.dr = login(Seldom.driver) 20 | self.dr.get(login.url) 21 | self.max_window() 22 | 23 | def down(self): 24 | self.quit() 25 | 26 | @classmethod 27 | def setUpClass(cls): 28 | cls().start() 29 | 30 | def test01(self): 31 | """测试示例1""" 32 | self.dr.search_input(key='百度一下') 33 | self.dr.search_button() 34 | self.assertText("百度一下") 35 | print('用例说明:test01') 36 | 37 | def test02(self): 38 | """测试示例2""" 39 | self.dr.search_input_loc.clear() 40 | self.dr.search_input_loc.send_keys('百度一下') 41 | self.dr.search_button_loc.click() 42 | self.assertText("百度一下") 43 | print('用例说明:test02') 44 | 45 | def test03(self): 46 | """测试示例3""" 47 | self.dr.search_input(key='百度一下') 48 | self.dr.search_button() 49 | self.assertText("百度一下") 50 | print('用例说明:test03') 51 | 52 | def test04(self): 53 | """测试示例4""" 54 | self.dr.search_input(key='百度一下') 55 | self.dr.search_button() 56 | self.assertText("百度一下") 57 | print('用例说明:test04') 58 | 59 | def test05(self): 60 | """测试示例5""" 61 | self.dr.search_input(key='百度一下') 62 | self.dr.search_button() 63 | self.assertText("百度一下") 64 | print('用例说明:test05') 65 | 66 | 67 | if __name__ == '__main__': 68 | ChromeConfig.headless = False 69 | ChromeConfig.executable_path = osSystem('../') # 默认根据操作系统自行选择Chromedriver驱动 70 | seldom.main( 71 | path='../test_case/test01_login.py', 72 | browser='chrome', 73 | debug=False, 74 | rerun=0, 75 | timeout=10, 76 | save_last_run=True, 77 | title='自动化测试报告', 78 | description='测试环境:Chrome' 79 | ) 80 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UiAutoDemo 2 | >基于seldom 和 poium库的 UI自动化测试框架模板 3 | 4 | #### 简介 5 | 6 | UiAutoDemo是一个下载即可用的UI自动化测试框架,专为公司自动化项目免去搭建自动化脚手架,也极其适合刚入门的自动化测试小白。很多入门小白不知道如何去搭建脚本的基本结构,自动化的框架架构;不用担心!这款框架绝对让您满意! 7 | 8 | ```框架支持邮件发送、HTML测试报告、框架默认含Chrome浏览器驱动``` 9 | 10 | #### 特点 11 | + 已经搭建好的```PageObject```设计模式的脚手架。 12 | + 提供[seldom](https://github.com/SeldomQA/seldom/blob/master/docs/seldom_api.md) 与 [poium](https://github.com/SeldomQA/poium/wiki) API编写自动化测试。 13 | + 全局启动浏览器和关闭浏览器,减少浏览器的启动次数。 14 | + 支持测试用例参数化 [parameterized](https://github.com/SeldomQA/seldom/blob/master/docs/parameterized.md) 15 | + 支持用例 失败/错误 重新尝试case 16 | + 支持生成```HTML```测试报告 与 ```XML```测试报告,用例失败/错误自动截图 17 | + 支持```HTML```测试报告邮件发送 18 | + 自动根据当前环境,调用Chrome浏览器驱动 19 | 20 | #### 必看! 21 | 22 | + ```UiAutoDemo```框架使用的是 ```PageObject```设计模式,简称```PO```;不懂什么是PO设计模式,下面有介绍 ↓; 23 | + 使用的编译语言 ```Python>=3.5```; 24 | + 框架使用的是 ```seldom``` 与 ```poium``` 第三方库,往下看有介绍 ↓; 25 | + 本框架自带```Chromedriver```浏览器驱动,自动检测本地操作环境调用该环境相应的Chrome驱动程序,但需要本地浏览器更新到最近版本 26 | + 测试类与测试用例的命名请遵从 ```ASCII码的顺序加载测试用例,数字与字母的顺序为:0-9,A-Z,a-z``` 27 | + ```UiAutoDemo```仅兼容```Unittest```框架;请勿使用其他测试框架运行 28 | + 框架内的```Chromedriver```驱动作者会持续更新,也可自行引入路径 29 | 30 | #### 项目架构 31 | 32 | ``` 33 | - UiAutoDemo/ 34 | - |── test_case/ 35 | - |── test_login.py 36 | - |──models/ 37 | - |── url.py 38 | - |── mail.py 39 | - |── osDriver.py 40 | - |──PageObject/ 41 | - |── loginPage.py 42 | - |── Browser_Driver/ 43 | - |── chromedriver84(Mac64) 44 | - |── chromedriver84(win32).exe 45 | - |── reports/ 46 | - |—— 年_月_日_时_分_秒_result.html 47 | - |—— 年_月_日_时_分_秒.xml 48 | - └── run.py 49 | ``` 50 | 51 | + ```testcase``` 文件夹用于存放页面元素,测试用例,公共元素 52 | + ```- test_login.py``` 编写局部模块的测试用例并执行 53 | + ```models``` 文件夹存放公共元素,如url 54 | + ```- url.py``` 存放测试url路径 55 | + ```- mail.py``` 用于发送邮件 56 | + ```- osDriver.py``` 检查本地操作系统环境,根据本地环境自动选择相应的driver驱动运行项目 57 | + ```PageObject``` 文件夹存放测试过程中需要使用的页面元素 58 | + ```- loginPage.py``` 存放页面元素定位,封装元素实例化 59 | + ```Browser_Driver``` 文件夹存放浏览器驱动 60 | + ```- chromedriver84(Mac64)``` Mac操作系统Chrome驱动 61 | + ```- chromedriver84(win32).exe``` Windows操作系统Chrome驱动 62 | + ```reports``` 文件夹存放项目测试后生成的测试报告 63 | + ```- 年_月_日_时_分_秒_result.html``` HTML测试报告 64 | + ```- 年_月_日_时_分_秒.xml``` XML测试报告 65 | + ```run.py``` 执行所有的测试用例并执行 66 | 67 | #### 依赖库 68 | 69 | + Python3.7.4 >= 70 | + poium0.6.3 >= (pip install poium) 71 | + seldom1.7.0 >= (pip install seldom) 72 | 73 | #### PageObject设计模式 74 | 75 | >PageObject模式是Selenium中的一种测试设计模式,主要是将每一个页面设计为一个Class,将页面定位和业务操作分开,分离测试对象(元素对象)和测试脚本(用例脚本),提高用例的可维护性。其中包含页面中需要测试的元素(按钮,输入框,标题 等),这样在测试页面中可以通过调用页面类来获取页面元素,这样巧妙的避免了当页面元素id或者其他位置变化时,需要改测试页面代码的情况。 当页面元素id变化时,只需要更改测试页Class中页面的属性即可。 76 | 77 | 78 | 79 | #### UiAutoDemo框架模块 80 | ```框架内的每个py文件都有注解;请使用者仔细阅读``` 81 | 82 | 1、此框架仅根据PageObject设计模式搭建的基础框架 83 | 84 | 2、封装一些便于运行项目的模块 85 | 86 | 3、Chromedriver驱动调用```from models import osSystem``` 87 | 88 | 4、运行项目 89 | 90 | 91 | ![d4I3TK.png](https://s1.ax1x.com/2020/08/27/d4I3TK.png) 92 | 93 | 5、查看报告 94 | 可以到```reports```查看测试报告 95 | 96 | ![查看报告](https://s1.ax1x.com/2020/08/27/d4dbSe.png) 97 | 98 | 99 | #### seldom文档 100 | 请阅读下面的文档,帮助你快速学习了解Seldom。 101 | 102 | * [seldom安装](https://github.com/SeldomQA/seldom/blob/master/docs/install.md) 103 | 104 | * [seldom创建项目](https://github.com/SeldomQA/seldom/blob/master/docs/create_project.md) 105 | 106 | * [浏览器&驱动](https://github.com/SeldomQA/seldom/blob/master/docs/driver.md) 107 | 108 | * [运行测试](https://github.com/SeldomQA/seldom/blob/master/docs/run_test.md) 109 | 110 | * [main()方法](https://github.com/SeldomQA/seldom/blob/master/docs/main.md) 111 | 112 | * [生成测试报告](https://github.com/SeldomQA/seldom/blob/master/docs/reports.md) 113 | 114 | * [seldom 元素定位](https://github.com/SeldomQA/seldom/blob/master/docs/find_element.md) 115 | 116 | * [seldom API](https://github.com/SeldomQA/seldom/blob/master/docs/seldom_api.md) 117 | 118 | * [keys键盘操作](https://github.com/SeldomQA/seldom/blob/master/docs/keys.md) 119 | 120 | * [seldom 断言](https://github.com/SeldomQA/seldom/blob/master/docs/assert.md) 121 | 122 | * [用例失败重跑&自动截图](https://github.com/SeldomQA/seldom/blob/master/docs/rerun_screenshot.md) 123 | 124 | * [数据驱动最佳实践](https://github.com/SeldomQA/seldom/blob/master/docs/parameterized.md) 125 | 126 | * [实现Page Objects设计模式](https://github.com/SeldomQA/seldom/blob/master/docs/poium.md) 127 | 128 | * [生成测试数据](https://github.com/SeldomQA/seldom/blob/master/docs/testdata.md) 129 | 130 | * [跳过测试用例](https://github.com/SeldomQA/seldom/blob/master/docs/skip.md) 131 | 132 | * [发邮件功能](https://github.com/SeldomQA/seldom/blob/master/docs/send_mail.md) 133 | 134 | * [test fixture](https://github.com/SeldomQA/seldom/blob/master/docs/setupclass.md) 135 | 136 | #### poium文档 137 | 138 | * [介绍](https://github.com/SeldomQA/poium/blob/master/README.md) 139 | * [HOME](https://github.com/SeldomQA/poium/wiki) 140 | * [PageSelect](https://github.com/SeldomQA/poium/wiki/PageSelect) 141 | * [PageWait](https://github.com/SeldomQA/poium/wiki/PageWait) 142 | 143 | #### 写到最后 144 | 145 | 1.此项目仅是一个自动化测试项目的脚手架,并不是Python第三方库 146 | 147 | 2.对selenium有一定的基础底子,能够很快用起来;纯小白也没关系,仔细阅读[seldom](https://github.com/SeldomQA/seldom/blob/master/docs/seldom_api.md) 与 [poium](https://github.com/SeldomQA/poium/wiki)文档即可 148 | 149 | 3.后期会不断添加一些新奇功能便于测试项目的工作 150 | 151 | #### 交流 152 | 153 | QQ群:948994709 154 | -------------------------------------------------------------------------------- /models/osDriver.py: -------------------------------------------------------------------------------- 1 | import re 2 | import os 3 | import zipfile 4 | import platform 5 | import requests 6 | from seldom.logging import log 7 | 8 | """ 9 | # 判断当前操作系统环境;以此来自动选择不同浏览器环境的驱动 10 | """ 11 | 12 | class automatic(object): 13 | def __init__(self): 14 | self.url = 'http://npm.taobao.org/mirrors/chromedriver/' 15 | 16 | # 获取线上最新版本号与版本时间 17 | def get_latest_version(self): 18 | rep = requests.get(self.url, timeout=30).text 19 | time_list = [] 20 | time_version_dict = {} 21 | result = re.compile(r'\d.*?/.*?Z').findall(rep) 22 | for x in result: 23 | time = x[-24:-1] 24 | version = re.compile(r'.*?/').findall(x)[0] 25 | time_version_dict[time] = version 26 | time_list.append(time) 27 | latest_version = time_version_dict[max(time_list)][:-1] # 获取浏览器版本号 28 | log.info('线上最新版本:'+str(latest_version)) 29 | return latest_version 30 | 31 | # 下载Mac系统下的Chromedriver 32 | def mac_download_driver(self, path=''): 33 | latest_version = automatic().get_latest_version() 34 | mac_driver_url = self.url + latest_version + '/chromedriver_mac64.zip' 35 | file = requests.get(mac_driver_url, timeout=60) 36 | with open(path + r'Browser_Driver/chromedriver.zip', 'wb') as zip_file: 37 | zip_file.write(file.content) 38 | log.info('Mac驱动下载成功!!!') 39 | 40 | # 下载Windows系统下的Chromedriver 41 | def win_download_driver(self, path=''): 42 | latest_version = automatic().get_latest_version() 43 | win_driver_url = self.url + latest_version + '/chromedriver_win32.zip' 44 | file = requests.get(win_driver_url, timeout=60) 45 | with open(path + r'Browser_Driver/chromedriver.zip', 'wb') as zip_file: 46 | zip_file.write(file.content) 47 | log.info('Windows驱动下载成功!!!') 48 | 49 | # 解压缩包 50 | def Unpack_driver(self, path=''): 51 | file = zipfile.ZipFile(path + r'Browser_Driver/chromedriver.zip', 'r') 52 | for files in file.namelist(): 53 | file.extract(files, path + r'Browser_Driver') 54 | log.info('解压成功!!!') 55 | file.close() 56 | os.remove(path + r'Browser_Driver/chromedriver.zip') 57 | log.info('ChromeDriver驱动压缩包删除成功!!!') 58 | 59 | # Mac系统下的本地与线上版本对比 60 | def Contrast_mac(self, path=''): 61 | try: 62 | log.info('正在检查本地ChromeDriver!!!') 63 | r = os.path.abspath(path + r'Browser_Driver/chromedriver') 64 | os.popen('chmod +x '+r) 65 | version = os.popen(r + r' --version').read() 66 | version = version.split(' ')[1] 67 | log.info("当前版本号:"+str(version)) 68 | except Exception as error: 69 | error 70 | log.info('❎检查不到Chromedriver,正在下载...') 71 | automatic().mac_download_driver(path=path) 72 | automatic().Unpack_driver(path=path) 73 | r = os.path.abspath(path + r'Browser_Driver/chromedriver') 74 | os.popen('chmod +x ' + r) 75 | version = os.popen(r + r' --version').read() 76 | version = version.split(' ')[1] 77 | log.info("当前版本号:"+str(version)) 78 | if version == automatic().get_latest_version(): 79 | log.info('✅当前系统Chromedriver已经是最新版本') 80 | else: 81 | log.info('当前系统Chromedriver不是最新版本,需要更新!!! 请等待!!!') 82 | automatic().mac_download_driver(path=path) 83 | automatic().Unpack_driver(path=path) 84 | 85 | # Windows系统下的本地与线上版本对比 86 | def Contrast_win(self, path=''): 87 | try: 88 | log.info('正在检查本地ChromeDriver!!!') 89 | r = os.path.abspath(path + r'Browser_Driver/chromedriver.exe') 90 | version = os.popen('"'+r+'"' + r' --version').read() 91 | version = version.split(' ')[1] 92 | log.info("当前版本号:"+str(version)) 93 | except Exception as error: 94 | error 95 | log.info('❎检查不到Chromedriver,正在下载...') 96 | automatic().win_download_driver(path=path) 97 | automatic().Unpack_driver(path=path) 98 | r = os.path.abspath(path + r'Browser_Driver/chromedriver.exe') 99 | version = os.popen('"'+r+'"' + r' --version').read() 100 | version = version.split(' ')[1] 101 | log.info("当前版本号:"+str(version)) 102 | 103 | if version == automatic().get_latest_version(): 104 | log.info('✅当前系统Chromedriver已经是最新版本') 105 | else: 106 | log.info('当前系统Chromedriver不是最新版本,需要更新!!! 请等待!!!') 107 | automatic().win_download_driver(path=path) 108 | automatic().Unpack_driver(path=path) 109 | 110 | def osSystem(path=''): 111 | os_system = platform.system() 112 | driver = automatic() 113 | if os_system == 'Windows': 114 | log.info('当前操作系统:Windows') 115 | driver.Contrast_win(path=path) # 检查对比Windows系统环境下的Chromedriver 116 | pathWin = path + r'Browser_Driver/chromedriver.exe' 117 | return pathWin 118 | elif os_system == 'Darwin' or \ 119 | os_system == 'darwin' or \ 120 | os_system == 'Mac' or \ 121 | os_system == 'mac' or \ 122 | os_system == 'OS X': 123 | log.info('当前操作系统:Mac OS') 124 | driver.Contrast_mac(path=path) # 检查对比Mac系统环境下的Chromedriver 125 | pathMac = path + r'Browser_Driver/chromedriver' 126 | return pathMac 127 | else: 128 | log.error("当前操作系统 " + os_system) 129 | raise SystemExit(log.error(' ❌ The current operating system environment is not Windows or Mac, ' 130 | 'please confirm the current environment!!')) 131 | 132 | 133 | if __name__ == '__main__': 134 | result = automatic() 135 | osSystem('../') 136 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /reports/测试报告示例.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 自动化测试报告 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 149 | 150 | 151 | 152 | 331 | 332 | 343 |
344 |
345 |
346 |
347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 |
Start Time:2020-07-27 10:58:40
Duration:0:00:51.516541
Status:Passed:10
Description:测试环境:Chrome
356 |
357 |
358 |
359 |
360 |

Test Case Pie charts

361 |

10

362 | PASSED
363 |

0

364 | FAILED 365 |

0

366 | ERRORS
367 |

0

368 | SKIPED
369 |
370 |
371 | 372 |
373 |
374 | 375 | 376 |

377 | Summary 378 | Pass 379 | Failed 380 | Error 381 | Skip 382 | All 383 |

384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 427 | 428 | 429 | 430 | 431 | 432 | 450 | 451 | 452 | 453 | 454 | 455 | 473 | 474 | 475 | 476 | 477 | 478 | 496 | 497 | 498 | 499 | 500 | 501 | 519 | 520 | 521 | 522 | 523 | 524 | 542 | 543 | 544 | 545 | 546 | 547 | 565 | 566 | 567 | 568 | 569 | 570 | 588 | 589 | 590 | 591 | 592 | 593 | 611 | 612 | 613 | 614 | 615 | 616 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 |
Test Group/Test caseCountPassFailErrorViewScreenshots
test01_login.test01_login101000Detail 
test01: 测试示例1
410 | 411 | 412 | pass 413 | 425 | 426 |
test02: 测试示例2
433 | 434 | 435 | pass 436 | 448 | 449 |
test03: 测试示例3
456 | 457 | 458 | pass 459 | 471 | 472 |
test04: 测试示例4
479 | 480 | 481 | pass 482 | 494 | 495 |
test05: 测试示例5
502 | 503 | 504 | pass 505 | 517 | 518 |
test06: 测试示例6
525 | 526 | 527 | pass 528 | 540 | 541 |
test07: 测试示例7
548 | 549 | 550 | pass 551 | 563 | 564 |
test08: 测试示例8
571 | 572 | 573 | pass 574 | 586 | 587 |
test09: 测试示例9
594 | 595 | 596 | pass 597 | 609 | 610 |
test10: 测试示例10
617 | 618 | 619 | pass 620 | 632 | 633 |
Total101000  
647 | 648 |
 
649 | 650 | 689 | 690 | 691 | 692 | -------------------------------------------------------------------------------- /test_case/reports/测试报告示例.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 自动化测试报告 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 149 | 150 | 151 | 152 | 331 | 332 | 343 |
344 |
345 |
346 |
347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 |
Start Time:2020-07-27 10:58:40
Duration:0:00:51.516541
Status:Passed:10
Description:测试环境:Chrome
356 |
357 |
358 |
359 |
360 |

Test Case Pie charts

361 |

10

362 | PASSED
363 |

0

364 | FAILED 365 |

0

366 | ERRORS
367 |

0

368 | SKIPED
369 |
370 |
371 | 372 |
373 |
374 | 375 | 376 |

377 | Summary 378 | Pass 379 | Failed 380 | Error 381 | Skip 382 | All 383 |

384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 427 | 428 | 429 | 430 | 431 | 432 | 450 | 451 | 452 | 453 | 454 | 455 | 473 | 474 | 475 | 476 | 477 | 478 | 496 | 497 | 498 | 499 | 500 | 501 | 519 | 520 | 521 | 522 | 523 | 524 | 542 | 543 | 544 | 545 | 546 | 547 | 565 | 566 | 567 | 568 | 569 | 570 | 588 | 589 | 590 | 591 | 592 | 593 | 611 | 612 | 613 | 614 | 615 | 616 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 |
Test Group/Test caseCountPassFailErrorViewScreenshots
test01_login.test01_login101000Detail 
test01: 测试示例1
410 | 411 | 412 | pass 413 | 425 | 426 |
test02: 测试示例2
433 | 434 | 435 | pass 436 | 448 | 449 |
test03: 测试示例3
456 | 457 | 458 | pass 459 | 471 | 472 |
test04: 测试示例4
479 | 480 | 481 | pass 482 | 494 | 495 |
test05: 测试示例5
502 | 503 | 504 | pass 505 | 517 | 518 |
test06: 测试示例6
525 | 526 | 527 | pass 528 | 540 | 541 |
test07: 测试示例7
548 | 549 | 550 | pass 551 | 563 | 564 |
test08: 测试示例8
571 | 572 | 573 | pass 574 | 586 | 587 |
test09: 测试示例9
594 | 595 | 596 | pass 597 | 609 | 610 |
test10: 测试示例10
617 | 618 | 619 | pass 620 | 632 | 633 |
Total101000  
647 | 648 |
 
649 | 650 | 689 | 690 | 691 | 692 | --------------------------------------------------------------------------------