Selenium学习笔记
selenium webdriver是业界公认ui自动化测试的标准,其封装的api可以对浏览器的任何地方进行操作
selenium2.0和selenium3.0的区别?
3.0任何浏览器的厂商都支持selenium,他们只要给予驱动就可以了,2.0只支持火狐和谷歌
webdriver工作原理?
通过webdriver创建一个浏览器服务,remote server(底层服务).启动脚本后会通过驱动打开浏览器,并绑定端口,不同浏览器端口不同
client端创建一个session来请求rmote server并发送restful请求,server解析后,完成代码的操作返回结果
如何定位html中的元素?
1.查看并分析html中所需定位的元素
2.找到对于当前页面来说唯一的属性
css selector与xpath区别?
其有着不同的定位方式,择优选择最佳的定位方式
xpath可以通过角标定位到一些css selector定位不到的元素
css selector基于html,能快速取到值,xpath底层要从xml转换成html对代码执行效率会受到影响,还依赖转化的准确度
xpath定位 xpath是xml的路径语言
/html/body/div/div/div/ul/li/a[@href="/xpath/xpath_syntax.asp"] 从祖先html开始查找定位元素,可以不用写角标 注意:一个/表示其子元素查找,//表示模糊匹配查找
//* 获取页面所有元素
//*[@id='xxxx'] @表示以id属性定位
//input[@id='xxx'] input表示以input标签名进行定位
//input[1] 如果出现不唯一的请求可以通过角标的形式取,注意角标从1开始
//input[1]/input[1] 层级定位方式,/表示当前层级内
//input[@id='xxx' and @class='xxx'] #逻辑定位方法,通过多种属性确立唯一
xpath(定位方法尽量少用层级定位,如果修改了层级位置会导入所有定位都失效,以属性定位为主)
css selector定位 html的css选择器标签定位
#i1 表示查找id属性为i1的元素
.i1 表示查找class属性为i1的属性
[name='xxx'] 表示查找name属性定位
input[name='xxx'] 可以通过标签名进行检索来缩小范围
input#name 查找input标签中id为name的元素
input[name='xxx'][id='xxx'][class='xxx'] input标签下多属性确立唯一
input>input[id='xxx'] >表示递进一层
input[name^='xxx'] ^支持前者模糊匹配
input[name$='xxx'] $支持后者模糊匹配
input[name*='xxx'] *表示包含,只要包含字段中的内容都可能会被匹配上
css selector不支持角标取值,所以我们要灵活运用xpath和css selector结合
由于css是html原始支持,还可以支持很多定位方法,以上一些我们在日常通常都可以用了,如进一步学习可以参考
http://www.w3school.com.cn/cssref/css_selectors.asp
selenium webdriver api-代码定位,基础操作
from selenium import webdriver # 驱动程序,用chrome,当然还可以用firefox,ie驱动 driver = webdriver.Chrome() # 获取网址 driver.get("http://www.baidu.com") # 设置页面宽长
driver.get_window_size()# 获取浏览器的大小 driver.set_window_size(400, 800)# 定义指定页面长宽 driver.maximize_window()#最大页面长宽 # 截图
driver.get_screenshot_as_file('xx.jpg')# 在当前脚本的同一级目录生成浏览器截屏的图片文件(其他底层还有三个截图api) # 八种单数定位方式(都需要确立唯一) driver.find_element_by_name() #通过name属性定位 driver.find_element_by_id() #通过id属性定位 driver.find_element_by_class_name() #通过class属性定位 driver.find_element_by_link_text("") #文案定位 driver.find_element_by_partial_link_text() #包含文案定位 driver.find_element_by_css_selector() #css selector定位 driver.find_element_by_tag_name() #标签名定位,如果有多个,获取的是html页面中第一个 driver.find_element_by_xpath(".//*[@id='kw']").clear() #xpath定位
# 八种复数定位方法
(不常用,单数的element加s就是复数,所有复数形式都返回一个列表,列表顺序按html从上到下,如果元素下还有子元素,可以通过元素进行再次定位)
# 其他两种定位
driver.find_element('id','i1') #单数形式,参数id表示通过id定位,i1表示元素值为i1进行定位
driver.find_elemnets('id','i1') #复数形式,返回列表
# 提交表单 driver.find_element_by_xpath(".//[@id='kw']").send_keys("selenium") driver.find_element_by_xpath(".//*[@id='kw']").submit() # 控制浏览器前进后退 driver.back() driver.forward() # 刷新页面 driver.refresh() # 浏览器关闭 driver.close() # 关闭一个页面也叫关闭一个tag,当页面只有一个tag的时候就直接关闭浏览器了 driver.quit() # 退出驱动也就是关闭浏览器
等待,操作浏览器,悬浮
from selenium import webdriver from selenium.webdriver.common.action_chains import ActionChains # 引入actionchains类 from selenium.webdriver.common.keys import Keysfrom selenium.common.exceptions import NoSuchElementException from time import ctime from selenium.webdriver.support.select import Select import time browser = webdriver.Chrome() # 打开网页驱动 #等待 一般等待分为三种,系统等待,隐士等待,显示等待
# 隐式等待10s
"""
implicitly_wait():隐式等待
当使用了隐士等待执行测试的时候,如果 WebDriver没有在 DOM中找到元素,将继续等待,超出设定时间后则抛出找不到元素的异常
换句话说,当查找元素或元素并没有立即出现的时候,隐式等待将等待一段时间再查找 DOM,默认的时间是0
一旦设置了隐式等待,则它存在整个 WebDriver 对象实例的声明周期中,隐式的等到会让一个正常响应的应用的测试变慢,
它将会在寻找每个元素的时候都进行等待,这样会增加整个测试执行的时间,所以在ui自动化实现比较鸡肋
"""
browser.implicitly_wait(10)
# 显示等待 ↓
'''
显示等待 ==>显示等待为selenium的核心,用好它能增加自动化的执行速度,提高效率
自设置了显示等待,在设置后到指定设置时间内,会按设置的步长等待,直到找到元素或超时
'''
browser.get("https://www.baidu.com") # 打开网址 print("设置浏览器宽1200、高1400显示") browser.set_window_size(1200, 1400)
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By
element = WebDriverWait(browser, 5, 0.5).until( EC.presence_of_element_located((By.ID, "kw")) )
#browser, 5, 0.5分别表示对象,超时时间,步长
#By.ID,"kw"分别表示通过id属性,定位的值
# 系统等待 ↓
'''
time.sleep(5)
系统等待用在测试调试阶段
''' time.sleep(2)
title = browser.title # title:用于获得当前页面的标题。 print(title) # 打印当前页面的title now_url = browser.current_url # 打印当前页面URL # current_url:用户获得当前页面的URL。 print(now_url) size = browser.find_element_by_id("kw").size # 找到输入框的页面属性 print(size) text = browser.find_element_by_id("kw").text # 获取搜索条目的文本信息 print(text) attribute = browser.find_element_by_id("kw").get_attribute('type') # 返回元素属性值 print(attribute) result = browser.find_element_by_id("kw").is_displayed() # 查看是否可见 print(result) browser.find_element_by_id("kw").clear() # 清除内容 # 如果超出10s抛出异常 try: print(ctime()) search_test = browser.find_element_by_id("kw").send_keys("seleniuma") # 输入seleniuma time.sleep(2) except NoSuchElementException as e: print(e) finally: print(ctime()) # 键盘按键 browser.find_element_by_id("kw").send_keys(Keys.BACK_SPACE) browser.find_element_by_id("su").send_keys(Keys.ENTER) time.sleep(2) browser.refresh() # 刷新 time.sleep(2) browser.find_element_by_id("kw").clear() search_test2 = browser.find_element_by_id("kw").send_keys("webdriver") # 输入webdriver time.sleep(2) browser.find_element_by_id('su') # 提交表单 # 鼠标悬浮 adove = browser.find_element_by_class_name("pf") # 找到adove ActionChains(browser).move_to_element(adove).perform() # 方法 :定位到执行元素鼠标悬停操作 browser.find_element_by_class_name("setpref").click() # 找到下拉条中元素进行点击操作,click:点击事件 time.sleep(2) # 悬停下拉框+显示条数 # search03 = browser.find_element_by_link_text("设置") # ActionChains(browser).move_to_element(search03).perform() # time.sleep(2) # 搜索结果显示条数 sel = browser.find_element_by_xpath("//select[@id='nr']") Select(sel).select_by_value('50') # 显示50条 time.sleep(5) browser.find_element_by_link_text("保存设置").click() time.sleep(2) # 返回原来的样子 browser.switch_to.alert.accept() time.sleep(2) search03 = browser.find_element_by_link_text("设置") ActionChains(browser).move_to_element(search03).perform() time.sleep(2) av = browser.find_element_by_link_text("搜索设置") av.click() time.sleep(2) browser.find_element_by_id("nr").click() time.sleep(2) # 搜索结果显示条数 sel = browser.find_element_by_xpath("//select[@id='nr']") Select(sel).select_by_value('10') # 显示10条 # …… time.sleep(2) browser.find_element_by_link_text("保存设置").click() time.sleep(2) browser.close()
等待扩展
WebDriverWait参数
def __init__(self, driver, timeout, poll_frequency=POLL_FREQUENCY, ignored_exceptions=None): pass #driver:类的实例 #timeout:超时时间 poll_frequency=POLL_FREQUENC:#调用until或until_not中的方法的间隔时间,默认值0.5秒 ignored_exceptions=None:#忽略的异常,如果在调用until或until_not的过程中抛出这个元组中的异常, 则不中断代码,继续等待,如果抛出的是这个元组外的异常,则中断代码,抛出异常。默认只有NoSuchElementException #以上是构造函数,下面介绍方法,总共两个until和until_not def until_not(self, method, message=''):#当某元素消失或什么条件不成立则继续执行 pass def until(self, method, message=''):#当某元素出现或什么条件成立则继续执行 pass #method:在等待期间,每隔一段时间调用这个传入的方法,直到返回值不是False #message: 如果超时,抛出TimeoutException,将message传入异常
等待操作
from selenium import webdriver from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC driver = webdriver.Chrome() driver.get('http://www.baidu.com') driver.maximize_window() # 判断某个元素进入dom树中,可以是不可见的元素,找到返回WebElement对象属性 WebDriverWait(driver, 10, 1).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#kw'))) # 判断某组元素进入dom树中,可以是不可见的元素,找到返回WebElement对象列表 WebDriverWait(driver, 10, 1).until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, '#kw'))) # 判断title是否正确,返回布尔值 WebDriverWait(driver, 10, 1).until(EC.title_is(u"百度一下,你就知道")) # 包含判断title是否正确,返回布尔值 WebDriverWait(driver, 10, 1).until(EC.title_contains('百度')) # 判断某个元素是否被加到了dom树里,并不代表该元素一定可见,如果定位到就返回WebElement WebDriverWait(driver, 10, 1).until(EC.presence_of_element_located((By.ID, 'kw'))) # 判断是否至少有1个元素存在于dom树中,如果定位到就返回列表 WebDriverWait(driver, 10, 1).until(EC.visibility_of_all_elements_located((By.ID, 'kw'))) # 判断某个元素是否可见 WebDriverWait(driver, 10, 1).until(EC.visibility_of(driver.find_element(by=By.ID, value='kw'))) # 判断某个元素是否别添加到dom里并可见,可见代表元素可显示且宽和高都大于0 WebDriverWait(driver, 10, 1).until(EC.visibility_of_element_located((By.ID, 'kw'))) # 判断某个元素是否包含预期字符串,返回布尔值 WebDriverWait(driver, 10, 1).until(EC.text_to_be_present_in_element((By.XPATH, "//*[@id='u1']/a[8]"), u'设置')) # 判断指定元素的属性值中是否包含预期字符串,返回布尔值 WebDriverWait(driver, 10, 1).until(EC.text_to_be_present_in_element_value((By.CSS_SELECTOR, '#su'), '百度一下')) # 判断该frame是否可以switch进,如果可以返回True并且switch进去,否则返回False WebDriverWait(driver,10,1).until(EC.frame_to_be_available_and_switch_to_it()) # 判断某个元素中是否可见并且是enable的,代表可点击 WebDriverWait(driver, 10, 1).until(EC.element_to_be_clickable((By.XPATH, "//*[@id='u1']/a[8]"))).click() # 等待某个元素从dom树中移除WebDriverWait(driver,10,1).until(EC.staleness_of(driver.find_element(By.ID,'su'))) # 判断某个元素是否被选中了,一般用在下拉列表 WebDriverWait(driver, 10).until(EC.element_to_be_selected(driver.find_element(By.XPATH, "//*[@id='nr']/option[1]"))) # 判断某个元素的选中状态是否符合预期 WebDriverWait(driver, 10).until( EC.element_selection_state_to_be(driver.find_element(By.XPATH, "//*[@id='nr']/option[1]"), True)) # 判断某个元素的选中状态是否符合预期 WebDriverWait(driver, 10).until(EC.element_located_selection_state_to_be((By.XPATH, "//*[@id='nr']/option[1]"), True)) # 判断页面上是否存在alert,如果有就切换到alert并返回alert的内容 instance = WebDriverWait(driver, 10).until(EC.alert_is_present())
文件上传,cookie,滚动条,js执行
from selenium import webdriver import time driver = webdriver.Chrome() driver.get('http://sahitest.com/demo/php/fileUpload.htm') driver.find_element_by_name("file").send_keys("C:\\Users\\admin\Desktop\\test.txt")#选择本地文件上传 driver.find_element_by_name("submit").click() driver.quit() driver = webdriver.Chrome() driver.set_window_size(1920,1080) driver.get("http://www.youdao.com") # 获得cookie信息 cookie = driver.get_cookies() # 将获得cookie的信息打印 print(cookie) print("向cookie的name 和value中添加会话信息") driver.add_cookie({'name': 'key-aaaaaaa', 'value': 'value-bbbbbb'}) # 遍历cookies中的name 和value信息并打印,当然还有上面添加的信息 for cookie in driver.get_cookies(): print("%s -> %s" % (cookie['name'], cookie['value'])) driver.get("http://www.testclass.net/selenium_python/javascript/") #滚动条操作 js = "window.scrollTo(100,700);" #scrollTo(x,y)
#执行js代码 driver.execute_script(js) time.sleep(3) driver.quit()
警告框处理
from selenium import webdriver from selenium.webdriver.common.action_chains import ActionChains import time browser = webdriver.Firefox() browser.implicitly_wait(10) browser.get("https://www.baidu.com") time.sleep(2) link = browser.find_element_by_link_text("设置") ActionChains(browser).move_to_element(link).perform() browser.find_element_by_link_text("搜索设置").click() time.sleep(2) browser.find_element_by_link_text("保存设置").click() time.sleep(2) print (browser.switch_to_alert().text) #先打印再接受警告框 ar = browser.switch_to.alert.accept() #点击确定警告框 dis = browser.switch_to.alert.dismiss() #点击取消警告框
browser.quit()
多窗口切换
from selenium import webdriver import time driver = webdriver.Chrome() driver.implicitly_wait(10) driver.get("http://www.baidu.com") # 获取当前对象的窗口句柄 sreach_windows = driver.current_window_handle driver.find_element_by_link_text('登录').click() driver.find_element_by_link_text("立即注册").click() # 获得当前所有打开的窗口的句柄,以列表形式返回 all_handles = driver.window_handles # 进入注册窗口 for handle in all_handles: if handle != sreach_windows:#遍历如果不属于之前的那个页面就执行下面操作 driver.switch_to.window(handle)#跳转到另一个页面 print('now register window!') driver.find_element_by_name("userName").send_keys('这个是用户名') driver.find_element_by_id('TANGRAM__PSP_3__phone').send_keys('123456') time.sleep(2)
# 以上过于复杂,可以参考以下两行
last_handle = driver.windows_handles[-1]# 表示拿到列表最后一个值,也就是最后一个页面的窗口句柄
driver.switch_to.window(last_handle)# 让浏览器跳到刚刚指定页面
# 两个页面之间tab切换 driver.switch_to.window(all_handles[0]) time.sleep(5) driver.switch_to.window(all_handles[1]) time.sleep(5) driver.switch_to.window(all_handles[0]) driver.quit()
判断checkbox勾选
off = driver.find_element_by_id('xxx')# 定位到checkbox勾选元素 print(on.is_selected())# 判断是否勾选,返回布尔值
iframe定位
driver.switch_to.frame('xxx')# 切换进入到当前html下的frame层 driver.switch_to.parent_frame()# 返回上一层 driver.switch_to.default_content()# 直接返回最外层
拖拽指令
from selenium.webdriver.common.action_chains import ActionChains s1 = driver.find_element_by_id('xxx')# s1为推拽起始元素 t1 = driver.find_element_by_class_name('xxx')# t1位推拽目标元素 ActionChains(driver).drag_and_drop(s1,t1).perform()
UI自动化框架(web)
我们为什么要做ui自动化测试?
项目基于稳定的前提,由于老功能在原先基础要增加新功能点,为了避免在旧业务上有过多资源来回归测试,可以用ui自动化来对其业务进行回归测试,不适用与新业务
我们为什么要做ui自动化框架?
目前互联网公司ui自动化框架现状:
1.运行不稳定
2.维护麻烦,源码修改后需要重新定位
3.自动化测试用例与页面数据脚本写在一起,排查时业务混乱
自动化框架解决思路:
1.显示等待框架封装
2.PO思想(page object) 每个页面为一个类class,每个功能为一个函数def,web端和app端都以这种思想为主
3.自动化测试用例与页面数据脚本分离
所以可以基于selenium webdriver原生代码,unittest单元测试api,报告,截图,日志和现状结合实现的框架能很好的帮助我们做好框架
框架中怎么为业务逻辑做断言?
1.判断元素消失,代表业务成功
2.判断另一个元素出现,且该元素一定是唯一的
有哪些框架值得我们使用?
我个人推荐虫师大大的框架,pyse,poium,还有seleniumbase等都是优秀的改良版测试框架,内置增加了api足够我们使用了
版权声明:本文原创发表于 博客园,作者为 RainBol 本文欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则视为侵权。