前言:
此时朋友们对“pythonweb自动化测试”大体比较关怀,咱们都想要了解一些“pythonweb自动化测试”的相关知识。那么小编在网摘上收集了一些对于“pythonweb自动化测试””的相关知识,希望咱们能喜欢,朋友们快快来学习一下吧!1.selenium使用方法1.1操作浏览器
1、启动浏览器(实例化浏览器)
启动Chrome浏览器(驱动已放入path环境变量下)
driver = webdriver.Chrome()
指定驱动路径驱动Chrome 浏览器
# .\driver\chromedriver.exe 为驱动存放位置,可以是相对路径或者绝对路径driver = webdriver.Chrome(executable_path=r'.\driver\chromedriver.exe')
启动Firefox浏览器
driver=webdriver.Firefox() # 指定驱动路径 启动 driver=webdriver.Firefox(executable_path="..\driver\geckodriver.exe")
启动IE浏览器
driver=webdriver.Ie() # 指定驱动路径 启动driver=webdriver.Ie(executable_path=r".\driver\IEDriverServer.exe")
2、最大化浏览器
driver.maximize_window()
driver为实例化浏览器对象(下同)
3、设置浏览器大小
driver.set_window_size(480, 800) # width 400, height 800
4、打开网页
driver.get(';)
5、使用另外窗口打开网页
# 新开一个窗口,通过执行js来新开一个窗口js='window.open(";);'driver.execute_script(js)
6、控制浏览器前进、后退
driver.get(';) driver.get(';) # 在同一窗口重新打开一个网页driver.back() # 后退 到知乎driver.forward() # 前进 换回到163
7、获取网页标题
title =driver.title # 获取网页的title
获取到的title为页面源码head 标签中title中的文本信息
8、获取网页的URL
url=driver.current_url # 获取网页的URL
获取的url为当前浏览器地址栏中的url
9、刷新页面
driver.refresh()
10、获取浏览器窗口大小
size=driver.get_window_size()
返回为字典型 如:{'width': 1050, 'height': 840}
11、关闭浏览器
driver.close()
关闭的是当前浏览器窗口的页签,存在多个窗口时关闭当前的活动窗口
12、退出浏览器
driver.quit()
关闭整个浏览器,包括webdriver的进程也会退出
1.2获取元素对象
八种属性定位页面元素:
序号
类型
示例
1
id 定位
find_element(By.ID,"id值")
2
name 定位
find_element(By.NAME,"name值")
3
tag 定位
find_element(By.TAG_NAME,"id值")
4
class 定位
find_element(By.CLASS_NAME,"class值")
5
link_text 定位
find_element(By.LINK_TEXT,"文本值")
6
partial_link 定位
find_element(By.PARTIAL_LINK_TEXT,"文本模糊值")
7
XPath 定位
find_element(By.XPATH,"唯一路径标识")
8
CSS_selector 定位
find_element(By.CSS_SELECTOR,"各种组合") ,实际使用最多
webdriver中元素定位元素的简便方法:
driver.find_element_by_id('元素id属性') # ------ 最常用,简单driver.find_element_by_name('元素name属性') # ------ 最常用,简单driver.find_element_by_class_name('元素class属性') # ------ 易重复,看情况使用driver.find_element_by_tag_name('元素标签名') # ------ 最不靠谱driver.find_element_by_link_text('链接文本') # ------ 精确匹配链接 (<a> 标签中的文字)driver.find_element_by_partial_link_text(‘部分链接文本’) # ------ 模糊匹配链接driver.find_element_by_xpath() # ------ 最灵活,万能的灵药driver.find_element_by_css_selector() # ------ 没xpath灵活
1、id元素定位
<input id="query" class="sec-input" name="query" maxlength="100" autocomplete="off" type="text">
driver.find_element_by_id('query')driver.find_element(By.ID,'query')
2、name元素定位
<input id="query" class="sec-input" name="query" maxlength="100" autocomplete="off" type="text">
driver.find_element_by_name('query')driver.find_elemnet(By.NAME,'query')
3、class name元素定位
<input id="query" class="sec-input" name="query" maxlength="100" autocomplete="off" type="text">
driver.find_element_by_class_name('sec-input')driver.find_element(By.CLASS_NAME,'sec-input')
4、 tag name元素定位(最不靠谱)
<input id="query" class="sec-input" name="query" maxlength="100" autocomplete="off" type="text">
driver.find_element_by_tag_name('input')driver,find_element(By.TAG_NAME,'input')
5、 link_text元素定位
页面底部搜狗输入法连接
<i class="i1"></i>搜狗输入法
driver.find_element_by_link_text('搜狗输入法')driver.find_element(By.LINK_TEXT,'搜狗输入法')
注意:连接文本是<a></a>标签对之间的文本
6、 partial link text元素定位
<<i class="i1"></i>搜狗输入法
driver.find_element_by_partial_link_text('输入法')driver.find_element(By.PARTIAL_LINK_Text,'输入法')
7、 XPath元素定位(强大)
xpath 可以根据元素的父节点或者哥哥弟弟节点定位到元素。
driver.find_element_by_xpath(‘//form[@id="sf"]//input[@type="text"]’) # 上级节点定位下级子节点driver.find_element_by_xpath(‘//span[@class="enter-input"]/preceding-sibling::span/input’) # 通过节点的弟弟节点定位
注意:使用xpath最好不要使用工具获取,手写的可靠性更高
8、css元素定位
css定位元素比xpath块,id,name,class,tag name都是转换为css后定位元素。具体请看find_element方法的代码。
<input id="query" class="sec-input" name="query" maxlength="100" autocomplete="off" type="text">
driver.find_elements_by_css_selector(".sec-input") # .表示classdriver.find_elements_by_css_selector("#query") # #表示id1.3操作元素对象
一、元素的常用操作
element.click() # 单击元素;除隐藏元素外,所有元素都可单击
element.submit() # 提交表单;可通过form表单元素提交表单
element.clear() # 清除元素的内容;如果可以的话
element.send_keys(‘需要输入的内容’) # 模拟按键输入;只针对支持输入的元素
注意:send_keys() 输入的内容必须为字符串
搜狗查询实例:
from selenium import webdriverimport timedriver = webdriver.Chrome()driver.maximize_window() # 最大化driver.get(r';) # 打开网页driver.find_element_by_id('query').send_keys('selenium') # 搜索框输入seleniumtime.sleep(2) # 等待3秒driver.find_element_by_id('query').clear() # 清除搜索框内容time.sleep(2)driver.find_element_by_id('query').send_keys('selenium') # 重新输入内容driver.find_element_by_id('sf').submit() # 提交搜索框的表单# driver.find_element_by_id('stb').submit() # 提交按钮也可提交表单,单击按钮也可以time.sleep(2)driver.quit() # 关闭浏览器
注意:submit() 提交表单,可以是提交按钮,也可以是表单元素,也可以是输入框元素
二、元素的常用方法
element.location 返回元素的坐标字典(相对于网页左上角0,0开始)
element.text 获取元素的文本,页面上看得到的文本
element.get_attribute('属性名称') 获得元素的属性 强调“有”
element.get_property('属性名称') 获得元素的固有属性值 强调“专”
element.is_displayed() 返回元素的结果是否可见,有些元素肉眼可见,但是他是隐藏的
示例:
from selenium import webdriverimport timedriver = webdriver.Chrome()driver.maximize_window() # 最大化driver.get(r';) # 打开网页driver.find_element_by_id('query').send_keys('selenium') # 搜索框输入seleniumelement=driver.find_element_by_id('query')print('搜索框的内容为:',element.get_attribute('value'))print('搜索框的class属性:',element.get_attribute('class'))print('搜索框的type属性:',element.get_attribute('type'))print('搜索框的坐标位置:',element.location)print('搜索框是否可操作:',element.is_displayed())time.sleep(2)text = driver.find_element_by_class_name('erwm-box').text # 获取二位码的文本print('底部二维码的文本为:',text)time.sleep(2)driver.quit() # 关闭浏览器
1、element.location 获取元素的坐标位置
对于已加载到浏览器的底部元素,操作元素时现在chrome无法自动拖动滚动条,需要获取元素位置后,采用js拖动滚动条到相应位置采用操作元素。
2、element.text 获取元素的文本
<div class="erwm-box"> <span class="ewm"></span> <div class="erwx"> <p>搜狗搜索APP</p> <p class="p2">搜你所想</p> </div> </div>
如上,我们定位class="erwm-box"元素,获取到的文本是 [搜狗搜索APP 搜你所想] ,也就是界面上能看到的文字内容。输入框除外(输入框的值是存储在value属性中),只要是界面上的文本内容都可以获取。
多用于校验点。
3、element.get_attribute('属性名称') 获取对应的属性值,强调“有”
<input type="text" class="sec-input" name="query" id="query" maxlength="100" autocomplete="off">
如上搜索输入框的属性有type、class、name、id、maxlength、autocomplete;我都可以通过get_attribute()获取到他的值,因为他’有’。
value是特殊的属性,输入框,单项按钮,多选按钮多具有改属性。
4、element.get_property('属性名称') 获得元素的固有属性值,强调“专”
它与get_attribute() 差别,get_property()是获取元素的固有属性。
我们所有的元素都有特定固有属性,如id、type、value等。
当使用get_attribute()无法获取到属性的值时,可使用get_property()。
5、element.is_displayed() 判定改元素是否可见
当我们定位到了元素,但是无法操作时,可以看看他是否可见,不可见不一定就是在界面上消失了。
6、其他方法
element.size 元素的大小
element.is_enabled() 元素是否可用
element.is_selected() 元素是否被选中,用于检测复选框或单项按钮是否被勾选
1.4设置等待时间
一、time.sleep(seconds) 固定等待
import timetime.sleep(3) #等待3秒
time.sleep(seconds) seconds参数为整数,单位(秒)。
它是Python的time提供的休眠方法。
常用于短时间的等待,为了自动测试用例的执行效率固定等待的时间需要控制在3秒内。在用例中尽量少用固定等待。
二、智能隐性的等待implicitly_wait(回应超时等待)
driver.implicitly_wait(time_to_wait)
回应超时等待,隐性的,设置后对应的是全局,如查找元素。
driver.implicitly_wait(10) # 设置全局隐性等待时间,单位秒
每次driver执行 找不到元素都会等待设置的时间,它的值设置的过长对用例执行效率有很大的影响,必须在执行完成之后还原回来。driver.implicitly_wait() 要慎之又慎的使用。
driver对它的默认值为0,driver.implicitly_wait(0)能还原隐性等待的设置时间。
三、智能显性等待WebDriverWait
WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None)
参数说明:
driver 为webdriver驱动 timeout 最长超时时间,单位(秒) poll_frequency 循环查找元素每次间隔的时间,默认0.5秒 ignored_exceptions 超时后需要输出的异常信息
WebDriverWait()下面有两个方法可用until()和until_not()
*WebDriverWait(driver, timeout).until(method, message='')*
method 函数或者实例call()方法返回True时停止,否则超时后抛出异常。
参数说明:
method 在等待时间内调用的方法或者函数,该方法或函数需要有返回值,并且只接收一个参数driver。 message 超时时抛出TimeoutException,将message传入异常显示出来
*WebDriverWait(driver, timeout).until_not(method, message='')*
于上面的until() 相反,until_not 中的method函数或者实例call()方法返回False结束,否则抛出异常。
until方法使用的method 的函数或者类call()方法详解:
函数我们一般采用匿名函数lambda 。
lambda driver:driver.find_element(<定位元素>) # 当定位的元素时为True,无元素时为False。如示例1、2:
WebDriverWait示例1:
WebDriverWait(driver,5).until(lambda driver:driver.find_element_by_id('query'))
5秒内等待元素(id='query')出现,lambda driver:driver.find_element_by_id('query') 为一个匿名函数,只有一个driver参数,返回的是查找的元素对象。
WebDriverWait示例2:
WebDriverWait(driver, 5).until_not(lambda driver:driver.find_element_by_name('query'))
5秒内等待元素消失,同示例1 until_not 要求无元素返回即元素不存在于该页面。
定义类中的call()方法。
class wait_element(object): def __init__(self, locator): self.locator = locator def __call__(self, driver): return driver.find_element(self.locator)WebDriverWait(driver, 5).until(wait_element((By.ID, 'query'))) # 等待元素出现WebDriverWait(driver, 5).until_not(wait_element((By.ID, 'query'))) # 等待元素消失
wait_element类中init()方法接收需要定位的元素,call()方法中只能有唯一变量driver,并且返回元素对象。
这样做是是不是很麻烦,其实selenium提供的一个库进行操作,expected_conditions库。引入位置
from selenium.webdriver.support import expected_conditions as ec,它囊括了我们需要使用等待的所有情况。
四、expected_conditions 类库
from selenium.webdriver.support import expected_conditions as ec # 引入包
下面示例都是以搜狗搜索首页为例。
方法中参数说明 locator=(By.ID, 'id') 表示使用By方法定位元素的元组,element表示获取的webElement元素对象。
ec.title_is(‘title’) 判断页面标题等于title
*ec.title_contains(‘title’)* 判断页面标题包含title
WebDriverWait(driver, 10).until(ec.title_is('搜狗搜索引擎 - 上网从搜狗开始')) # 等待title 于参数相等WebDriverWait(driver, 10).until(ec.title_contains('搜狗搜索引擎')) # 等待title 包含 参数的内容
*ec.presence_of_element_located(locator)* 等待locator元素是否出现
ec.presence_of_all_elements_located(locator) 等待所有locator元素是否出现
WebDriverWait(driver, 10).until(ec.presence_of_element_located((By.ID, 'query')))WebDriverWait(driver, 10).until(ec.presence_of_all_elements_located((By.ID, 'query')))
*ec.visibility_of_element_located(locator)* 等待locator元素可见
ec.invisibility_of_element_located(locator) 等待locator元素隐藏
*ec.visibility_of(element)* 等待element元素可见
WebDriverWait(driver, 10).until(ec.visibility_of_element_located((By.ID, ''stb''))) # 等待元素可见WebDriverWait(driver, 10).until(ec.invisibility_of_element_located((By.ID, ''stb''))) # 等待元素隐藏WebDriverWait(driver, 10).until(ec.visibility_of(driver.find_element_by_link_text('高级搜索'))) # 等待元素可见
*ec.text_to_be_present_in_element(locator,text)* 等待locator的元素中包含text文本
ec.text_to_be_present_in_element_value(locator,value) 等待locator元素的value属性为value
WebDriverWait(driver, 10).until(ec.text_to_be_present_in_element((By.ID, 'erwx'), '搜索APP')) # 等待元素中包含搜索APP文本WebDriverWait(driver, 10).until(ec.text_to_be_present_in_element_value((By.ID, 'query'),'selenium')) # 等待元素的值为 selenium,一般用于输入框
ec.frame_to_be_available_and_switch_to_it(locator) 等待frame可切入
WebDriverWait(driver, 10).until(ec.frame_to_be_available_and_switch_to_it((By.ID, 'frame')))WebDriverWait(driver, 10).until(ec.frame_to_be_available_and_switch_to_it('frameid'))ec.alert_is_present() 等待alert弹出窗口出现WebDriverWait(driver, 10).until(ec.alert_is_present())
ec.element_to_be_clickable(locator) 等待locator元素可点击
WebDriverWait(driver, 10).until(ec.element_to_be_clickable((By.ID, 'kw')))
等待元素被选中,一般用于复选框,单选框
ec.element_to_be_selected(element) 等待element元素是被选中
ec.element_located_to_be_selected(locator) 等待locator元素是被选中ec.element_selection_state_to_be(element, is_selected) 等待element元素的值被选中为is_selected(布尔值)
ec.element_located_selection_state_to_be(locator,is_selected) 等待locator元素的值是否被选中is_selected(布尔值)
from selenium import webdriverimport timefrom selenium.webdriver.support.wait import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as ec # 引入包from selenium.webdriver.common.by import Bydriver = webdriver.Chrome()driver.maximize_window() driver.get(r';) driver.find_element_by_link_text('设置').click()WebDriverWait(driver, 3).until(ec.element_to_be_clickable((By.LINK_TEXT, '搜索设置'))) # 等待搜索可点击,不可缺少driver.find_element_by_link_text('搜索设置').click()element = driver.find_element_by_id('s1_1')WebDriverWait(driver, 2).until(ec.element_to_be_selected(element)) # element被选中WebDriverWait(driver, 10).until(ec.element_located_to_be_selected((By.ID, 'SL_0'))) # id=’SL_0’ 被选中WebDriverWait(driver, 10).until(ec.element_selection_state_to_be(element,True )) # element 被选中WebDriverWait(driver, 10).until(ec.element_located_selection_state_to_be((By.ID, 'SL_1'), False)) # id=’SL_1’不被选中time.sleep(3)driver.quit()
五、什么时候使用等待
固定等待sleep与隐性等待implicitly_wait尽量少用,它会对测试用例的执行效率有影响。
显性的等待WebDriverWait可以灵活运用,什么时候需要用到?
1、页面加载的时候,确认页面元素是否加载成功可以使用WebDriverWait
2、页面跳转的时候,等待跳转页面的元素出现,需要选一个在跳转前的页面不存在的元素
3、下拉菜单的时候,如上百度搜索设置的下拉菜单,需要加上个时间断的等待元素可点击
4、页面刷新的时候
总之,页面存在改变的时候;页面上本来没的元素,然后再出现的元素
1.5键盘鼠标事件ActionChains
一、鼠标点击操作
click(element=None) 左击 context_click(element=None) 右击 double_click(element=None) 双击 move_to_element(element) 移动鼠标到元素中间(悬停) drag_and_drop(source,target) source上按下左键拖动到target元素上 click_and_hold(element=None) 在元素上按下鼠标左键 release() 释放鼠标 perform() 执行ActionChains中存储的动作
element有None默认值的表示不传入参数该动作在原地执行。
鼠标事件具体使用示例如下:
示例1:鼠标左键点击
action=ActionChains(driver)action.click() # 在鼠标当前位置单击action.perform() # 执行action存储的动作# 鼠标在 '新闻' 元素位置单击action.click(driver.find_element_by_link_text('新闻')).perform()
注意:action.click() 动作并未执行,它只是存储在action实例中,需要通过action.perform()方法执行存储动作;鼠标键盘事件动作动作可以存储多个,然后一次性执行。如下执行Cytl+C:
ActionChains(driver).key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()
示例2:鼠标右击
action=ActionChains(driver)action.context_click().perform() # 在鼠标当前位置右击# 鼠标在 '新闻' 元素位置右击action.context_click(driver.find_element_by_link_text('新闻')).perform()
示例3:鼠标双击操作
action=ActionChains(driver)action.double_click().perform() # 在鼠标当前位置双击# 鼠标在 '新闻' 元素位置双击击action.double_click(driver.find_element_by_link_text('新闻')).perform()
示例4:鼠标移动
action = ActionChains(driver)element=driver.find_element_by_link_text('设置')# 鼠标移动到 '新闻' 元素上的中心点action.move_to_element(element).perform()# 鼠标在原位置向x轴移动xoffset、y轴移动yoffset;xoffset、yoffset可为正负数action.move_by_offset(-200,100).perform()# 鼠标移动到element元素中心点偏移xoffset、yoffsetaction.move_to_element_with_offset(element,-500,600).perform()
action.move_by_offset(xoffset,yoffset) 这里需要注意,如果 xoffset 为负数,表示横坐标向左移动,yoffset 为负数表示纵坐标向上移动。而且如果这两个值大于当前屏幕的大小,鼠标只能移到屏幕最边界的位置。
鼠标移动操作在测试环境中比较常用到的场景是需要获取某元素的 flyover/tips,实际应用中很多 flyover 只有当鼠标移动到这个元素之后才出现,所以这个时候通过执行 move_to_element(to_element) 操作,就能达到预期的效果。
根据我个人的经验,这个方法对于某些特定产品的图标的 flyover/tips 也不起作用,虽然在手动操作的时移动鼠标到这些图标上面可出现 flyover,但当使用 WebDriver 来模拟这一操作时,虽然方法成功执行,但 flyover 却不出来。所以在实际应用中,还需要对具体的产品页面做相应的处理。
示例5:鼠标悬停
action.click_and_hold().perform() # 鼠标在当前位置按下并不释放# 鼠标 在'设置' 上悬停action.click_and_hold(driver.find_element_by_link_text('设置')).perform()action.click_and_hold(element) 这个方法实际上是执行了两个动作,首先是鼠标移动到元素 element,然后再 click_and_hold, 所以这个方法也可以写成 action.move_to_element(element).click_and_hold()。
示例6:鼠标拖拽
source = driver.find_element_by_id("kw") # 获取起始位置元素target = driver.find_element_by_id("sk") # 获取目标元素# 将元素source拖动到target的位置ActionChains(driver).drag_and_drop(source, target).perform()# 鼠标拖拽动作,将 source 元素向x、y轴方向移动 (xoffset, yoffset) ,其中 xoffset 为横坐标,yoffset 为纵坐标。ActionChains(driver).drag_and_drop_by_offset(source, -100, 100).perform()
在这个拖拽的过程中,已经使用到了鼠标的组合动作,首先是鼠标点击并按住 click_and_hold( source) 元素,然后执行鼠标移动动作 (move_to),移动到 target 元素位置或者是 (xoffset, yoffset) 位置,再执行鼠标的释放动作 (release)。所以上面的方法也可以拆分成以下的几个执行动作来完成:
ActionChains(driver).click_and_hold(source).move_to_element(target).release().perform()
示例7:鼠标释放操
action = ActionChains(driver)action.release().perform() # 释放按下的鼠标
二、键盘操作
对于键盘的模拟操作,ActionChains类中有提供了按下key_down(keys)、释放key_up(keys)、按下并释放send_keys(keys_to_send) 等方法。
键盘的操作有普通键盘和修饰键盘两种 。
普通键盘为常用字母数字等;修饰键盘为Ctrl、Shift、Alt等,修饰键盘一般和其他键组合使用的键。
使用键盘操作时需要引入from selenium.webdriver.common.keys import Keys包,Keys 包中含所有特殊用键。
1、普通键盘操作
键盘操作使用send_keys(*keys_to_send)方法,该方法支持多个按键连续操作,如果需要对某个元素执行按键操作使用send_keys_to_element( element, *keys_to_send)方法。具体使用如下示例:
from selenium.webdriver.common.keys import Keysaction = ActionChains(driver)action.send_keys(Keys.SPACE).perform() # 按下并释放空格键action.send_keys(Keys.TAB).perform() # 按下并释放Tab键action.send_keys(Keys.BACKSPACE).perform() # 按下并释放Backspace键action.send_keys(Keys.BACKSPACE,Keys.SPACE).perform() # 连续执行按键动作action.send_keys(Keys.TAB).send_keys(Keys.TAB).perform() # 也可以这样组合'''针对某个元素发出某个键盘的按键操作,或者是输入操作'''element = driver.find_element_by_id('query')# 对一元素使用键盘操作action.send_keys_to_element(element, 'selenium').perform()# 上面动作拆解为下面动作action.click(element).send_keys('selenium').perform()
注意除了 ActionChains类有 send_keys(keys_to_send)方法外,WebElement 类也有一个 send_keys_to_element(keys_to_send)方法,这两个方法对于一般的输入操作基本上相同,不同点在于以下几点:
第一:Actions 中的 send_keys(*keys_to_send)对修饰键操作后并不会释放,也就是说当调用 actions.send_keys(Keys.ALT)、 actions.send_keys(Keys.CONTROL)、 action.send_keys(Keys.SHIFT) 的时候,相当于调用 actions.key_down(keys_to_send),而如果在现实的应用中想要模拟按下并且释放这些修饰键,应该先action.reset_actions()重设action,然后再调用 action.send_keys(keys.NULL).perform()取消按下的修饰键。
第三点,在 WebDriver 中,我们可以使用 WebElement 类的 send_keys() 来上传附件,比如 element.send_keys(“D:\test\uploadfile\test.jpg”)上文件,但不能使用ActionChains来上传附件,因为type=’file’的输入框并不支持键盘输入。
2、修饰键的使用
修饰键是键盘上的一个或者一组特别的键,当它与一般按键同时使用时,用来临时改变一般键盘的普通行为。
修饰键一般跟普通键组合使用,比如 Ctrl+A、Alt+F4等。
我们电脑中的修饰键一般有以下几种修:Ctrl、Alt(Option)、Shift、AltGr、Windows logo、Command、FN(Function)。一般使用的都是前三种。
对于修饰键的使用在Python selenium中一般使用按下key_down(keys)、释放key_up(keys)、按下并释放send_keys(keys_to_send)组合实现。
action = ActionChains(driver)action.key_down(Keys.CONTROL).perform() # 按下ctrl键action.key_up(Keys.CONTROL).perform() # 释放ctrl键action.key_down(Keys.SHIFT).perform() # 按下shift键action.key_up(Keys.SHIFT).perform() # 释放shift键action.key_down(Keys.ALT).perform() # 按下alt键action.key_up(Keys.ALT).perform() # 释放alt键
示例:通过ctrl+c 来复制文本
ActionChains(driver).key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()
三、WebElement.send_keys()键盘操作
WebElement元素对象下的send_keys也支持组合键盘操作。
代码示例如下:
element = driver.find_element_by_id('query')element.send_keys('selenium')element.send_keys(Keys.BACK_SPACE) # 按BACKSPACE删除一个字符element.send_keys(Keys.SPACE) # 空格键(Space)element.send_keys(Keys.CONTROL, 'a') # 全选(Ctrl+A)element.send_keys(Keys.CONTROL, 'c') # 复制(Ctrl+C)element.send_keys(Keys.CONTROL, 'v') # 粘贴(Ctrl+v)element.send_keys(Keys.TAB) # 制表键(Tab)element.send_keys(Keys.ESCAPE) # 回退键(Esc)element.send_keys(Keys.ENTER) # 回车键(Enter)1.6层级定位与定位一组元素
一、层级定位(二次定位)
在实际测试过程中,一个页面可能有多个属性基本相同的元素,如果要定位到其中的一个,这时候需要用到层级定位。先定位其父元素,然后再通过父元素定位该元素。
示例:通过层级定位搜狗输入框
driver = webdriver.Chrome()driver.maximize_window()driver.get(r';)form_element = driver.find_element_by_id('sf') # 获取form表单元素form_element.find_element_by_id('query').send_keys('selenium') # 通过表单定位输入框form_element.find_element_by_id('stb').click() # 通过表单定位搜索按钮time.sleep(3)driver.quit()
如上代码,我们先定位到了form表单,然后通过表单定位下面的输入框与按钮。
注意:上面示例只通过两层定位到了元素,层级定位不一定定位两次,我们可以定位多次。
二、定位一组元素
而当我们需要获取多个属性相同的对象,并且需要批量操作该对象时,就会使用find_elements定位一组元素。
创建以下html文件,文件名checkbox.html
<form class="form-horizontal"> <div class="control-group"> <label class="controllabel" for="China">中国人</label> <div class="controls"> <input type="checkbox" id="China"/> </div> </div> <div class="control-group"> <label class="controllabel" for="American">美国人</label> <div class="controls"> <input type="checkbox" id="American"/> </div> </div> <div class="control-group"> <label class="controllabel" for="German">德国人</label> <div class="controls"> <input type="checkbox" id="German"/> </div> </div> <div class="button"> <input type="submit" id="submit"/> </div></form>
示例:全选上面的多选框
from selenium import webdriverimport timedriver = webdriver.Chrome()driver.maximize_window()driver.get(r'E:\xxx\checkbox.html') # 打开checkbox.html文件,使用绝对地址checkboxs = driver.find_elements_by_xpath('//input[@type="checkbox"]') # 获取批量的对象for checkbox in checkboxs: # 循环控制 if not checkbox.is_selected(): # 判断多选框是否被选中 checkbox.click() # 单击time.sleep(3)driver.quit()
三、综合运用
当我们需要定位一组元素时,页面上相似的元素会很多,这时我们需要和层级一定一起使用。先定位到该组元素的父元素,然后通过父元素定位其子孙元素。
示例1:获取搜狗微信页面搜索热词的内容
driver = webdriver.Chrome()driver.maximize_window()driver.get(r';)topele = driver.find_element_by_id('topwords') # 搜索热词的父元素tops = topele.find_elements_by_tag_name('a') # 二次批量定位热词元素for top in tops: # 循环获取元素 print(top.text) # 打印文本内容driver.quit()
UI自动化测试中对于表格的定位是个难点,怎么样快速获取表格数据,请看下面几个示例。
示例2:定位表格获取表头
driver = webdriver.Chrome()driver.maximize_window()driver.get(r';)# //table[@class="dataintable"]//tr[1]//th 获取表头元素table_header = driver.find_elements_by_xpath('//table[@class="dataintable"]//tr[1]//th')for header in table_header: # 循环获取元素 print(header.text) # 打印文本内容driver.quit()
示例3:定位表格第二列数据内容
driver = webdriver.Chrome()driver.maximize_window()driver.get(r';)# //table[@class="dataintable"]//tr[y]//td[x] y第几条记录,x第几列数据# //table[@class="dataintable"]//tr//td[2] 获取第二列数据table_header = driver.find_elements_by_xpath('//table[@class="dataintable"]//tr//td[2]')for header in table_header: # 循环获取元素 print(header.text) # 打印文本内容driver.quit()
示例4:获取表格中所有的数据
driver = webdriver.Chrome()driver.maximize_window()driver.get(r';)# //table[@class="dataintable"]//tr 定位所有行tables = driver.find_elements_by_xpath('//table[@class="dataintable"]//tr')for tr in tables: # 循环每行元素 for td in tr.find_elements_by_tag_name('td'): # 循环获取列 print(td.text, end='\t\t') print('\n')driver.quit()
定位表格,采用find_elements 组定位,使用xpath=//table//tr[y]//td[x](y第几条记录,x第几列数据),当y或者x其中一个没有值时定位一行或一列。
1.7下拉框元素定位
选择获取反选下拉框元素首先要实例化select元素
from selenium.webdriver.support.ui import Select # 引入包
select_element=Select(element) # 实例化select
三种常用选择方法
select_element.select_by_index(index) 根据index定位,从0开始 select_element.select_by_value(value) 根据value属性定位 select_element.select_by_visible_text(text) 根据文本定位
反选的方法
select_element.deselect_by_index(index) 根据index定位,从0开始 select_element.deselect_by_value(value) 根据value属性定位 select_element.deselect_by_visible_text(text) 根据文本定位 select_element.deselect_all() 取消全部选择
获取选项的值
select_element.options 返回这个select元素所有的options select_element.all_selected_options 所有被选中的options select_element.first_selected_option 第一个被选中的option
创建select.html 文件,代码如下:
<form> <select id="s1Id"> <option></option> <option value="o1" id="id1">o1</option> <option value="o2" id="id2">o2</option> <option value="o3" id="id3">o3</option> </select> <br/><br/> <select id="s2Id" multiple="multiple" size="6"> <option></option> <option value="o1val">o1</option> <option value="o2val">o2</option> <option value="o3val">o3</option> <option value="o4val"> With spaces</option> <option value="o4val"> With nbsp</option> </select></form>
示例1:采用三种方法依次选择's1Id'的值
s1 = Select(driver.find_element_by_id('s1Id')) # 实例化Select,页面第一个下拉框s1.select_by_index(1) # 选择第二项选项:o1s1.select_by_value("o2") # 选择value="o2"的项s1.select_by_visible_text("o3") # 选择text="o3"的值,即在下拉时我们可以看到的文本
示例2:想查看一个's1Id'所有的选项
s1 = Select(driver.find_element_by_id('s1Id'))for select in s1.options: print(select.text)
示例3:查看我已选中的所有选项,'s2Id'可以多选的选择框
s4 = Select(driver.find_element_by_id('s2Id'))s4.select_by_index(1) # 根据顺序选择第2个s4.select_by_value("o2val") # 根据value属性选择o2vals4.select_by_visible_text("With spaces") # 根据展示文本选择With spacess4.select_by_visible_text(u" With nbsp") # 注意空格,只有为 是才用空格for select in s4.all_selected_options: # 循环获取所有的值 print(select.text)
注意:只有只有为 的空格才是空格,在html中代码只有 才代表空格,代码中的空格不是空格。
示例4:查看选择框的默认值或选中的值
s1 = Select(driver.find_element_by_id('s1Id'))print(s1.first_selected_option.text) # 查看选择默认值s1.select_by_value("o2")print (s2.first_selected_option.text) # 查看选中的值
示例5:取消选择
s4 = Select(driver.find_element_by_id('s2Id'))s4.select_by_index(1)s4.select_by_value("o2val")s4.select_by_visible_text("With spaces")s4.select_by_visible_text(u" With nbsp")s4.deselect_by_index(1) # 根据值顺序取消选择s4.deselect_by_value("o2val") # 根据value属性取消选择s4.deselect_by_visible_text("With spaces") # 根据文本取消选择s4.select_by_value("o2val")s4.select_by_index(1)s4.deselect_all() # 取消全部选择1.8定位frame和iframe中的元素对象
< frame> <iframe> 标签,浏览器会在标签中打开一个特定的页面窗口(框架),它在本窗口中嵌套进入一个网页,当用selenium定位页面元素的时候会遇到定位不到frame框架内的元素的问题。
定位frame中的元素前我们需要driver.switch_to.frame()切换到对应的frame中,执行操作后,要操作frame框架外的元素,需要通过driver.switch_to.default_content()切换回主文档页面。
driver.switch_to.frame(index/id/name/WebElement) 切入frame裤架中,参数可以为id/name/index
driver.switch_to.parent_frame() 切换回当前frame的上一层,如果当前已是主文档,则无效果
driver.switch_to.default_content() 切换回主文档
创建如下两个html文件,两个文件放入同一个文件夹内
frame.html
<html><head> <meta http-equiv="content-type" content="text/html;charset=utf-8"/> <title>frame</title></head><body><div class="row-fluid"> <label>frame外输入框</label> <input type='text' id="frameinput"> <div class="span10 well"> <h3>frame</h3> <iframe id="f1" name="frame2" src="inner_frame.html" width="800" height="600"></iframe> </div></div></body></html>
inner_frame.html
<html><head> <title>inner frame</title></head><body><label id="innerlable">frame1内多选按钮 </label><input type="checkbox" id="innercheck" name="inner"><div class="row-fluid"> <h3>inner frame</h3> <iframe id="f2" name="frame2" src="; width="700" height="400"> </iframe></div></body></html>
示例:操作主文档的元素 --> 切换到外层frame 操作外层frame的元素 --> 切换到内层frame 操作内层的元素 --> 切换回外层frame 操作外层frame 的元素 --> 再次切入内层frame操作元素 --> 切换回主文档操作文档元素 -->再去切换到外层frame操作元素
from selenium import webdriverimport timedriver = webdriver.Chrome()driver.get(r'E:\frame.html') # 打开frame.html页面,注意修改为你的位置driver.find_element_by_id('frameinput').send_keys('操作frame外的元素')driver.switch_to.frame(0) # 根据index切换,从0开始text = driver.find_element_by_id('innerlable').textprint(text)driver.find_element_by_id('innercheck').click()driver.switch_to.frame('f2') # 根据id切入 内层framedriver.find_element_by_id('index-kw').send_keys('selenium frame')driver.switch_to.parent_frame() # 切换到上一层表单driver.find_element_by_id('innercheck').click()driver.switch_to.frame('frame2') # 根据name再次切入内层framedriver.find_element_by_id('index-bn').click()driver.switch_to.default_content() # 切换回主文档driver.find_element_by_ta('frameinput').clear()driver.switch_to.frame(driver.find_elements_by_tag_name('iframe')) # 通过webelement切换driver.find_element_by_id('innercheck').click()time.sleep(3)driver.quit()
1、 driver.switch_to.frame(frame_reference)切换进入frame
switch_to_frame() 将淘汰使用,建议使用switch_to.frame()。
switch_to.frame() 切换frame支持4种不同参数方法进行切换,元素的frame的index,frame的id或name属性,frame元素的WebElement元素对象。
通常采用id和name就能够解决绝大多数问题。但有时候frame并无这两项属性,则可以用index和WebElement来定位:
index从0开始,整型参数,根据同层frame的顺序定位WebElement对象,即find_element方法所取得的对象,我们可以用tag_name、xpath等来定位frame对象。如上示例的:driver.switch_to.frame(driver.find_elements_by_tag_name('iframe'))
2、 driver.switch_to.default_content() 切换回主文档
切到frame中之后,我们便不能继续操作主文档的元素,这时如果想操作主文档内容,则需切回主文档。
driver.switch_to.default_content() # 切换到主文档中。
注意:很多人都会忘记这步操作
3、driver.switch_to.parent_frame() 切换到上一层表单
<html> <iframe id="frame1"> <iframe id="frame2" / > </iframe></html>
嵌套frame很少会遇到,如下frame1为外层,frame2嵌套在frame1中。我们进行切换操作如下:
a. 从主文档切到frame2,一层层切进去
driver.switch_to.frame("frame1")driver.switch_to.frame("frame2")
b. 从frame2再切回frame1,selenium提供了一个方法能够从子frame切回到父frame,而不用我们切回主文档再切进来。
driver.switch_to.parent_frame() # 如果当前已是主文档,则无效果
parent_frame()这个相当于后退的方法,我们可以随意切换不同的frame。
1.9Alert/Confirm/Prompt 弹出窗口处理
一、Alert/Confirm/Prompt弹出窗口特征说明
Alert弹出窗口:
提示用户信息只有确认按钮,无法通过页面元素定位,不关闭窗口无法在页面上做其他操作。
Confirm 弹出窗口:
有确认和取消按钮,该弹出窗口无法用页面元素定位,不关闭窗口无法在页面上做其他操作。
Prompt弹出窗口:
有输入框、确认和取消按钮,该弹出窗口无法用页面元素定位,不关闭窗口无法在页面上做其他操作。
注意:3种窗口为浏览器自带的窗口,该窗口无法定位到元素,能定位到元素需要使用WebElement操作。
二、Alert/Confirm/Prompt弹出窗口操作
第一步:需要获取弹出窗口,两种方法 与Alert(driver)
alert=driver.switch_to.alert
或
from selenium.webdriver.common.alert import Alertalert=Alert(driver)
第二步:对获取到的窗口进行操作,常用方法如下:
alert.text() # 获取窗口信息alert.accept() # 确认alert.dismiss() # 取消alert.send_keys(keysToSend) # 输入信息
alert.authenticate(username, password) # 用户认证信息登录,已有确认操作
三、实例说明
创建下面3个html文件
alertTest.html
<html><head> <title>Alert Test</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"/></head><script type="text/javascript">function showAlert(){ alert(document.from1.t1.value);}function showMultilineAlert(){ alert("你必须纠正以下错误:\n你必须输入XXXX.\n你必须做XXXX.\n你必须XXXX");}</script><body><h2>Alert Test</h2><form name="from1"> <input type="text" name="t1" value="可以输入 Alert 信息"><br><br> <input type="button" name="button1" value="点击Alert获取输入框信息" onclick="showAlert()"><br><br> <input type="button" name="button2" value="Alert自带多行文本信息" onclick="showMultilineAlert()"><br></form></body></html>
confirmTest.html
<html><head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> <title>Confirm Test</title></head><script type="text/javascript">function showConfirm(){ var t1 = document.from1.t1; if (confirm("请点击确认或取消")){ t1.value = "确认"; }else{ t1.value = "取消"; }}</script><body><h2>Confirm Test</h2><form name="from1"> <input type="button" name="button1" value="点击Confirm按钮" onclick="showConfirm()"><br><br> <input type="text" name="t1"></form></body></html>
promptTest.html
<html><head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> <title>Prompt Test</title></head><script type="text/javascript"> function showPrompt(){ var t1 = document.from1.t1; t1.value = prompt("请输入信息,信息将填入页面输入框."); }</script><body><h2>Prompt Test</h2><form name="from1"> <input type="button" name="button1" value="点击Prompt按钮" onclick="showPrompt()"><br><br> <input type="text" name="t1"></form></body></html>
示例1:Alert弹窗获取文本与确认操作
from selenium import webdriverfrom selenium.webdriver.support.wait import WebDriverWaitfrom selenium.webdriver.support.expected_conditions import alert_is_presentfrom selenium.webdriver.common.alert import Alertdriver = webdriver.Chrome()driver.get(r'E:\XXX\alertTest.html')driver.find_element_by_name('button1').click() # 点击第一个按钮WebDriverWait(driver, 5).until(alert_is_present()) # 等待弹出窗口出现alert = driver.switch_to.alert # 获取弹出窗口text1 = alert.text # 获取窗口文本信息print(text1) # 打印窗口文本信息alert.accept() # 确认print('----------')driver.find_element_by_name('button2').click() # 点击第二个按钮WebDriverWait(driver, 5).until(alert_is_present()) # 等待弹出窗口出现alert = Alert(driver) # 获取弹出窗口text1 = alert.text # 获取窗口文本信息print(text1) # 打印窗口文本信息alert.accept() # 确认driver.quit()
注意:WebDriverWait(driver, 5).until(alert_is_present()) 加上这个可提高代码的可靠性
示例2:Comfirm弹窗获取文本、确认、取消操作
driver = webdriver.Chrome()driver.get(r'E:\XXX\confirmTest.html')driver.find_element_by_name('button1').click() # 点击按钮WebDriverWait(driver, 5).until(alert_is_present()) # 等待弹出窗口出现alert = driver.switch_to.alert # 获取弹出窗口print(alert.text) # 打印窗口信息alert.accept() # 确认time.sleep(2)driver.find_element_by_name('button1').click() # 点击按钮WebDriverWait(driver, 5).until(alert_is_present()) # 等待弹出窗口出现alert = driver.switch_to.alert # 获取弹出窗口alert.dismiss() # 取消time.sleep(2)driver.quit()
示例3:Prompt 弹窗获取文本、输入内容、确认操作
driver = webdriver.Chrome()driver.get(r'E:\XXX\promptTest.html')driver.find_element_by_name('button1').click() # 点击按钮WebDriverWait(driver, 5).until(alert_is_present()) # 等待弹出窗口出现alert = Alert(driver) # Alert 获取弹出窗口alert.send_keys('selenium Alert弹出窗口输入信息') # 输入信息alert.accept() # 确认time.sleep(2)driver.quit()1.10上传文件
一、input控件上传文件
查看长传文件的页面元素标签,如果为input表明是通过input控件上传文件。我们可以直接采用WebElement.send_keys(‘文件地址’) 长传文件。
创建html文件,如下:
upload.html
<html><head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> <title>upload file</title></head><body><h3>upload file</h3><input type="file" name="file"/></body></html>
示例:长传C:\install.log文件。
from selenium import webdriverimport timedriver = webdriver.Chrome()driver.get(r'E:\XXXX\Html\upload.html') # 文件的地址driver.find_element_by_name('file').send_keys(r'C:\install.log') # 上传文件time.sleep(2)driver.quit()1.11浏览器多窗口切换
有时web应用会打开多个浏览器窗口,当我们要定位新窗口中的元素时,我们需要将webDriver的handle(句柄)指定到新窗口。
什么意思?
假设我们打开web应用,在系统运行过程中重新打开一个新窗口(可以是页签,当前浏览器存在两个窗口),这时我们webDriver对浏览器的操作指针(句柄)还再原窗口,如果需要操作新窗口元素就要将handle句柄切换到新窗口。
一、常用方法
driver.current_window_handle 获取当前窗口handle
driver.window_handles 获取所有窗口的handle,返回list列表
driver.switch_to.window(handle) 切换到对应的窗口
driver.close() 关闭当前窗口
二、示例
示例:进入搜狗搜索 --> 打开搜狗输入法页面 --> 输入法页面查看皮肤 --> 关闭搜狗搜索页面 --> 输入法页面查看词库
from selenium import webdriverimport timedriver = webdriver.Chrome()driver.get(';)driver.find_element_by_link_text('搜狗输入法').click()nowhandle = driver.current_window_handle # 获得当前窗口print(driver.current_window_handle)print('当前窗口为:', driver.title)allhandles = driver.window_handles # 获得所有窗口for handle in allhandles: # 循环判断窗口是否为当前窗口 if handle != nowhandle: driver.switch_to.window(handle) # 切换窗口 time.sleep(2)print('切换到窗口:', driver.title)driver.find_element_by_link_text('皮肤').click() # 操作新窗口元素driver.switch_to.window(nowhandle) # 回到原先的窗口print('回到原来窗口:', driver.title)driver.close() # 关闭当前窗口,关闭的是当前的窗口driver.switch_to.window(driver.window_handles[0]) # 再次切换窗口driver.find_element_by_link_text('词库').click()time.sleep(5)driver.quit()
三、封装层函数
在自动化测试中切换窗口页面一般会封装为函数,如下示例:
def switch_to_window(driver, winB): """ :param winB: 1.切换窗口的标题 2.切换窗口的序号 3.切换页面的元素 :return: True 切换成功 :Usage: driver.switch_to_window('win_name') driver.switch_to_window(2) # 切换到第二个窗口 located=(By.ID,'id') # 确定切换页面的元素 driver.switch_to_window(located) # 切换到页面中存在located的元素窗口 """ result = False handles = driver.window_handles current_handle = driver.current_window_handle if isinstance(winB, tuple): for handle in handles: driver.switch_to.window(handle) time.sleep(2) try: driver.find_element(*winB) except NoSuchElementException: pass else: result = True break if not result: driver.switch_to.window(current_handle) time.sleep(2) elif isinstance(winB, str): for handle in handles: driver.switch_to.window(handle) time.sleep(2) if winB in driver.title: result = True break if not result: driver.switch_to.window(current_handle) time.sleep(2) elif isinstance(winB, int): if winB <= len(handles): driver.switch_to.window(winB - 1) time.sleep(2) result = True else: print('参数错误') return result1.12xpath定位元素
XPath 最初是用来在 XML 文档中定位 DOM 节点的语言,由于 HTML 也可以算作 XML 的一种实现,所以 Selenium 也可以利用 XPath 这一强大的语言来定位 Web 元素。xpath的强大在于它可以通过父节点或者兄弟节点,根据html元素的前后关联性定位到元素需要的元素。
XPath 使用路径表达式来选取 XML 文档中的节点或节点集。节点是通过沿着路径 (path) 或者步 (steps) 来选取的。
1、选取节点
XPath 使用路径表达式在 XML 文档中选取节点。节点是通过沿着路径或者 step 来选取的。
示例:
2、谓语(Predicates)
谓语用来查找某个特定的节点或者包含某个指定的值的节点。
谓语被嵌在方括号中。
3、选取未知节点
XPath 通配符可用来选取未知的 XML 元素。
示例:
4、XPath 轴
轴可定义相对于当前节点的节点集。
示例:
5、综合运用
示例:搜狗搜索页面元素为示例
1.13CSS定位元素
1、CSS 元素选择器
input 选择input元素
p 选择p元素
2、CSS ID与类选择器
ID 选择器以 "#" 来定义。
class类选择器以一个‘.’点号显示
示例:搜狗搜索页面元素示例
#query 表示id为query的元素
.query 表示class为query的元素
3、CSS 属性选择器
属性选择器可以根据元素的属性及属性值来选择元素。
示例:
[title] 将title属性放到中括号中,表示选择具有该属性的元素
[title=value] title属性等于value的元素
[title~=value] title属性包含value单词的元素,注意是单词
[title|=value] title属性以value单词开头的元素
[title^=value] title属性以value开头的元素
[title$=value] title属性以value结尾的元素
[title*=value] title属性包含value的元素
input[title*=value] input元素下有title属性包含value的元素
inputtype="ext#query input元素下有type="text"、 name='query'、id="query"的元素
4、CSS 后代选择器
后代选择器(descendant selector)又称为包含选择器。后代选择器可以选择作为某元素后代的元素。
注意:后代不一定是儿子,也有可能是孙子。
示例:搜狗搜索页面元素示例
span input 选择span下的input元素
div.content span.enter-input input#stb 选择div.content下span.enter-input的下的input ID=stb的元素。(搜狗搜索示例)
5、CSS 子元素选择器
与后代选择器相比,子元素选择器(Child selectors)只能选择作为某元素子元素的元素。
如果您不希望选择任意的后代元素,而是希望缩小范围,只选择某个元素的子元素,就使用子元素选择器(Child selector)。
与后代的区别在于,子元素选择器只能选择儿子。
示例:搜狗搜索页面元素示例
div>input 只作为 div 元素子元素的 input元素
div>form>span>input div下的子元素form下的子元素span下的子元素input
div>form[name='sf']>span>input#query div下的子元素form[name='sf']下的子元素span下的子元素input#query
div#content form>span>input#query div#content下的子元素form下的子元素span下的子元素input#query
6、CSS 相邻兄弟选择器
相邻兄弟选择器(Adjacent sibling selector)可选择紧接在另一元素后的元素,且二者有相同父元素。
示例:搜狗搜索页面元素示例
input+input input后出现的input的元素
div#content form>span+input div#content下的form元素下的子元素span同级相邻的第一个弟弟元素
7、CSS 伪类
CSS 伪类用于向某些选择器添加特殊的效果。selenium中元素CSS定位用的伪类只有:first-child(元素的第一个子元素),其他的可靠性非常低要不就是不能使用。
示例:搜狗搜索页面元素示例
input:first-child 所有第一个input元素
form > input:first-child 所有 form子元素中的第一个 input 元素
form input:first-child 所有 form元素中以input 作为第一个元素的元素
form span:first-child input:first-child form下的第一个span元素下的第一个input元素
8、CSS选择器运用示例
例子是搜狗搜索中的元素为例。
9、CSS选择器参考手册
参考w3school的选择器参考手册为样本,进行了删减,将不适合自动化测试的选择器删除。
原文参考手册见:
例子是搜狗搜索中的元素为例:
1.14JavaScript获取页面元素
1、DOM获取元素
HTML DOM 定义了访问和操作 HTML 文档的标准。每个页面都是一个DOM Tree 结果,如下图
通过 HTML DOM,树中的所有节点均可通过 JavaScript 进行访问。我们通过JavaScript返回该节点就是我们的元素。
document.getElementById() 获取带有指定 ID 的元素
document.getElementsByClassName() 获取包含带有指定类名的所有元素的节点列表
document.getElementsByName() 获取指定Name的所有元素的节点列表
document.getElementsByTagName() 获取带有指定标签名称的所有元素的节点列表
注意:getElementsByClassName() 在 Internet Explorer 5,6,7,8 中无效
示例:通过DOM的JavaScript脚本获取元素
js='return document.getElementById("query")'js='return document.getElementsByClassName("sec-input")[0]'js='return document.getElementsByName("query")[0]'js='return document.getElementsByTagName("input")[0]'js='return document.getElementById("sf").getElementsByTagName("input") ' # id=sf的input子元素element=driver.execute_script(js) # 执行js获取元素
注意:由于getElements返回的为列表所以需要使用[0]指定为第1个元素,如果查找出对应元素存在多个可以指定第几个。
2、JQuery获取元素
JQuery获取元素也是通过返回值获取,比DOM的兼容性高。
常用语法格式如下:
return $("p:contains('包含的字符')")[0] 根据页面文本获取元素
return $(css定位)[0] css定位获取对象
return $x(xpath定位)[0] xpath定位获取对象
示例:
js = 'return $("input[name=w]+input")[0]'js = 'return $("form#sf input[type=text]")[0]'js = 'return $x("//input[@name=\'w\']/following-sibling::input")[0]'js='$("p:contains(\'搜狗搜索APP\')")[0]'element=driver.execute_script(js) # 执行js获取元素
附件:JQuery选择器
来自于:
1.15JavaScript操作元素对象
avaScript操作元素对象可以使用DOM操作元素,如果应用有JQuery可以使用JQuery操作元素对象。
selenium运行JavaScript有两种形式,一种是接收JavaScript脚本语言,另一种是将WebElement传入JavaScript中执行脚本。如下:
driver.execute_script("window.open(';)")driver.execute_script('arguments[0].scrollIntoViewIfNeeded(true);',element)
1、打开新窗口
DOM操作:
window.open(";)
2、滚动浏览器滚动条
DOM操作:
document.body.scrollWidth; //网页正文全文宽,包括有滚动条时的未见区域document.body.scrollHeight; //网页正文全文高,包括有滚动条时的未见区域document.documentElement.clientWidth; //可见区域宽度,不有滚动条时的未见区域document.documentElement.clientHeight; //可见区域高度,不有滚动条时的未见区域document.documentElement.scrollTop=100; //设置或返回匹配元素相对滚动条顶部的偏移document.documentElement.scrollLeft=100 ; //设置或返回匹配元素相对滚动条左侧的偏移window.scrollTo(100,400); //设计滚动条left=100,top=400document.getElementsByClassName("name")[0].scrollIntoViewIfNeeded(true) //滚动到name元素显示
JQuery操作:
JQueryelement.height() 设置或返回匹配元素的高度
JQueryelement.width() 设置或返回匹配元素的宽度
JQueryelement.scrollTop() 设置或返回匹配元素相对滚动条顶部的偏移。
JQueryelement.scrollLeft() 设置或返回匹配元素相对滚动条左侧的偏移。
示例:
$(window).scrollTop(300); //拖动页面距离顶部300像素$(document).scrollTop(300) $("html,body").scrollTop(300); $(window).scrollTop(document.body.scrollHeight); //拖动到底部$(document).scrollTop($(window).height()); //拖动到底部
3、拖动窗口内元素滚动条
DOM操作:
document.getElementsByClassName("scroll")[0].scrollTop=10000 document.getElementsByClassName("scroll")[0].scrollLeft=10000
JQuery操作:
$("div.id").scrollTop(300); $("div.id").scrollLeft(300);
4、新增与修改元素属性
DOM操作:
改变属性
document.getElementById('query').value='selenium' // 设置元素值,如果是输入框则输入内容document.getElementsByClassName("sec-input")[0].disabled=false // 取消置灰
使元素隐藏或可见
document.getElementById("query").style.display="none" // 隐藏document.getElementById("query").style.display="block" // 可见
JQuery操作:
JQueryelement.attr() 设置或返回匹配元素的属性和值。
$("#query").attr('value','selenium') //设置元素值,如果是输入框则输入内容$("#query").attr('disabled',false) //取消置灰$("#query").attr('style','display: none;') // 隐藏
$("#query").attr('style','display: block;') # 可见
5、删除元素属性
DOM操作:移除元素属性
document.getElementById("query").removeAttribute('readonly') // 移除'readonly'属性,是元素可输入document.getElementById('query').value // 获取value值
JQuery操作:移除元素属性
JQueryelement.removeAttr() 从所有匹配的元素中移除指定的属性。
$("#query").removeAttr('readonly') // 移除'readonly'属性,是元素可输入
6、获取元素的内容
DOM操作:
document.getElementById("query").innerHTML // 获取HTML内容document.getElementsByClassName('top-nav')[0].innerText // 获取文本内容document.getElementsByClassName("sec-input")[0].attributes.属性 //获取元素属性
JQuery操作:
JQueryelement.html() 设置或返回匹配的元素集合中的 HTML 内容。
JQueryelement.val() 设置或返回匹配元素的value属性值
JQueryelement.text() 设置或返回匹配元素的内容。
$('.top-nav').html() // 获取HTML$('.top-nav').text() // 获取text$('#query').val() //获取val值
7、操作页面元素
DOM操作:
document.getElementById('stb').click() // 单击元素
JQuery操作:
$('#stb').click()
8、传入WebElement元素对象js操作
js=’arguments[0].click()’driver.execute_script(js,element)
注意:execute_script接收两个参数arguments[0] 表示元素,element为需要传入的元素
示例:搜狗浏览器输入值
element=driver.find_element_by_id('query')driver.execute_script('arguments[0].value="selenium"',element)
示例:符文框输入带html格式的值
driver.get(';) # 打开网页driver.switch_to.frame(driver.find_element_by_xpath('//div[@id="edui1_iframeholder"]/iframe')) # 切换iframeWebDriverWait(driver, 15).until(lambda driver: driver.find_element_by_css_selector('body.view'))element = driver.find_element_by_css_selector('body.view') driver.execute_script('arguments[0].innerHTML="<b>selenium</b><br><p>selenium<p>"', element)
示例:滚动条拖动到元素位置
driver.get(';) element=driver.find_element_by_id('auto')driver.execute_script('arguments[0].scrollIntoViewIfNeeded(true);',element)1.16cookie 处理
river.get_cookies() # 获得cookie 信息
driver.get_cookies(name) # 获得对应name的cookie信息
add_cookie(cookie_dict) # 向cookie 添加会话信息
delete_cookie(name) # 删除特定(部分)的cookie
delete_all_cookies() # 删除所有cookie
示例:
from selenium import webdriverdriver=webdriver.Chrome()driver.get(';)cookies = driver.get_cookies() # 获得所有cookie 信息print('删除前cookies:',cookies) # 打印cookie信息driver.add_cookie({'name': 'key-name', 'value': 'value-123456'}) #添加cookie信息print('key-name cookie信息:',driver.get_cookie('key-name')) # 查看添加的key-name的cookie信息driver.delete_cookie("key-name") # 删除一个特定的cookiedriver.delete_all_cookies() # 删除所有cookieprint('删除后cookies:',driver.get_cookies())driver.quit()2.unittest单元测试框架2.1 unittest单元测试实例
创建计算器类calculator
# Calculator.pyclass calculator(object): def __init__(self, a, b): self.a = a self.b = b def add(self): return (self.a + self.b) def minus(self): return (self.a - self.b) def multip(self): return (self.a * self.b) def divide(self): return (self.a / self.b)
创建一个简单的单元测试用例
import unittest # 导入unittest 包from unittest_doc.com.Calculator.Calculator import calculator # 引入需要测试的包# 所有用例需继承TestCase类或者其子类class simple_test(unittest.TestCase): def setUp(self): print('@@@初始化test_simple@@@') self.a = calculator(1, 2) def test_add(self): print('---测试用例test_simple add---') self.assertEqual(self.a.minus(), -1, '两值不相等') self.assertEqual(self.a.add(), 3, '两值不相等') self.assertNotEqual(self.a.divide(), 1, '两值不相等') def test_divide(self): print('---测试用例test_simple divide---') self.assertEqual(self.a.divide(), 0.5) def tearDown(self): print('@@@结束test_simple@@@')if __name__ == '__main__': unittest.main()
运行结果:
@@@初始化test_simple@@@---测试用例test_simple add---@@@结束test_simple@@@@@@初始化test_simple@@@---测试用例test_simple divide---@@@结束test_simple@@@2.2 TestCase详解
测试用例由setUp(),test_add(),test_divide(),tearDown() 4个部分组成,它们放在一个继承于unittest.TestCase 的测试类下。
2.2.1继承
unittest提供一个基类TestCase,如果我们要编写一个测试用例,就需要继承这个抽象基类,这样当我们运行测试程序时它会自动的运行这些测试用例。
2.2.2测试方法的名称
测试方法要以test开头,这样测试程序能够自动找到要运行的方法,在上述例子中包含3个测试方法,
test_add_5_5test_bool_valuetest_raise
2.2.3setUp和tearDown
setUp() 用于测试用例执行前的准备工作。如测试用例中需要访问数据库,可以在setUp中建立数据库连接并进行初始化;用例需要使用web,可以先实例化浏览器;app测试需先要启动app,可先实例化app。
tearDown() 用于用例执行之后的善后工作。如关闭数据库连接,关闭浏览器,关闭app。当用例没运行成功是他也会执行。
setUpClass() 所有测试用例运行前运行,必须使用@classmethod装饰器装饰,在setUp()方法前执行,整个测试过程只执行一次,主要作用是单元测试前的准备工作。
tearDownClass() 所有测试用例运行后运行,必须使用@classmethod装饰器装饰,在tearDown()方法后执行,整个测试过程只执行一次,主要作用是单元测试后的清理工作。
2.2.4断言
assertEqual()来检查预期的输出;调用assertTrue()或assertFalse()来验证一个条件;调用assertRaises()来验证抛出了一个特定的异常。
2.3TestSuite测试套件
2.3.1TestSuite 测试套件简介
对一个功能的验证往往是需要很多多测试用例,可以把测试用例集合在一起执行,这就产生了测试套件TestSuite 的概念,它是用来组装单个测试用例,规定用例的执行的顺序,而且TestSuite也可以嵌套TestSuite。
2.3.2初始化套件
suite = unittest.TestSuite()
2.3.3添加测试用例
把测试用例放入一个列表中suite = unittest.TestSuite() suite.addTest(simple_test('test_add')) suite.addTest(simple_test('test_divide'))用suite.addTests()把测试用例列表加入套件suite = unittest.TestSuite() tests = [Case('test_raise'), Case('test_bool_value'), Case('test_add_5_5')] suite.addTests(tests)unittest.makeSuite根据文件批量创建测试套件,如果一个文件中有非常多测试用例,可以根据用例名称的相似性创建测试套件。unittest.makeSuite(testCaseClass, prefix) #testCaseClass<Class类型>为测试用例类的名称 #prefix <str类型>用例相似的部分名称示例:suite = unittest.makeSuite(simple_test, 'test') # 创建并批量加载测试用例统计测试套件中的用例个数suite.countTestCases()2.4 TestLoader 加载测试用例
unittest.TestLoader()根据目录批量创建测试套件,可以指定用例存放目录,根据文件名称匹配测试用例。
注意:用例存放的子目录中必须具备init.py 文件,否则无法加载用例。
语法:
unittest.TestLoader().discover(start_dir, pattern='test\*.py', top_level_dir=None)*'''start_dir要测试的模块名或测试用例目录。pattern='test.py' 表示用例文件名的匹配原则。星号“*”表示任意多个字符。top_level_dir=None 测试模块的顶层目录。None <=> 测试用例不是放在多级目录中'''
示例:
suites=unittest.defaultTestLoader.discover('./testDirectory', pattern='*_test.py')
或
suites=unittest.TestLoader().discover('./testDirectory', pattern='*_test.py')2.5 TestsRunner 执行测试用例2.5.1TextTestRunner
创建测试套件后,执行测试用例使用unittest.TextTestRunner().run(TestSuite)
示例:执行加载simple_test用例的测试套件
suites = unittest.TestLoader().discover('./testDirectory', pattern='*_test.py') #加载测试用例runner = unittest.TextTestRunner(verbosity=2)runner.run(suites) # 执行测试用例
测试套件灵活运用
为测试用例文件添加suite 方法,方便加载测试套件
import unittest # 导入unittest 包from unittest_doc.com.Calculator.Calculator import calculator # 引入需要测试的包# 所有用例需继承TestCase类或者其子类class simple_test(unittest.TestCase): def setUp(self): print('@@@初始化test_simple@@@') self.a = calculator(1, 2) def test_add(self): print('---测试用例test_simple add---') self.assertEqual(self.a.minus(), -1, '两值不相等') self.assertEqual(self.a.add(), 3, '两值不相等') self.assertNotEqual(self.a.divide(), 1, '两值不相等') def test_divide(self): print('---测试用例test_simple divide---') self.assertEqual(self.a.divide(), 0.5) def tearDown(self): print('@@@结束test_simple@@@')def test_suite(): # 创建测试添加测试套件函数 suite = unittest.TestSuite() # 建立测试套件 suite.addTests([simple_test('test_add'), simple_test('test_divide')]) return suiteif __name__ == '__main__': runner = unittest.TextTestRunner(verbosity=2) runner.run(test_suite())嵌套测试套件,多个测试套件组合在一起
suite1 = unittest.TheTestSuite()suite2 = unittest.TheTestSuite()alltests = unittest.TestSuite((suite1, suite2))2.5.2 HTMLTextRunner示例
fp=open(filename, 'wb') # 写方式打开报告文件runner = HTMLTestRunner.HTMLTestRunner(stream=fp,title='报告标题',description='报告说明' )#执行测试runner.run(Suite) # Suite为TestSuite测试套件产生不同文件测试报告
#构建测试用例集suite=unittest.defaultTestLoader.discover('../testDirectory', pattern='*_test.py')#测试套件组合在一起now=time.strftime("%Y%m%d%H%M%S", time.localtime()) filename=r'./report/'+now+r'result.html' # 根据时间生成文件名with openopen(filename, 'wb') as fp: runner = HTMLTestRunner.HTMLTestRunner(stream=fp,title='报告标题',description='报告说明' ) runner.run(suite)#执行测试2.6跳过测试
class SkipCase(unittest.TestCase): def setUp(self): self.test_class = TestClass() @unittest.skip("Skip test.") def test_add_5_5(self): self.assertEqual(self.test_class.add(5, 5), 10) @unittest.skipIf(NUM < 3, "Skiped: the number is too small.") def test_bool_value(self): self.assertTrue(self.test_class.is_string("hello world!")) @unittest.skipUnless(NUM==3, "Skiped: the number is not equal 3.") def test_raise(self): self.assertRaises(KeyError, self.test_class.raise_error)
unittest中使用装饰器的方式来实现跳过测试与预计的失败,常用的主要有3中,
@unittest.skip:直接跳过测试用例;@unittest.skipIf:当满足条件时跳过测试用例;@unittest.skipUnless:只有满足某一条件时不跳过,其他的都跳过;2.7断言assert
assertEqual(a,b,[msg]):断言a和b是否相等,相等则测试用例通过。
assertNotEqual(a,b,[msg]):断言a和b是否相等,不相等则测试用例通过。
assertTrue(x,[msg]):断言x是否True,是True则测试用例通过。
assertFalse(x,[msg]):断言x是否False,是False则测试用例通过。
assertIs(a,b,[msg]):断言a是否是b,是则测试用例通过。
assertNotIs(a,b,[msg]):断言a是否是b,不是则测试用例通过。
assertIsNone(x,[msg]):断言x是否None,是None则测试用例通过。
assertIsNotNone(x,[msg]):断言x是否None,不是None则测试用例通过。
assertIn(a,b,[msg]):断言a是否在b中,在b中则测试用例通过。
assertNotIn(a,b,[msg]):断言a是否在b中,不在b中则测试用例通过。
assertIsInstance(a,b,[msg]):断言a是是b的一个实例,是则测试用例通过。
assertNotIsInstance(a,b,[msg]):断言a是是b的一个实例,不是则测试用例通过。
assertRaises(Exceptm,a,value,[msg]):value值是否有异常
msg='测试失败时打印的信息'
2.8参数化
2.8.1参数化代码 1.导包 unittest/parameterized 2.定义测试类 3.书写测试方法(用到的测试数据使用变量代替) 4.组织测试数据并传参
2.8.2代码实现
方式一:使用数组作为测试数据testcase3.py# 1.导包 unittest/parameterized
import unittest
from parameterized import parameterized
from tools import login
# 组织测试数据[(),(),()]or[[],[],[]]
data = [
('admin','123456','登录成功'),
('root','123456','登录失败'),
('admin','123123','登录失败')
]
# 2.定义测试类
class TestLogin(unittest.TestCase):
# 3.书写测试方法(用到的测试数据使用变量代替)
@parameterized.expand(data)
def test_login(self,username,password,expect):
self.assertEqual(expect,login(username,password))
# 4.组织测试数据并传参(装饰器@)
if __name__=="__main__":
unittest.main()方式二:使用Json文件作为测试数据data.json[
{
"desc":"正确的用户名和密码",
"username":"admin",
"password":"123456",
"expect":"登录成功"
},
{
"desc":"错误的用户名",
"username":"root",
"password":"123456",
"expect":"登录失败"
},
{
"desc":"错误的密码",
"username":"admin",
"password":"123123",
"expect":"登录失败"
},
{
"desc":"错误的用户名和密码",
"username":"root",
"password":"123123",
"expect":"登录失败"
}
]testcase4.py# 1.导包 unittest/parameterized
import json
import unittest
from parameterized import parameterized
from tools import login
# 组织测试数据[(),(),()]or[[],[],[]]
# "desc":"正确的用户名和密码",
# "username":"admin",
# "password":"123456",
# "expect":"登录成功"
def build_data():
with open('data.json',encoding="utf-8") as f:
result = json.load(f) #[{},{},{}]
data = []
for i in result: #i {}
data.append((i.get("expect"),i.get('username'),i.get("password")))
return data
# 2.定义测试类
class TestLogin(unittest.TestCase):
# 3.书写测试方法(用到的测试数据使用变量代替)
@parameterized.expand(build_data())
def test_login(self,expect,username,password):
self.assertEqual(expect,login(username,password))
# 4.组织测试数据并传参(装饰器@)
if __name__=="__main__":
unittest.main()3.自动化框架搭建tests 存放测试用例data 测试数据reports 测试报告logs 日志文件config 处理配置文件path等common 所有项目通用的代码
根目录下放:
readme 自动化测试项目的说明文件run.py 项目入口主程序
标签: #pythonweb自动化测试