说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家!
目录
一丶叙述
1.项目介绍
项目分为九部分:基础项目实战丶PageObject丶Unittest丶数据驱动丶关键字驱动丶行为驱动丶日志模块丶持续继承丶源码管理
实战基础:[{"Selenium3":["环境搭建","基础API使用"]},"如何破解验证码","基础函数的封装"]
分层自动化:["分层设计思想","分层设计实战","分层case编写","流程调节"]
Unittest与PO结合:["Unittest的使用","assert断言","HTMLTestRunner","如何批量管理case","失败截图处理","项目结合"]
数据驱动的使用:["数据驱动基础","PO中引入数据驱动","文件实现数据驱动","项目中引入数据驱动"]
关键字模型从设计到开发:{"实现持续集成":["关键字模型设计","操作类设计封装","关键字模型实现","流程梳理"]}
行为驱动从设计到开发:["环境搭建","行为驱动分析","行为驱动case编写","行为驱动和PO"]
日志模块项目中的使用:["日志模块介绍","日志简单应用","保存日志","项目中使用日志"]
持续集成:["持续集成的使用","使用邮件进行通知","定时执行工程"]
源码管理:["git环境的搭建","仓库的运用","创建分支","代码的克隆","实现更好的管理"]
2.项目效果展示
- 首先博主先展示一个比较low的HTMLTestRunner测试报告
- 话不多说高大上的HTMLTestRunner测试报告
- 点击详情后,查看对应测试用例结果
- 点击失败,可查看测试用例失败的详情错误信息
- 鼠标放在饼形图上可查看测试结果比列数据
- 最后的测试报告则是通过持续集成Jenkins来向目标邮箱发送测试报告
二丶环境搭建
1.selenium环境搭建
- Selenium工作原理
- 需要的环境有Client丶Driver丶Brower
- Client端使用Pycharm进行代码编写开发语言为python3
- Driver端使用谷歌浏览器的ChromeDriver
2.环境搭建实战
- python3.x版本的安装,因博主早就安装了所以这里不演示
- 安装项目的虚拟环境
- 在以上创建的webtest_py3环境中安装selenium
- 在Pycharm中新建一个名为SeleniumPython的项目,项目环境为webtest_py3
- 创建项目成功后,在项目根目录下创建cdtaogang_selenium目录,然后该目录下创建start_browser.py文件,如下
- 在start_browser文件中编写如下代码启动chrome浏览器
-
from selenium
import webdriver
-
driver = webdriver.Chrome()
- 运行start_browser文件,则提示如下错误信息
- 出现以上错误是因为selenium不知道你的浏览器的位置,所以需要安装chromedriver来作为中间件来操作你的浏览器,首先需要知道你的谷歌浏览器的版本信息,点击浏览器中的帮助——关于Google Chrome来查看版本信息
- 进入谷歌官网去下载对应版本的chromedriver,地址http://chromedriver.chromium.org/downloads,如下博主的谷歌浏览器版本为75则下载如下版本的chromedriver
- 紧接着将下载好的chromedriver.exe文件拷贝到你的项目使用的python安装目录即可
- 重新运行代码,成功打开谷歌浏览器
- 通过driver对象的get方法,在方法中输入url地址,运行代码则打开谷歌浏览器并且访问目标url地址
3.需求分析及用例设计
- 对乐学网站的注册功能进行分析,如下图所示
- 创建测试需求分析文档
- 创建测试用例文档
- 测试用例文档中的id元素的值,通过浏览器检查即可看到
4.注册页面结构分析
- 在网站的注册页面,点击检查元素,通过选择器来选择页面内容查看该页面内容对应的html标签,发现整个注册窗口分为两个部分,第一部分就是如下图所示的login-tab标签容器,第二部分就是login-main输入框部分所在的容器
- 查看login-main容器下的输入框容器,都是在form表单中进行提交到服务器的
- 在form表单中的div表示每个输入框以及提交按钮的容器,查看每个div对应的页面内容
- 还可以输入js代码来获取你想要获取的html标签元素
5.启动不同浏览器
说明:在实际自动化测试工作中,肯定不会只打开一种浏览器
- 前面已经对谷歌浏览器Chrome进行了打开并成功访问百度,接下来是打开IE浏览器,首先需要跟之前Chrome浏览器一样需要下载driver插件,进入http://selenium-release.storage.googleapis.com/index.html地址下载IE的IEDriverServer,需要注意的是IEDriverServer的版本要与你安装的Selenium版本一致不然会出错,然后将下载好的IEDriverServer.exe文件放在项目所在的python安装目录中,如果你的windows版本为10则需要去官网下载MicrosoftWebDriver.exe
- 然后在start_browser文件中去调用Ie的接口方法打开浏览器,需要注意的是win10是调用Edge方法
- 接着是火狐浏览器,同样的需要下载driver插件,地址https://github.com/mozilla/geckodriver/releases 去下载对应windows版本的geckodriver,将下载好的geckodriver.exe文件拷贝到python安装目录下
- 然后在代码中调用Firefox方法,成功的打开火狐浏览器并访问百度
6.使用title_contains检查页面是否正确
- 通过selenium打开浏览器并访问测试的网站地址,根据页面的元素以及网页的title标题来判断是否成功的打开目标地址
- 通过从selenium.webdriver.support包中导入expected_conditions,再使用expected_conditions模块中的title_contains方法来判断目标地址title中是否包含了"注册"字段,查看打印的结果说明title中包含了"注册"字段
7.使用不同方式进行定位
- 注册表单中的邮箱地址通过class选择器定位
driver.find_element_by_class_name("form-control input-lg").send_keys("cdtaogang@163.com")
- 注册表单中的用户名通过id选择器定位
driver.find_element_by_id("register_nickname").send_keys("cdtaogang")
- 注册表单中的密码通过name属性来进行定位
driver.find_element_by_name("password").send_keys("111111")
- 注册表单中的验证码通过xpath来进行定位
driver.find_element_by_xpath('//*[@id="captcha_code"]').send_keys("xrfdw")
- 运行代码,则出现如下错误提示
- 导致以上错误的原因是第一存在书写不规范传递的class name中存在空格,第二主要是该class name的值不唯一
- 解决方法就是:要么不使用class name进行定位,要么就在当前class name上增加父级的class name来保证数据唯一
driver.find_element_by_class_name("controls").find_element_by_class_name("form-control").send_keys("cdtaogang@163.com")
- 重新运行代码,成功的访问注册页面并自动填写注册表单的数据
- 动图显示自动输入表单数据
- 其实代码是有问题的,之所以能成功输入邮箱地址丶用户名丶密码以及验证码,那是因为博主刚好是在表单第一个div容器邮箱地址选择了class name进行查找的,因为按照父级div class="controls" 子级 div class="form-control input-lg"的标签不是唯一的
- 所以正确的代码因该是通过find_elements_by_class_name获取class name 为controls的所有结果集,取结果集的第一个元素,为什么是第一个元素因为邮箱地址就是表单中的第一个元素,然后从结果中找到class name为form-control的标签,这才是正确的代码
8.如何使用Expected_conditions判断元素是否可见
- 需要使用expected_conditions模块也就是ec中的visibility_of_element_located来检验元素的可见性,然后再selenium.webdriver.support包下的wait模块中导入WebDriverWait这个类,通过实例化这个类后调用其until方法来判断元素是否存在,存在的话代码继续运行不存在则返回false
-
element = driver.find_element_by_class_name(
"controls")
-
result = ec.visibility_of_element_located(element)
-
WebDriverWait(driver,
1).until(result)
- 运行代码,提示如下错误
- 解决方法:from selenium.webdriver.common.by import By导入By这个类,通过这个类的CLASS_NAME属性与查找元素class name的值"controls"来形成元组传递给visibility_of_element_located进行构造
- 到现在这一步,如果有朋友发现自己的电脑比较卡的话,那是因为不断的运行程序,那么就会一直在windows任务中创建 chromedriver.exe的计划,这样导致自己电脑越来越卡;但是博主的电脑没有感受到任何的卡顿,可能是内存性能比较高吧
- 解决方法就是在代码中进行close关闭driver
driver.close()
9.Expected_conditions源码分析
- 在Pycharm中按住Ctrl后鼠标左键点击即可进入源码查看,通过源码的注释以及返回值包括核心代码来查看整个实现过程,也能看出框架的核心的代码,如下我们之前调用的title_is这个方法源码中就是拿传递的title与driver中的title进行对比,返回Boolean类型
- 还有就是实例化visibility_of_element_located类时,传递的locator,来判断元素是否存在不存在出现异常则返回False
10.输入注册用户名字及获取用户信息
- 在注册页面的邮箱地址一栏,通过代码获取邮箱地址栏标签中placeholder得值,也就是“填写你常用的邮箱作为登录帐号”这句话,首先是获取邮箱所在的element元素,通过get_attribute方法来获取该标签中想要获取的元素,代码如下
-
email_element = driver.find_element_by_id(
"register_email")
-
print(email_element.get_attribute(
"placeholder"))
- 通过邮箱地址element元素send_keys方法向input框中输入邮箱地址,然后再通过get_attribute方法来获取输入的value属性值,需要注意的是当你input框中输入数据时,检查元素中并没有input框中的数据字段,当没有属性值的则默认输入value进行获取,代码如下
-
email_element.send_keys(
"xxx@163.com")
-
print(email_element.get_attribute(
"value"))
- 运行代码,查看结果中成功打印出邮箱地址input标签中的placeholder的值以及input框中的内容
11.如何生成用户名
- 使用python内置的random模块进行邮箱地址的生成
12.如何解决验证码思路
- 在公司内部测试中可以通过登录成功后的cookie状态来进行登录忽略验证码,还可以公司开发设定一个万能的验证码以及取消验证码,在这里我们通过将生成的二维码图片通过selenium driver中的sava方法进行保存后,使用pytesseract读图片中的验证码进行解析
13.如何解决验证码代码实战
- 验证码的图片是需要我们去获取的,只能定位页面中验证码的坐标来将图片裁剪下来进行识别,为什么不能通过验证码的url地址来进行图片的获取,因为每当访问或者刷新图片验证码的地址会导致验证码的更改,所以必须要取页面上用户看到的验证码图片,首先获取页面中验证码的坐标,并通过save_screenshot方法将页面保存下来
- 查看F:/selenium_image/captcha.png文件,并打开此图片
- 紧接着需要获取验证码的高度和宽度,然后通过python的pillow库中image对象的corp对下载到F:/selenium_image/captcha.png的图片进行裁剪,将裁剪下的图片保存到F:/selenium_image/captcha_1.png文件
- 打开F:/selenium_image/captcha_1.png图片,成功截取到验证码图片
14.使用pytesseract识别图片中得问题
- 首先需要在项目环境中安装pytesseract库
- 然后在项目目录下常见read_image_code.py文件,在文件中编写如下代码,并对之前截取的captcha_1.png图片进行读取打印出图片中的文字,从打印结果看很不理想无法读取,原因是pytesseract库读取图片中的文字信息是要求整洁清晰并且有规则无干扰项
15.showapiRequest解决图片验证码识别
- 目前来说要能识别图片验证并且有很高的的效率要么就是自己去开发一个失败图片验证码的框架或者工具,这个难度比较高,要么就是去调用别人公司开发出来的api进行使用,博主在https://www.showapi.com/ 中去下载其python语言下的sdk工具
- 需要注册用户后,选择图片验证码识别,然后进行购买使用套餐即可,价格也很便宜
- 购买成功以后在,我的订单中则出现了如下的计量,可以看到使用每个验证码接入点的配量,只需要0.1元
- 在我的资源中则看到自己购买的资源包
- 紧接着在网站中去进行接口测试,测试是否对图片验证码提取识别成功
- 在代码中进行如下编写,对前面截取的注册验证码进行识别,结果显示识别成功;需要注意的是在网站提供的python示例代码中的my_appId和my_appSecret的值需要从个人中心我的应用中去获取的
- 最后通过json.loads将字符串转为json对象并取值,从json中获取图片验证码的值
16.注册输入验证码流程整合
- 现在我们将read_image_code中的代码拷贝到start_browser中并将读取到的图片验证码的值自动填写到验证码输入框中
- 运行代码,成功打开网站读取验证码正确,并成功在验证码框自动输入验证码
17.注册流程梳理及代码封装
- 在项目目录下创建register_code.py用于编写注册相关的核心代码,完成用户自动化注册功能实现,说白点就是将之前的代码整合一起进行封装后一次性完成邮箱用户名的随机生成获取验证码注册即可,代码如下
- 测试自动化进行用户注册成功,为了让大家看到效果博主在测试时将driver.close已经注释掉了
18.以配置文件形式实现定位设计思想
说明:当网站页面的数据包括html代码进行变更后,那么我们封装的代码则需要进行对应的修改,这样直接在代码上进行修改肯定是很low的,那么就需要创建一个项目的配置文件,将这样定位元素放到配置文件中,在代码只需要从配置文件中读取数据即可,即使网站页面变更我们只需要修改配置文件的数据即可
- 在项目根目录下创建config配置目录,在该目录下创建LocalElement.ini配置文件,在配置文件中将网站注册页面中input输入框中中所有的元素数据进行如下的配置,以:分开前面的为属性后面为属性值
19.如何读取配置文件low代码
- 首先需要安装python的读取ini文件的库configparser
- 然后在项目目录下创建read_ini.py文件,在文件中对创建的LocalElement.ini文件中内容进行读取
20.重构封装读取配置文件方法
- 将read_ini中的代码使用类进行封装后,运行代码同样成功获取出配置文件中user_email的数据
21.设计封装定位元素类
- 为了降低代码模块的容错率,需要在项目目录下创建一个utils的python包,并且将read_ini.py文件拷贝到utils包下,然后再在项目目录下创建一个find_element.py文件,用于操作对read_ini中获取到的data数据进行分割分别获取到元素类别属性以及属性值
22.如何将整个注册流程脚本进行模块化实战
- 在项目目录下创建register_func.py脚本文件,在该文件中主要的逻辑为整合register_code.py和read_ini.py以及find_element.py中的代码完成整个注册功能自动化脚本,详细代码如下,逻辑很简单就是各种封装各种调用最后整合即可
- 测试自动化完成注册功能成功,非常完美perfect
23.注册失败进行截图处理
分析:在注册页面进行用户注册时,因邮箱地址和用户名以及密码是不可能报错的,所导致注册失败的原因只有验证码错误
- 根据验证码错误提示获取页面的元素信息
- 紧接着在LocalElement.ini配置文件中添加验证码错误的配置数据
- 然后在register_func中main方法中获取验证码错误元素数据,当数据为空时表示注册成功,反正则失败,为了更好的演示注册失败,需要将代码captcha_code对应的data数据传递为xxxx数据,这样做导致验证码肯定是错误的
- 运行代码后,在浏览器网站页面中成功在验证码输入框输入指定的错误验证码,导致验证码错误
- 查看代码运行结果,成功提示出注册失败,说明逻辑正确
- 最后查看注册失败保存到F:/selenium_image/code_error.png图片
24.多浏览器跑case
- 在启动代码中进行for循环根据遍历生成的i的值来判断driver的值,0代表使用Chrome,1代表Firefox,2代表Ie浏览器
-
if __name__ ==
'__main__':
-
for i
in range(
3):
-
RegisterFunc(
"http://www.5itest.cn/register", i).main()
- 运行代码后,均显示注册失败,因为验证码这一块的值被我们写死了
三丶项目实战中PO模型的设计与封装
说明:PO即Page Object设计模式,通俗解释一下就是每个页面当成一个对象,给这些页面写一个类,主要就是完成元素定位和业务操作;Page Object将测试对象及单个的测试步骤封装在每个Page对象中,以page为单位进行管理;优势就是如果页面元素发生变化,你去维护页面元素配置文件即可,测试类的代码不需要更改
1.po模型设计思想
- 前面完成了注册功能的自动化测试,核心代码为register_func.py,该模块可以完成自动化测试注册功能,但是代码的复用性很低,只适合注册功能的自动化测试,要想在网站的其他页面如登录丶主页以及搜索等等页面进行测试的话是不可能的,所以需要在项目中使用po模型思想,对每个页面都写一个类进行单个测试,在项目进行如下的分层结构
2.po模型之如何设计操作层
- 通过first_case.py模块中注册case得知需要去测试邮箱丶用户名丶密码丶验证码以及注册功能是否错误或者成功,然后根据register_handle.py模块来发送数据并进行处理页面元素的数据,而在register_handle模块于first_case模块中则需要一个register_business.py模块操作我们的register_handle模块并将其进行组装, 操作层结构如下
3.po模型设计之如何设计业务层
- 通过把register_business模块中的对应邮箱丶用户名丶密码丶验证码的判断是否成功来判断first_case模块中的case是否成功,中间只是通过register_handle模块中获取注册页面的错误信息,在register_business通过调用获取的错误信息来判断返回True还是False,最后在first_case模块中根据register_business模块返回的Boolean值来进行下一步的处理操作,业务层结构如下
4.po模型设计之如何设计po及模块串联设计
思路:首先在项目根目录下创建base包,然后这个包主要存放的是一些共同使用的模块,将之前cdtaogang_selenium包下的find_element.py模块拷贝到base包下,紧接着还需要创建一个page包,再在该包下创建一个register_page.py模块,这个模块的作用就是去调用find_element.py模块的get_element方法通过传递的key的值到LocalElement.ini配置文件中去获取注册页面元素数据,然后register_page模块中将元素数据返回到register_handle模块中向该元素发送数据
- 项目目录体系如下
- 核心代码块为最开始的first_case——register_business——register_handle——register_page——find_element,说白了就是这几个模块之前的各种调用而已
5.po模型设计之如何把注册页面组装成完整的自动化case
- 首先需要在register_page模块中完成获取所有注册页面的元素,需要注意的是在register_handle模块中的get_error_msg方法中需要获取每个input框错误提示信息,所以需要在LocalElement.ini配置文件中添加错误信息配置
- 紧接着在register_hanle模块中也需要将其他输入数据的方法进行补全,最后还需要获取注册页面错误提示信息的值
6.po模型设计之注册页面常见业务case编写
- 首先在register_handle模块中定义一个click_register方法,用户注册页面注册按钮的点击;然后再定义一个get_register_button_text获取注册页面注册按钮的value值
- 需要将整个po模型补全,首先在register_business模块中对其余输入框的数据进行验证,并定义一个register_success方法在这个方法中调用register_handle模块中的get_register_button_text方法来判断是否注册成功,当页面注册成功后,则页面就没有注册按钮所在的元素了,即在find_element模块中的get_element方法中会抛出异常返回None
- 最后在first_case模块中进行po模型分层case处理注册页面input输入字段数据判断,说白了就是前四个测试为邮箱地址丶用户名丶密码丶验证码的分别输入错误的数据进行错误测试,最后一个就是测试是否注册成功;在测试case中当返回的email_error丶username_error丶password_error以及captcha_error的值为为True时表示通过调用的get_error_msg方法获取注册页面的错误信息获取不到则返回的是None,即在register_business模块方法中表示错误信息验证不成功返回True,那么在first_case模块中的测试case中则打印出"注册成功了,此条case执行失败",因为当注册页面没有错误提示信息元素值时,说明输入的数据格式是正确的,反之则打印出"注册失败了,此条case执行成功"
7.po模型之流程梳理完成注册页面常见case调试
- 在启动文件first_case模块中编写运行代码实例化FirstCase类,并调用测试方法,进行测试
- 运行first_case模块,查看测试效果
- 根据测试效果,可以看到在执行到第二个case时,则没有继续往下执行,原因是当执行第一条case时也就是test_register_email_error方法,该方法是判断页面中是否存在邮箱地址错误的元素,当传递"xxx"邮箱地址时,肯定会出现错误提示,所以程序继续往下执行没有报错,但是当执行第二条case时也就是test_register_username_error方法,在当前页面上继续输入注册数据,本来该方法测试的是错误的用户名所以传递的是"lao",很明显会出现用户名的错误提示,重点但是页面此时的注册页面的输入框数据并没有清空,所以导致注册页面上用户名一栏的数据为"laowanglao",即就是第一个case传递的name+第二个case传递的name,此时的用户名长度大于4,所以此刻的注册页面用户名错误提示信息的元素找不到,所以在调用get_error_msg方法里代码时传递的形参info的值为email_error即调用get_user_email_error_element方法,此方法的核心就是调用get_element此时出现异常返回None,那么回到get_error_msg方法中则调用text方法时报错因为None类型不存在任何方法,则在Pycharm控制台提示以下错误,要解决此错误那么则需要在每次点击注册后,需要将input框中的数据进行清空,但是这样做需要重新去定位元素,还有一种方法则是使用unittest测试模块运行代码,这个在后面会使用到来解决此报错
转载:https://blog.csdn.net/qq_41782425/article/details/94022561