龙空技术网

Web自动化测试

自在春风xyz 133

前言:

此时朋友们对“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")   #  #表示id
1.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 result
1.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自动化测试