1、介绍
自动化测试概念:让程序代替人为去验证程序功能的过程,本质上就是用来让将人的精力从重复性的工作中解放出来
优点:
·减少人工的重复性劳动
·执行速度快
·可以重复利用
·生成测试报告,有利于决策
缺点:
·对测试人员的技能要求高
应用场景:
·单元测试
·回归测试:项目在发新版本之后对项目之前的功能进行验证
·压力测试:可以理解多用户同时去操作软件,统计软件服务器处理多用户请求的能力
·兼容性测试:不同浏览器(IE、Firefox、Chrome)等等
主流测试工具:
·Selenium(开源)【本阶段学习】: Selenium是开源的web自动测试工具,免费,主要做功能测试。
·Loadrunner(收费、Web、性能): Loadrunner是商业性能测试工具,收费,功能强大,适合做复杂场景的性能测试
·Robot framework: Robot Framework是一个基于Python可扩展地(关键字驱动)的测试自动化框架;
2、Web自动化:Selenium
2.1、Selenium介绍
·Selenium是一个用于Web应用程序测试的工具,可以直接调用浏览器,它支持所有主流的浏览器。
·最初是为网站自动化测试而开发的,但却被很多爬虫爱好者发扬光大
·官网:https://www.selenium.dev/
特点:
1) 开源软件:源代码开放可以根据需要来增加工具的某些功能
2) 跨平台:linux 、windows 、mac
3) 核心功能:就是可以在多个浏览器上进行自动化测试
4) 多语言:Java、Python、C#、JavaScript、Ruby等
6) 功能强大:能够实现类似商业工具的大部分功能,因为开源性,可实现定制化功能
2.1.1、WebDriver
Webdriver 是一种用于控制浏览器的程序,不同的浏览器有不同的 webdriver
·Chrome (ChromeDriver)【本阶段学习使用】
·IE(InternetExplorerDriver)
·Opera(OperaDriver)
·Firefox (FirefoxDriver)
·safari(SafariDriver)
·HtmlUnit (HtmlUnit Driver)
webdriver 提供了对外的接口,其他程序通过这些接口控制 webdriver 与浏览器的交互。例如:我们可以写 python 程序来调用 webdriver 的接口。实际上从其他程序的角度看,webdriver 就是充当了和浏览器交互的一个桥梁。
说明:
·Firefox、Chrome:对元素定位和操作有良好的支持,同时对JavaScript支持也非常好。
·IE: 只能在windows平台运行,所有浏览器中运行速度最慢
·HtmlUnit:无GUI(界面)运行,运行速度最快;
2.1.2、Selenium 执行过程
python代码--> selenium 封装的 python 接口--> WebDriver 提供接口--> 浏览器
2.1.3、环境搭建
·基于python环境搭建
pip install selenium -i https://pypi.tuna.tsinghua.edu.cn/simple
注意: 在安装selenium时,前提是Python3.5以上版本安装完毕且能正常运行
·安装适配浏览器版本的webdriver驱动
国内不能直接访问Chrome官网,可以在ChromeDriver仓库中下载或者https://npm.taobao.org/mirrors/chromedriver
2.2、元素定位
2.2.1、WebDriver元素定位的简单方式
selenium页面元素定位的方法,是在selenium中可以通过多种方式来定位标签,返回标签元素对象:
·通过 id 属性定位 : find_element_by_id
·通过 name 属性定位 : find_element_by_name
·通过 class 属性定位 : find_element_by_class_name
·通过标签名定位 : find_element_by_tag_name
·通过内容定位 a 标签(绝对匹配) : find_element_by_link_text
·通过内容定位 a 标签(模糊匹配) : find_element_by_partial_link_text
from selenium.webdriverimportChromeimporttraceback# 通过指定chromedriver的路径来实例化driver对象driver = Chrome(executable_path='./chromedriver')# 控制浏览器访问url地址# file://{本地文件绝对路径}driver.get('file:///home/python/code/unit_testing/selenium_code/test.html')# 打开本地 html 文件try:print(driver.find_element_by_id('username'))# 通过 id 属性定位driver.find_element_by_name('password2')# 通过 name 属性定位driver.find_element_by_class_name('input-password')# 通过 class 属性定位driver.find_element_by_tag_name('ul')# 通过标签名定位driver.find_element_by_link_text('标签')# 通过内容定位 a 标签(绝对匹配)driver.find_element_by_partial_link_text('Optimization')# 通过内容定位 a 标签(模糊匹配)except Exception:print(traceback.format_exc()) finally:# 退出浏览器driver.quit() |
Chrome(executable_path='./chromedriver')中executable参数指定的是下载好的chromedriver文件的路径
要在代码中尽量保证driver.quit()能够成功执行,进而关闭driver退出模拟浏览器;不然将在操作系统中残留进程,对系统造成不必要的压力
2.2.2、xpath方式
·XPath即为XML Path的简称,它是一种用来确定XML/HTML文档中某部分位置的语言
·XPath文档:http://www.w3school.com.cn/xpath/index.asp
1、xpath路径
html,xml 中的元素可以嵌套其他元素,但是根元素只有一个。我们可以这种嵌套关系看成路径。路径分绝对路径和相对路径:
·绝对路径:从根元素到指定元素之间所有经过元素层级路径,绝对路径以 "/" 开始,例如: input 的绝对路径是: /html/body/form/input
·相对路径:从任何元素开始到该元素的路径,相对路径以 "//" 开始,例如: 用户名输入框标签的相对路径有: //form/input,//body/form/input
2、xpath定位
xpath 定位是结合路径来进行定位的,分为绝对定位和相对定位。定位过程中还可以结合元素的属性值。
定位方法:find_element_by_xpath
·纯路径定位
绝对定位:find_element_by_xpath("/html/body/form/input")
相对定位:find_element_by_xpath("//div/ul/li/a")
·结合属性定位
单个属性:find_element_by_xpath("//input[@type='text']")
多个属性:driver.find_element_by_xpath("//input[@type='text' and @name='username']")
·选择上一级元素
find_element_by_xpath("//input/.."):返回的是 form 元素
·满足条件的多个元素,选择其中的一个
driver.find_element_by_xpath("//ul/li[1]"):有多个 li 满足条件,选择其中一个,通过下标来完成,下标从 1 开始
driver.find_element_by_xpath("//ul/li[last()]"):选择最后一个
driver.find_element_by_xpath("//ul/li[last()-1]"):选择倒数第二个
from selenium.webdriverimportChromeimporttraceback# 通过指定chromedriver的路径来实例化driver对象driver = Chrome(executable_path='./chromedriver')# 控制浏览器访问url地址# file://{本地文件绝对路径}driver.get('file:///home/python/code/unit_testing/selenium_code/test.html')# 打开本地 html 文件try:print(driver.find_element_by_xpath('/html/body/form/input'))print(driver.find_element_by_xpath('//div/ul/li'))print(driver.find_element_by_xpath('//form/input[@name="password"]'))print(driver.find_element_by_xpath('//form/input[@name="password2" and @type="text"]'))print(driver.find_element_by_xpath('//li/..'))print(driver.find_element_by_xpath('//ul/li[1]'))print(driver.find_element_by_xpath('//ul/li[last()]'))print(driver.find_element_by_xpath('//ul/li[last()-1]')) except Exception:print(traceback.format_exc()) finally:# 退出浏览器driver.quit() |
2.2.3、CSS方式
定位方法:find_element_by_css_selector
在selenium中极力推荐CSS定位,因为它比XPath定位速度要快
CSS 选择器语法非常强大,在这里我们只学习在测试中常用的几个
driver.find_element_by_css_selector('#username') # 通过 iddriver.find_element_by_css_selector('.input-text')# 通过 classdriver.find_element_by_css_selector('form')# 通过标签名driver.find_element_by_css_selector('input[type="password"]')# 通过标签属性driver.find_element_by_css_selector('div>ul')# 通过父子元素 |
2.2.4、查询多个元素
·通过 id 属性定位 : find_elements_by_id
·通过 name 属性定位 : find_elements_by_name
·通过 class 属性定位 : find_elements_by_class_name
·通过标签名定位 : find_elements_by_tag_name
·通过内容定位 a 标签(绝对匹配) : find_elements_by_link_text
·通过内容定位 a 标签(模糊匹配) : find_elements_by_partial_link_text
·通过 xpath : find_elements_by_xpath
·通过 CSS 选择器: find_elements_by_css_selector
和选择单个元素的字面区别就是多了个 s。
区别:调用这类方法,会返回一个列表,没有找到元素则返回空列表,查找单个元素的方法会在找不到元素时抛出 NoSuchElementException 异常
2.3、元素等待
概念:WebDriver定位页面元素时如果未找到,会在指定时间内一直等待的过程。
元素等待的必要性:
当使用脚本定位元素或去验证程序的运行状态时,由于资源受限或网络延迟引起的响应速度太慢,导致要定位的元素还未加载到页面。
例如:页面是通过 Ajax 发起请求,但是网络有延迟,提交按钮点击完后,页面等待服务器的返回结果来更新页面,那么在这期间,测试代码是不能够直接去查找预期的元素的。
元素等待类型:
显式等待
隐式等待
2.3.1、显式等待
概念:使 WebDriver 等待某个条件成立,否则在达到最大时长时抛出超时异常(TimeoutException)
1、WebDriverWait 类
from selenium.webdriver.support.wait import WebDriverWait |
参数:
driver: webdriver对象
timeout: 等待多长时间
poll_frequency: 每次执行失败时休眠多长时间
2、调用方法
WebDriverWait.util(method, message=''): |
参数说明:
method 函数,这个函数必须定义一个参数,接受 driver 对象。例如: def contain_title(driver)
message 如果等待失败,message 作为消息抛出
返回值:如果找到,返回找到元素的对象
from selenium.webdriverimportChromeimporttracebackfrom selenium.webdriver.support.waitimportWebDriverWait driver = Chrome('./chromedriver')# 3. 打开网址# file://{本地网址绝对路径}driver.get('http://www.baidu.com') try:# time.sleep(2)# 1. 指定最长的等待时间,指定检测until函数的时间# driver对象,最长等待5s, 如果没有找到,每隔0.5s, 检测until()指定的函数,如果5s都没有找到,抛出异常wait_driver = WebDriverWait(driver, 5, 0.5)# WebDriverWait.until(), 需要传入一个函数名, 这个函数,参数为Chrome类型el = wait_driver.until(lambda temp: temp.find_element_by_tag_name('html'))print(el) except Exception as e:# print(e) # 只打印错误信息print(traceback.format_exc())# 有错误路径显示finally:# 不管有没有异常,都保证driver可以关闭driver.quit() |
2.3.2、隐式等待
如果定位某一元素定位失败,那么就会触发隐式等待有效时长,如果在指定时长内加载完毕,则继续执行,否则抛出 NoSuchElementException 异常。
调用方法
driver.implicitly_wait(10)
from selenium.webdriverimportChrome from selenium.webdriver.support.waitimportWebDriverWaitimporttracebackimporttime# 通过指定chromedriver的路径来实例化driver对象driver = Chrome(executable_path='./chromedriver')# 控制浏览器访问url地址driver.get('https://www.baidu.com') driver.implicitly_wait(5)# 隐式等待try: driver.find_element_by_id('kw') except Exception as e:print('type = ', type(e))# print(traceback.format_exc())finally:# 退出浏览器driver.quit() |
2.4、浏览器常用属性和方法
2.4.1、属性
driver.name:当前浏览器的名字
driver.title:当前网页的标题
driver.current_url:当前网页的
url driver.page_source:当前网页的源码
2.4.2、方法
driver.close()# 关闭当前窗口driver.quit()# 关闭浏览器# 历史driver.back()# 历史后退driver.forward()# 历史前进# 刷新页面driver.refresh()# 刷新页面# 窗口大小位置driver.maximize_window()# 浏览器最大化driver.fullscreen_window()# 浏览器全屏driver.minimize_window()# 浏览器最小化 |
2.4.3、窗口截图
说明:自动化脚本是由程序去执行的,因此有时候打印的错误信息并不是十分明确。如果在执行出错的时候对当前窗口截图保存,那么通过图片就可以非常直观地看到出错的原因。
在WebDriver类库中,提供了截图方法,我们只需要调用:
driver.get_screenshot_as_file(文件路径.png)
from selenium.webdriverimportChrome driver = Chrome('./chromedriver')# 3. 打开网址# file://{本地网址绝对路径}driver.get('https://www.baidu.com') driver.maximize_window() driver.implicitly_wait(2)# 截图保存driver.get_screenshot_as_file('error.png') driver.quit() |
2.4.4、执行 javascript 代码
有时候我们需要在特定页面中执行 javascript 脚本,通过 driver.execute_script(js代码)
from selenium.webdriverimportChrome from selenium.webdriver.support.waitimportWebDriverWaitimporttracebackimporttime# 通过指定chromedriver的路径来实例化driver对象driver = Chrome('./chromedriver')# 控制浏览器访问url地址driver.get('https://www.baidu.com')# driver.maximize_window() # 最大化窗口# 执行js代码driver.execute_script("alert('hello world')")time.sleep(3)# 延时3s# 退出浏览器driver.quit() |
2.4.5、cookie
driver.get_cookies():获取所有的 cookie
driver.get_cookie(name):获取指定的 cookie
driver.delete_cookie(name):删除指定的 cookie
driver.delete_all_cookies():删除所有的 cookie
driver.add_cookie(cookie_dict):添加一个 cookie cookie_dict {"name":"xxx","value":"xxx"} 可选的 key 是 "path", "domain", "secure", "expiry"
2.5、元素常用属性和方法
2.5.1、模拟鼠标单击
点击元素,通过调用 click() 方法
2.5.2、输入框元素填充数据和清空
如果是输入框元素,可以通过 send_keys(字符串) 将该字符串填充到输入框中,通过 clear() 清空输入框
from selenium.webdriverimportChromeimporttracebackimporttime# 通过指定chromedriver的路径来实例化driver对象driver = Chrome(executable_path='./chromedriver')# 控制浏览器访问url地址# file://{本地文件绝对路径}driver.get('file:///home/python/code/unit_testing/selenium_code/test.html')# 打开本地 html 文件try: el = driver.find_element_by_id('username')time.sleep(1)# 填充数据el.send_keys("我的用户名")time.sleep(2)# 清空数据el.clear()time.sleep(1) except Exception:print(traceback.format_exc()) finally:# 退出浏览器driver.quit() |
2.5.3、获取标签属性
html 元素有一些属性,这些属性通过 get_attribute(属性名) 来获取
2.5.4、行为链
WebDriver 中将元素的点击和发送表单数抽象位行为链,行为链中可以包含一个以上的动过,常见行为如下:
鼠标单击
鼠标右击
鼠标双击
鼠标拖动
鼠标指针移动
按键按下
按键松开
1、ActionChains的使用
from selenium.webdriver.common.action_chains import ActionChains |
使用步骤:
实例化 ActionChains
通过方法添加要执行的行为,可以添加多个,并且可以链式添加,这一步是保存要执行的行为,并不会执行。例如
调用 Actionchains 对象的 perform() 执行上一步添加的行为
2、方法参考
reset_actions(self) : 清空行为链
click(self, on_element=None): 鼠标点击
click_and_hold(self, on_element=None) : 鼠标按下
release(self, on_element=None) : 松开鼠标
context_click(self, on_element=None) : 鼠标右击
double_click(self, on_element=None) : 鼠标双击
drag_and_drop(self, source, target) : 拖动元素,source 被拖动元素,target 表示被拖动到那个元素中
drag_and_drop_by_offset(self, source, xoffset, yoffset) : 拖动元素,给定x,y 轴偏移
key_down(self, value, element=None) : 按键按下
key_up(self, value, element=None) : 按键松开
move_by_offset(self, xoffset, yoffset) : 鼠标箭头移动,给定 x,y 轴偏移
move_to_element(self, to_element) : 鼠标移动到某个元素中心
move_to_element_with_offset(self, to_element, xoffset, yoffset) : 鼠标移动到元素内的 x,y 轴位置
send_keys(self, *keys_to_send): 发送多个按键,也可以是一个字符串
send_keys_to_element(self, element, *keys_to_send) :
2.6、窗口、frame、警告框
2.6.1、frame
frame:HTML页面中的一种框架,主要作用是在当前页面嵌套另一页面页面; (HTML语言中,<frame></iframe>标签为表单框架)
webdriver只能访问一个页面,默认是外层页面,如果要访问嵌套的页面,必须切换当前到嵌套页面中。
切换
driver.switch_to.frame(frame 元素)
driver.switch_to.default_content() 切换到外层页面
2.6.2、多窗口
说明:在HTML页面中,经常有a标签也就是超链接,这些链接在被执行时,有的会在新的窗口打开链接;
切换
说明:在WebDriver中封装了获取当前窗口句柄方法和获取所有窗口句柄的方法以及切换指定句柄窗口的方法;(句柄:英文handle,窗口的唯一识别码)
driver.switch_to.window(窗口句柄) |
2.6.3、警告框处理
说明:WebDriver中对处理警告框的操作,有专用的处理方法;
提示: HTML中常用的对话框有三种,处理的方法都一样
alert
confirm
prompt
1、调用方法
# 获取当前窗口的警告框
alert=driver.switch_to.alert
2、警告框处理方法
accept : 接受对话框选项
dismiss : 取消对话框选项
from seleniumimportwebdriverimporttimedriver = Chrome('./chromedriver') driver.get('http://www.baidu.com')# 打开一个警告框driver.execute_script("alert('hello')")# 切换到警告框alert = driver.switch_to.alert# 关闭警告框alert.dismiss() |
2.7、下拉框
说明:下拉框就是HTML中<select>元素;
2.7.1、Select类
from selenium.webdriver.support.select import Select
说明:Select 类是 WebDriver 为解决 select 标签定位诞生的,此类定位的是 select 标签。
使用步骤:
找到 select 元素
实例化 Select 对象
2.7.2、常用属性和方法
select.options# select 中所有 optionsselect.all_selected_options# 所有被选中的 optionselect.first_selected_option# 第一个被选中的 optionselect.select_by_value(value)# 通过 option 的值选中select.select_by_index(index)# 通过 option 的下标选中select.select_by_visible_text(text)# 通过 option 的可见文本选中select.deselect_all()# 全部不选中select.deselect_by_value(value)# 通过 option 的值取消选中select.deselect_by_index(index)# 通过 option 的下标取消选中select.deselect_by_visible_text(text)# 通过 option 的文本取消选中 |
2.8、无界面模式
2.8.1、Selenium无界面模式
绝大多数服务器是没有界面的,selenium控制谷歌浏览器也是存在无界面模式的,这一小节我们就来学习如何开启无界面模式(又称之为无头模式)
开启无界面模式的方法
·实例化配置对象
options = webdriver.ChromeOptions()
·配置对象添加开启无界面模式的命令
options.add_argument("--headless")
·配置对象添加禁用gpu的命令
options.add_argument("--disable-gpu")
·实例化带有配置对象的driver对象
driver = webdriver.Chrome('./chromedriver', options=options)
注意:macos中chrome浏览器59+版本,Linux中57+版本才能使用无界面模式!
from seleniumimportwebdriver options = webdriver.ChromeOptions()# 创建一个配置对象options.add_argument("--headless")# 开启无界面模式options.add_argument("--disable-gpu")# 禁用gpudriver = webdriver.Chrome('./chromedriver', options=options)# 实例化带有配置的driver对象driver.get('https://www.itcast.cn')print(driver.title) driver.quit() |
2.9、综合练习
使用selenium+unittest对美多v5.0项目(http://mp-meiduo-python.itheima.net)的登陆和登出功能进行自动化测试,并生成测试报告
2.9.1、目录结构
2.9.2、测试用例
importunittest from selenium.webdriverimportChrome from parameterizedimportparameterizedimporttimeTIME = 0.3classTestUser(unittest.TestCase):defsetUp(self) -> None:print('前置:创建Chrome对象') self.driver = Chrome('./drivers/chromedriver') self.driver.maximize_window()# 最大化self.driver.implicitly_wait(10)# 指定隐式等待的时间deftearDown(self) -> None:print('后置:退出driver') self.driver.quit() @parameterized.expand([('admin', 'admin'), ('mike', '1111111'), ('itcast', 'admin')])deftest_uesrs(self, username, pwd):print('测试用例,selenium操作')# 1. 打开网址self.driver.get('http://mp-meiduo-python.itheima.net/')# 2. 定位元素,元素操作(点击、输入)# 找到主页面登陆连接按钮,点击self.driver.find_element_by_link_text('登录').click()# 找用户名输入框,清空内容,输入用户名el = self.driver.find_element_by_name('username') el.clear()time.sleep(TIME) el.send_keys(username)time.sleep(TIME)# 找密码输入框,清空内容,输入用户名el = self.driver.find_element_by_name('pwd') el.clear()time.sleep(TIME) el.send_keys(pwd)time.sleep(TIME)# 找复选框el = self.driver.find_element_by_name('remembered')# el.is_selected() # 这个元素是否被选中,如果选中了,返回True, 否则,返回Falseprint(el.is_selected())ifel.is_selected():# 如果复选框是被选中的el.click()# 再点击一下,复选框由选中变成没有选中的状态# 3. 登陆操作# 找到登陆按钮,点击,如果用户名、秘密正确,切换到登陆后的页面self.driver.find_element_by_class_name('input_submit').click()time.sleep(TIME)# 4. 登陆操作的结果,断言# 登陆时,网址为:http://mp-meiduo-python.itheima.net/login/# 登陆成功后,网址切换为http://mp-meiduo-python.itheima.net/# 作了登陆操作后,只要当前网址为http://mp-meiduo-python.itheima.net/,说明登陆成功self.assertEqual(self.driver.current_url, 'http://mp-meiduo-python.itheima.net/', '登陆失败')# 登出# 1. 登陆成功后,才能登出# 2. 找登出按钮,点击self.driver.find_element_by_class_name('quit').click()# 3. 找成功退出后的变化规律# http://mp-meiduo-python.itheima.net/ 变为 http://mp-meiduo-python.itheima.net/login/self.assertEqual(self.driver.current_url, 'http://mp-meiduo-python.itheima.net/login/', '登出失败')time.sleep(TIME) |
2.9.3、main.py
importunittest from BeautifulReportimportBeautifulReportif__name__ == '__main__':# 1. 创建suite测试套件(容器),把当前目录下的test文件加入到容器suite = unittest.defaultTestLoader.discover('./')# 2. 根据suite创建runnerrunner = BeautifulReport(suite)# 3. runner启动测试报告runner.report('美多登陆登出测试', '测试报告名字.html', './reports') |
本文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理