一、selenium介绍
selenium主要用于web应用程序的自动化测试,还支持所有基于web的管理任务自动化。
selenium经历了2个版本,selenium1.0和selenium2.0;selenium不是一个单独的工具,而是由一些插件、类库构成,每个组成部分都有其特点和应用场景。
selenium2.0由以下组件构成:
selenium2.0 = selenium1.0 + Webdriver
Webdirver:通过原生浏览器支持或扩展来直接控制浏览器,针对各个浏览器开发,与浏览器紧密集成,支持创建更高级的测试,其还可以利用操作系统级的调用,模拟用户输入;
selenium IDE:嵌入到Firefox浏览器中的一个插件,实现简单的浏览器操作录制与回放功能,主要用于快速创建BUG及重现脚本,可转化为多种语言;
selenium Gird:测试辅助工具,利用现有的计算机基础设施,实现多台计算上和异构环境中运行测试用例;
selenium RC:selenium的核心组件,支持多种不同语言编写自动化测试脚本,通过其服务器作为代理服务器去访问应用,达到测试的目的;
Client Libraries:Client Libraries库主要用于编写测试脚本,用来控制Selenium Server的库;
Selenium Server:负责控制浏览器行为;
Selenium Core(一个JavaScript函数集合):被嵌入到浏览器中,通过它实现用程序对浏览器进行操作;
Launcher:用于启动浏览器,把Core加载到浏览器页面当中,并把浏览器代理设置为Selenium Server的HTTP Proxy;
二、环境搭建
1、安装python
登录Python官网,找到download,选择与自身平台(Windows/Linux)相符的版本下载(建议3.5+),然后安装即可;
注意:安装时选择安装界面的“Add Python 3.x to PATH”进行勾选,避免再次配置环境变量;
安装完成后通过Windows命令提示符CMD输入“python”,查看是否安装成功,如下图所示:
如上图所示,则证明安装成功;
2、安装setuptools与pip
setuptools是PEAK(Python enterprise Application Kit)的一个副项目,是python的distutilsde的增强工具,可以更方便创建和发布python包,特别是对其他包有依赖的情况;
pip是一个安装和管理python包的工具,通过pip来安装python包将变得很简单,省去了繁琐的过程,pip的安装依赖于setuptools,安装pip之前需要先安装setuptools;
注意:python目前不支持setuptools,因此需要使用distribute;
setuptools与pip的下载地址如下:
setuptools:https://pypi.python.org/pypi/setuptools
pip:https://pypi.org/project/pip/
注意: 最新版的python安装包中已经集成了pip,可以在安装目录下的script路径下查看是否有pip.exe或pip3.exe文件,如果有,则cmd命令行中输入pip进行验证;
如上图所示,则证明已经安装pip;
3、安装selenium
完成上面2个步骤之后,可以通过cmd命令直接安装selenium包,如下图所示:
注意:安装时如果只输入包名,则默认安装当前库中的最新版本,如果想安装自己需要的版本,则需要在包名后面加上版本号,比如:
pip install selenium==2.48.0
4、下载浏览器驱动
前面说过,selenium支持多种浏览器,所以只需要下载对应的浏览器驱动,将解压得到的exe文件放到python的安装目录下即可;
各个浏览器驱动下载地址:https://www.seleniumhq.org/download/
5、调试
打开一款python编译器,输入下面的代码,运行,查看是否成功调用浏览器运行,如果运行成功,则说明已成功搭建好自动化开发环境;
一、WebDriver原理
1、关于WebDriver
设计模式:按照Server-Client的经典设计模式设计;
Server端:即Remote Server(远程服务器),可以是任意的浏览器,当脚本启动浏览器时,该浏览器就是Remote Server,它的职责是等待Client发送请求并做出响应;
Client端:简单来说就是我们的测试代码,测试代码中的一些行为是以HTTP请求的方式发送给被测试浏览器——Remote Server,Remote Server接受请求,执行相应操作,
并在Response中返回执行状态、返回值等信息;
2、WebDriver工作流程
①WebDriver启动目标浏览器,并绑定至指定端口,启动的浏览器实例将作为WebDriver的Remote Server;
②Client端通过CommandExcuter发送HTTPRequest给Remote Server的侦听端口(通信协议:the webdriver wire protocol);
③Remote Server需要依赖原生的浏览器组件(比如:chromedriver.exe)来转化浏览器的native调用;
3、WebDriver.log
python提供了logging模块给运行中的应用,提供了一个标准的信息输出接口。它提供了basicConfig方法用于基本信息的定义,开启debug模块,
就可以捕捉到Client端向Server端发送的请求,例子如下:
1 # coding=utf-8 2 # 导入logging模块,捕捉Client发送的请求 3 from selenium import webdriver 4 import logging 5 from selenium import webdriver 6 from selenium.webdriver.support.select import Select # select类 7 from selenium.webdriver.common.by import By #By类:定位元素 8 9 logging.basicConfig(level=logging.DEBUG) 10 driver = webdriver.Chrome("F:\安装工具\python\chromedriver.exe") 11 driver.get("www.baidu.com") 12 13 driver.find_element_by_id("kw").send_keys("selenium") 14 driver.find_element_by_id("su").click() 15 driver.quit()
二、WebDriver定位方法
WebDriver是基于selenium设计的操作浏览器的一套API,针对多种编程语言都实现了这套API,站在python角度来说,WebDriver是python的一个用于实现Web自动化的第三方库。
1、WebDriver定位方法
WebDriver定位方法提供了八种元素定位方法,所对应的方法、特性分别是:
2、XPath和CSS的类似功能对比
3、用By定位元素
针对前面介绍的8种定位方法,WebDriver还提供另一种方法,即:统一调用find_element()方法,通过By来声明定位方法,并且传入对应定位方法的定位参数,例子如下:
find.element()方法只用于定位元素,它需要两个参数,第一个参数是定位的类型,由By提供,第二个参数是定位的具体方式,在使用By之前需要将By类导入;
# 导入By类的包 from selenium.webdriver.common.by import By find.element(by.id,"kw") find.element(by.name,"wd") find.element(by.class_name,"s_ipt") find.element(by.tag_name,"input") find.element(by.link_text,"新闻") find.element(by.partial_link_text,"新") find.element(by.xpath,"//*[@class=‘bg s_btn‘") find.element(by.css_selector,"span.bg s_btn_wr>input#su")
4、定位一组元素
上面提到的8种定位方法,都是针对单个元素定位的,webdriver还提供了与之对应的8种用于定位一组元素的方法。其一般应用于以下场景:
①批量操作元素,例如勾选页面上所有的复选框;
②先获取一组元素,再从这组元素中过滤出需要操作的元素;
定位一组元素的方法与定位单个元素的用法相似,唯一的区别是在element后面多一个s表示复数,具体如下:
# webdriver提供的定位一组元素方法 id find_elements_by_id() Name find_elements_by_name() class_name find_elements_by_class_name() tag Name find_elements_by_tag_name() link text find_elements_by_link_text() partial link text find_elements_by_partial_link_text() xpath find_elements_by_xpath() css selector find_elements_by_css_selector()
获取一组元素中某个元素的几个方法:
len():用来计算元素的个数,通过print()打印出计算的结果;
pos()或pop(-1):默认获取一组元素的最后一个元素,并返回该元素的值;
pop(0):默认获取一组元素的第一个元素,并返回该元素的值;
pop(1):默认获取一组元素的第二个元素,并返回该元素的值;
......
三、WebElement接口常用方法
通常需要与页面交互的方法都由WebElement接口提供,包括上面提到的8种定位方法,下面介绍常用的几种方法:
submit():用于提交表单,例如搜索框输入关键字之后的“回车”操作,例如:
# 提交表单 from select import webdriver driver = webdriver.Chrome("安装工具\python\chromedriver.exe") driver.get("http://www.baidu.com") driver.find_element_by_id("kw").send_keys("imyalost") # 提交输入框中的内容 driver.find_element_by_id("imyalost").submit() driver.quit()
注意:有时候submit()方法和click()方法可以互用,但submit()的应用范围不及click()广泛;
clear():清除文本;
send_keys(*value):模拟按键输入;
click():单击元素;
size:返回元素的尺寸;
text:获取元素的文本;
get.attribute(name):获得属性值;
is_displayed():设置该元素是否用户可见;
# webelement接口常用方法 from selenium import webdriver driver = webdriver.Chrome("安装工具\python\chromedriver.exe") driver.get("http://www.baidu.com") # 获得输入尺寸 size = driver.find_element_by_id("kw").size print("size") # 返回百度页面底部备案信息 text = driver.find_element_by_id("cp").text print("text") # 返回元素的属性值,可以是id、name、type或其他属性 attribute = driver.find_element_by_id("kw").get_attribute("type") print("attribute") # 返回元素结果是否可见,返回结果为True或Flase result = driver.find_element_by_id("kw").is_displayed() print("result")
一、控制浏览器
webdriver主要提供操作页面上各种元素的方法,但它也提供操作浏览器的一些方法,例如控制浏览器大小、前进和后退等。
1、控制浏览器窗口大小
# 控制浏览器大小 from selenium import webdriver driver = webdriver.Chrome("安装工具\python\chromedriver.exe") driver.get("http://www.baidu.com") # 参数数字为像素点 print("设置浏览器宽480、高800显示") driver.set_window_size(480,800)
2、全屏显示
webdriver提供了maximize_window()方法使打开的浏览器全屏显示,其用法与set_window_size()相同。
3、控制浏览器前进、后退
现在的浏览器在浏览网页时都提供了前进和后退功能,webdriver也提供了对应的forward()和back()方法,来模拟前进和后退按钮:
# 控制浏览器前进、后退 from selenium import webdriver driver = webdriver.Chrome("安装工具\python\chromedriver.exe") # 访问百度首页 first_url=‘http://www.baidu.com‘‘ print("now access %s "%(first_url)) driver.get(first_url) # 访问新闻页面 second_url=‘http://www.news.baidu.com‘ print("now access % s "%(second_url)") driver.get("second_url") # 后退到百度首页 print("back to %s "%(first_url)") driver.back() # 前进到新闻页 print("forward to %s "%(second_url)") driver.forward()
为了看清脚本执行过程,每一步的操作都通过print()打印当前的URL地址,执行结果如下:
now access http://www.baidu.com
now access http://news.baidu.com
back to http://www.baidu.com
froward to http://news.baidu.com
4、模拟浏览器前刷新
一般我们刷新页面都是通过F5或者页面上的刷新按钮,webdriver也提供了刷新方法refresh(),用来模拟页面刷新:
......
# 刷新当前页面
driver.refresh()
......
二、鼠标事件
在webelement接口提供的方法中,可以通过click()来模拟鼠标单击操作,但实际上鼠标交互方式很多,例如:右击、悬停、鼠标拖动等功能;
webdriver提供了ActionChains类,封装了鼠标操作的常用方法:
perform():执行所有的ActionChains中存储的行为
context_click():鼠标右击
double_click():鼠标双击
drag_and_drop():鼠标拖动
move_to_element():鼠标悬停
1、鼠标右击操作
# 鼠标右击操作 from selenium import webdriver from selenium.webdriver.common.action_chains import ActionChains driver = webdriver.Chrome("安装工具\python\chromedriver.exe") driver.get("http://www.baidu.com") # 定位到要右击的元素 right_click = driver.find_element_by_id("KW") # 对定位到的元素执行鼠标右击操作 ActionChains(driver).context_click(right_click).perform() ...
2、鼠标悬停
鼠标悬停弹出下拉菜单也是一个十分常见的功能设计,move_to_element()方法可以模拟鼠标悬停动作,其用法与context_click()相同;
1 # 鼠标悬停 2 ... 3 above = driver.find_element_by_id("id") 4 ActionChains(driver).move_to_element(above).perform() 5 ...
3、鼠标双击操作
double_click()方法用于模拟鼠标双击操作;
1 # 鼠标双击操作 2 ... 3 double_click = driver.find_element_by_id("id") 4 ActionChains(driver).double_click(double_click).perform() 5 ...
4、鼠标拖放操作
drag_and_drop(source,target)在源元素上按住鼠标左键,然后移动到目标元素上释放;
source:鼠标拖动的源元素
target:鼠标释放的目标元素
# 定位元素的位置 ... element = driver.find_element_by_id("id") # 定位元素要移动到的目标位置 target = driver.find_element_by_id("xx") # 执行元素的拖放操作 ActionChains(driver).drag_and_drop(element,target).perform() ...
三、键盘事件
Keys()类提供了键盘上几乎所有的按键方法,send_keys()不见可以模拟键盘输入,还可以用来输入键盘上的按键,甚至是组合键,例子如下:
# 模拟键盘事件 from selenium import webdriver # 引入keys模块 from selenium.webdriver.common.keys import Keys driver = webdriver.Chrome("安装工具\python\chromedriver.exe") driver.get("http://www.baidu.com") # 输入框输入内容 driver.find_element_by_id("kw").send_keys("selenium") # 输入“教程” driver.find_element_by_id("kw").send_keys("教程") # 删除“教程” driver.find_element_by_id("kw").send_keys(Keys.BACK_SPACE) ...
以下为常用的键盘操作:
# 常用的键盘操作 send_keys(Keys.BACK_SPACE) send_keys(Keys.SPACE) send_keys(Keys.TAB) send_keys(Keys.ESCAPE) send_keys(Keys.ENTER) send_keys(Keys.CONTROL,‘a‘) send_keys(Keys.CONTROL,‘c‘) send_keys(Keys.CONTROL,‘v‘) send_keys(Keys.CONTROL,‘x‘) send_keys(Keys.F1) ... send_keys(Keys.F12)
以上为webdriver的控制浏览器操作以及模拟键盘、鼠标操作的常用方法,当然具体在实际使用过程中,还需要结合实际的业务场景,灵活运用
在编写自动化测试脚本时,为了使“机器”去自动辨识test case的执行结果是True还是False,一般都需要在用例执行过程中获取一些信息,来判断用例的执行时成功还是失败。
判断成功失败与否,就涉及到断言。webdriver的断言使用有三种模式:操作(action)、辅助(accessors)、断言(assertion)。
1、操作(action)
模拟用户与Web应用程序的交互,一般用于操作应用程序的状态;
如点击链接,选择选项的方式进行工作;如果一个动作执行失败,或是有错误,当前的测试将会停止执行。
常见命令如下:
open(打开页面)
click(点击)
clickAndWait(点击并等待)
type(文本类型)
select(选择下拉菜单)
selectWindow(选择弹出窗口)
pause(等待指定时间,以毫秒为单位,即要睡眠的时间)
setSpeed(设定执行速度。以毫秒延迟间隔长度。默认没有延迟,即为0)
setTimeout(指定等待动作完成的等待时间。默认为30秒,需要等待的动作包括了OPEN 和WAITFOR)
goBack(模拟用户点击其浏览器上的“back”按钮)
close(模拟用户点击弹出窗体或表单标题栏上的”关闭”按钮)
2、辅助(accessors)
辅助工具,用于检查应用程序的状态并将结果存储到变量中;
如:storeElementPresent(locator,variableName)
其中参数locator表示元素定位器,variableName用于存储结果的变量名;
即将locator定位到的状态存储到variableName变量中,如果该元素出现返回true,否则返回false,可同断言一同使用。
3、断言(assertion)
验证应用程序的状态是否同所期望的一致。
常见的断言包括:验证页面内容,如标题是否为X或当前位置是否正确,或是验证该复选框是否被勾选。
常用断言如下:
assertLocation(判断当前是在正确的页面)
assertTitle(检查当前页面的title是否正确)
assertValue(检查input的值, checkbox或radio,有值为”on”无为”off”)
assertSelected(检查select的下拉菜单中选中是否正确)
assertSelectedOptions(检查下拉菜单中的选项的是否正确)
assertText(检查指定元素的文本)
assertTextPresent(检查在当前给用户显示的页面上是否有出现指定的文本)
assertTextNotPresent(检查在当前给用户显示的页面上是否没有出现指定的文本)
assertAttribute(检查当前指定元素的属性的值)
assertTable(检查table里的某个cell中的值)
assertEditable(检查指定的input是否可以编辑)
assertNotEditable(检查指定的input是否不可以编辑)
assertAlert(检查是否有产生带指定message的alert对话框)
waitForElementPresent (等待检验某元素的存在,为真时,则执行)
使用断言的注意点:
①不要使用断言作为公共方法的参数检查,公共方法的参数永远都要执行;
②断言语句不可以有任何边界效应,不要使用断言语句去修改变量和改变方法的返回值;
在UI自动化测试中,有时候会遇到页面元素无法定位的问题,包括xpath等方法都无法定位,是因为前端元素被设置为不可见导致。
1、具体问题
常见的页面元素不可见导致的不可定位,都是由于下面的问题:
通过查看相关文档,可以看出display:none方法是设置元素不可见,这就是导致为什么通过定位页面元素无法定位的原因。
2、解决方案
对于这种问题,可以通过JavaScript修改页面元素属性来将元素置位可见,然后通过id、classname等方法去定位,示例代码如下(针对上图所示):
js = "document.getElementById(\"txtPassword\").style.display=‘block‘;" # 调用js脚本 driver.execute_script(js) sleep(3) driver.find_element_by_id("txtPassword").send_keys("123456")
代码解析:
首先通过selenium封装好的方法document去找到display元素,document提供以下方法来定位display元素:
getElementById():返回对指定ID第一个对象的引用
getElementsByName() :返回带有指定名称的对象集合
getElementsByTagName():返回带有指定标签名的对象集合
上面我定义了一个js变量,然后通过getElementById()方法去引用display元素,修改none属性为block属性(作为块级元素显示),然后通过selenium自带的execute_script方法执行脚本。
最后,当元素属性置为可见时,可以通过ID去定位元素。
其实还有一个解决方案:让前端修改display:none为block就好了,但这样的话,带来的变化和安全风险又是需要考虑的问题。一个问题的解决总是伴随着新的问题,核裂变了解一下?
想起今天和同行聊天时说起的分裂BUG的话题,对话如下:
大佬N:核裂变的原理是通过中子撞击原子核产生多个新的原子核,原子核是已有的BUG,中子是修改BUG加上的代码,分裂之后这个bug消失了,取而代之的是更多的原子核(BUG)。。。
我:引起一个BUG的原因可能是多个,修改一段代码可能造成多个BUG,就像用新技术解决旧问题而带来的新问题一个意思。。。
自动化本身最大的挑战还是变化,因此从分层测试角度结合公司项目具体情况,考虑解决问题的方法,才是最好的选择。
在利用selenium进行UI自动化测试过程中,经常会遇到下拉框选项,这篇博客,就介绍下如何利用selenium的Select模块来对标准select下拉框进行操作。。。
首先导入Select模块:
1 # coding=utf-8 2 from selenium import webdriver 3 from selenium.webdriver.support.select import Select
感兴趣的可以将鼠标指向Select,然后按住Ctrl鼠标单击,查看Select模块的源码,是如何定义封装Select的各个方法的。
1、Select提供了三种选择某一项的方法
1 select_by_index # 通过索引定位 2 select_by_value # 通过value值定位 3 select_by_visible_text # 通过文本值定位
注意事项:
index索引是从“0”开始;
value是option标签的一个属性值,并不是显示在下拉框中的值;
visible_text是在option标签中间的值,是显示在下拉框的值;
2、Select提供了三种返回options信息的方法
1 options # 返回select元素所有的options 2 all_selected_options # 返回select元素中所有已选中的选项 3 first_selected_options # 返回select元素中选中的第一个选项
注意事项:
这三种方法的作用是查看已选中的元素是否是自己希望选择的:
options:提供所有选项的元素列表;
all_selected_options:提供所有被选中选项的元素列表;
first_selected_option:提供第一个被选中的选项元素;
3、Select提供了四种取消选中项的方法
1 deselect_all # 取消全部的已选择项 2 deselect_by_index # 取消已选中的索引项 3 deselect_by_value # 取消已选中的value值 4 deselect_by_visible_text # 取消已选中的文本值
注意事项:
在日常的web测试中,会经常遇到某些下拉框选项已经被默认选中,这种时候就需要用到这里所说的四种方法;
下面以实际的代码来做个示例,被测试网页与源码截图如下:
比如要选择3线,那么三种选择方法示例代码如下:
# coding=utf-8 from selenium import webdriver from selenium.webdriver.support.select import Select from time import sleep # 登录 driver = webdriver.Chrome() ...... # 根据索引选择 Select(driver.find_element_by_name("storeDeclare.cityLine")).select_by_index("3") # 根据value值选择 Select(driver.find_element_by_name("storeDeclare.cityLine")).select_by_value("3线") # 根据文本值选择 Select(driver.find_element_by_name("storeDeclare.cityLine")).select_by_visible_text("3线") sleep(5) driver.quit()
以上就是关于selenium的Select模块提供的几种方法的用法,示例代码只是示例,具体实践还需要结合实际的工作需要来进行
UI自动化测试,大多都是通过定位页面元素来模拟实际的生产场景操作。但在编写自动化测试脚本中,经常出现元素定位不到的情况,究其原因,无非两种情况:1、有frame;2、没有设置等待。
因为代码运行速度和浏览器加载渲染速度,不是一个量级,所以导致了这种情况发生。webdriver提供了3种类型的等待:显式等待、隐式等待、强制等待。
1、显示等待
定义:等待某个条件成立时继续执行,否则在达到最大时长时抛出异常(TimeoutException);
WebDriverWait(driver,timeout,poll_frequency=0.5,ignored_exceptions=None) driver:浏览器驱动 timeout:最长超时时间 poll_frequency:检测间隔时间,默认0.5s ignored_exceptions:超时后的异常信息,默认情况抛出NoSuchElementException异常 WebDriverWait()一般由until()或until_not方法配合使用,下面是这两种方法的说明: until(method,message=‘‘):调用该方法提供的驱动程序作为一个参数,直到返回值为True; until_not(method,message=‘‘):调用该方法提供的驱动程序作为一个参数,直到返回值为Flase;
示例代码如下:
# coding = utf-8 from selenium import webdriver from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By driver = webdriver.Chrome("F:\安装工具\python\chromedriver.exe") driver.implicitly_wait(10) driver.get(‘http://www.cnblogs.com/imyalost/‘) locator = (By.LINK_TEXT, ‘老_张‘) try: WebDriverWait(driver, 20, 0.5).until(EC.presence_of_element_located(locator)) print(driver.find_element_by_link_text(‘老_张‘).get_attribute(‘href‘)) finally: driver.close()
代码解析:
本例中,通过as关键字将expected_conditions重命名为EC,并调用presence_of_element_located()方法判断元素是否存在;
上面的例子中,同时使用了隐性等待和显性等待,但是需要注意的是:等待的最长时间取两者之中的最大值;
title_is: 判断当前页面的title是否完全等于(==)预期字符串,返回布尔值 title_contains : 判断当前页面的title是否包含预期字符串,返回布尔值 presence_of_element_located : 判断某个元素是否被加到了dom树里,并不代表该元素一定可见 visibility_of_element_located : 判断某个元素是否可见. 可见代表元素非隐藏,并且元素的宽和高都不等于0 visibility_of : 跟上面的方法做一样的事情,只是上面的方法要传入locator,这个方法直接传定位到的element就好了 presence_of_all_elements_located : 判断是否至少有1个元素存在于dom树中。举个例子,如果页面上有n个元素的class都是‘column-md-3‘,那么只要有1个元素存在,这个方法就返回True text_to_be_present_in_element : 判断某个元素中的text是否 包含 了预期的字符串 text_to_be_present_in_element_value : 判断某个元素中的value属性是否 包含 了预期的字符串 frame_to_be_available_and_switch_to_it : 判断该frame是否可以switch进去,如果可以的话,返回True并且switch进去,否则返回False invisibility_of_element_located : 判断某个元素中是否不存在于dom树或不可见 element_to_be_clickable : 判断某个元素中是否可见并且是enable的,这样的话才叫clickable staleness_of : 等某个元素从dom树中移除,注意,这个方法也是返回True或False element_to_be_selected : 判断某个元素是否被选中了,一般用在下拉列表 element_selection_state_to_be : 判断某个元素的选中状态是否符合预期 element_located_selection_state_to_be : 跟上面的方法作用一样,只是上面的方法传入定位到的element,而这个方法传入locator alert_is_present : 判断页面上是否存在alert
2、隐式等待
定义:通过设定的时长等待页面元素加载完成,再执行下面的代码,如果超过设定时间还未加载完成,则继续执行下面的代码(注意:在设定时间内加载完成则立即执行下面的代码);
隐式等待的方法为:implicitly_wait,示例代码如下:
# coding = utf-8 from selenium import webdriver driver = webdriver.Chrome("F:\安装工具\python\chromedriver.exe") driver.implicitly_wait(10) # 隐性等待,最长等10秒 driver.get(‘http://www.cnblogs.com/imyalost/‘) print(driver.current_url) driver.quit()
代码解析:
本例中,设置的等待时长为10秒,但这10秒并非一个固定时间,并不影响脚本执行速度;其次,隐式等待对整个driver的周期都起作用,因此只需要设置一次即可。
3、强制等待
即sleep()方法,由python中的time模块提供,强制让代码等待xxx时间,无论前面的代码是否执行完成或者还未完成,都必须等待设定的时间。
示例代码如下:
# coding = utf-8 from selenium import webdriver from time import sleep driver = webdriver.Chrome("F:\安装工具\python\chromedriver.exe") driver.get(‘http://www.cnblogs.com/imyalost/‘) sleep(5) print(driver.current_url) driver.quit()
代码解析:
本例中,设置强制等待时间为5秒,5秒之后,打印获取到的当前页面的url,然后关闭窗口。
这种强制等待的方法,在debug时候很有用,不过建议慎用这种方法,因为太死板,严重影响程序执行速度!
以上三种等待方法,在具体的场景中需要根据情况选择合适的方法,灵活运用。。。
自动化测试过程中,获得用例的执行结果后,需要有具象化、简洁明了的测试结果,比如:用例执行时间、失败用例数、失败的原因等,这时候,就需要用到测试报告。
HTML测试报告是python语言自带的单元测试框架,其扩展的HTMLTestRunner模块可用于生成易于使用的HTML测试报告。
1、HTMLTestRunner下载
下载地址:http://tungwaiyip.info/software/HTMLTestRunner.html
下载完成后,将下载的文件保存到C盘的\Python35\Lib目录下(可以通过如下命令获取python安装目录):
①进入cmd命令行
②输入python
③输入import sys
④输入print(sys.path)
C:\Users\dell>python Python 3.5.1 (v3.5.1:37a07cee5969, Dec 6 2015, 01:54:25) [MSC v.1900 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> import sys >>> print(sys.path) [‘‘, ‘C:\\Users\\dell\\AppData\\Local\\Programs\\Python\\Python35\\python35.zip‘, ‘C:\\Users\\dell\\AppData\\Local\\Programs\\Python\\Python35\\DLLs‘, ‘C:\\Users\\dell\\AppData\\Local\\Programs\\Python\\Python35\\lib‘, ‘C:\\Users\\dell\\AppData\\Local\\Programs\\Python\\Python35‘, ‘C:\\Users\\dell\\ AppData\\Local\\Programs\\Python\\Python35\\lib\\site-packages‘]
2、修改HTMLTestRunner文件
因为HTMLTestRunner是基于python2开发的,为了使其支持python3的环境,需要对其中的部分内容进行修改,修改后的内容如下:
# HTMLTestRunner修改内容 # 第94行 import io # 第539行 self.outputBuffer = io.StringIO() # 第631行 print(sys.stderr, ‘\nTime Elapsed: %s‘ % (self.stopTime-self.startTime)) # 第642行 if not cls in rmap: # 第766行 uo = o # 第772行 ue = e
3、python文件执行与调用
①python文件的后缀为.py
②py文件既可以用来执行,就像一小段程序,也可以用来作为模块被导入
③在python中导入模块一般用import
代码如下:
from selenium import webdriver import unittest import time class MyTest(unittest.TestCase): def setUp(self): self.driver = webdriver,Chrome("F:\安装工具\python\chromedriver.exe") self.driver.maximize_window() self.driver.implicitly.wait(10) self.base_url = "http://www.baidu.com" def test_baidu(self): driver = self.driver driver.get(self.base_url + "/") driver.find_element_by_id("kw").clear() driver.find_element_by_id("kw").send_key("unittest") driver.find_element_by_id("su").click() time.sleep(2) title = assertEqual(title,"unittest_百度搜索") def tearDown(self): self.driver.quit() if __name__ == "__main__": unittest.main()
4、HTMLTestRunner测试报告
以上面的test_baidu.py文件为例子,生成HTMLTestRunner测试报告,代码如下:
from selenium import webdriver import unittest from HTMLTestRunner import HTMLTestRunner class Baidu(unittest.TestCase): def setUp(self): self.driver = webdriver.Chrome("F:\安装工具\python\chromedriver.exe") self.driver.implicitly_wait(10) self.base_url = "http://www.baidu.com/" def test_baidu_search(self): driver = self.driver driver.get(self.base_url) driver.find_element_by_id("kw").send_key("HTMLTestRunner") driver.find_element_by_id("su").click() def tearDown(self): self.driver.quit() if __name__ == "__main__": baidu = Baidu("test_baidu_search") testunit = unittest.TestSuite() testunit.addTest(baidu) # 定义报告存放路径 fp = open(‘./result.html‘, ‘wb‘) # 定义测试报告 runner = HTMLTestRunner(stream=fp, title=‘百度搜索测试报告‘, description= ‘用例执行情况:‘) runner.run(testunit) #运行测试用例 fp.close() #关闭报告文件
代码简析:
①将HTMLTestRunner模块用import导入
②通过open()方法以二进制写模式打开当前目录下的result.html,如果没有则自动创建该文件
③调用HTMLTestRunner模块下的HTMLTestRunner类,stream指定测试报告文件,title用于定义测试报告的标题,description用于定义测试报告的副标题
④通过HTMLTestRunner的run方法运行测试套件中所组装的测试用例,最后通过close()关闭测试报告文件
随着软件不断迭代功能越来越多,对应的测试用例也会呈指数增长。一个实现几十个功能的项目,对应的用例可能有上百个甚至更多,如果全部集成在一个文件中,那么这个文件就很臃肿且维护麻烦。
一个很好的方法就是将这些用例按照功能类型进行拆分,分散到不同测试文件中,即一个项目,对应多个分支。
一、分拆后的实现代码
1、testbaidu.py
from selenium import webdriver import unittest import time class MyTest(unittest.TestCase): def setUp(self): self.driver = webdriver.Chrome("F:\安装工具\python\chromedriver.exe") self.driver.maximize_window() self.driver.implicitly.wait(10) self.base_url = "http://www.baidu.com" def test_baidu(self): driver = self.driver driver.get(self.base_url + "/") driver.find_element_by_id("kw").clear() driver.find_element_by_id("kw").send_key("unittest") driver.find_element_by_id("su").click() time.sleep(2) title = assertEqual(title,"unittest_百度搜索") def tearDown(self): self.driver.quit()
2、testyoudao.py
from selenium import webdriver import unittest import time class Mytest(unittest.TestCase): def setUp(self): self.driver = webdriver.Chrome("F:\安装工具\python\chromedriver.exe") self.driver.maximize_window() self.driver.implicitly_wait(10) self.base_url = "http://www.youdao.com" def test_youdao(self): driver = self.driver driver.get(self.base_url + "/") driver.find_element_by_id("query").clear() driver.find_element_by_id("query").send.keys("webdriver") driver.find_element_by_id("qb").click() time.sleep(2) title = driver.title self.assertEqual(title, "webdriver - 有道搜索") def tearDown(self): self.driver.close()
二、创建用于执行所有用例的ALL_HTMLtest.py文件
1、ALL_HTMLtest.py
# coding=utf-8 import unittest import time from HTMLTestRunner import HTMLTestRunner # 加载用例testbaidu,testyoudao import testbaidu import testyoudao # 将测试用例添加到测试集中 suite = unittest.TestSuite() suite.addTest(testbaidu.MyTest("test_baidu")) suite.addTest(testyoudao.Mytest("test_youdao")) if __name__ == ‘__main__‘: # 执行测试 runner = unittest.TextTestRunner() runner.run(suite)
拆分带来的好处显而易见,可以根据不同功能创建不同的测试文件,甚至不同的目录,还可以将不同的小功能划分为不同的测试类,在类下编写测试用例,整体结构更加清晰。
但依然存在缺陷(当用例达到成百上千条时,在ALL_HTMLtest.py中addTest()添加测试用例就变得很麻烦)。。。
2、TestLoader类
unittest单元测试框架提供了TestLoader类,该类负责根据各种标准加载测试用例,并将它们返回给测试套件。
unittest提供了可以共享的defaultTestLoader类,可以使用其子类和方法创建实例,discover()方法就是其中之一。
discover(start_dir, pattern=‘test*.py‘, top_level_dir=None)
找到指定目录下的所有测试模块,并递归查找子目录下的测试模块,只有匹配到文件名才能被加载,如果启动的不是顶层目录,则顶层目录必须单独指定。
start_dir:要测试的模块名或测试用例目录;
pattern=‘test*.py‘:表示用例文件名的匹配原则,下面的例子中匹配文件名为以“test”开头的“.py”文件,星号“*”表示任意多个字符;
top_level_dir=None:测试模块的顶层目录,如果没有顶层目录,默认为None;
# coding=utf_8 import unittest from unittest import defaultTestLoader # 定义测试用例的目录为当前目录 test_dir = ‘./‘ discover = unittest.defaultTestLoader.discover(test_dir,pattern=‘test*.py‘) if __name__ == ‘__main__‘: runner = unittest.TextTestRunner() runner.run(discover)
三、集成测试报告
# coding=utf_8 import unittest import time from unittest import defaultTestLoader from HTMLTestRunner import HTMLTestRunner # 定义测试用例的目录为当前目录 test_dir = ‘./report‘ discover = unittest.defaultTestLoader.discover(test_dir,pattern=‘test*.py‘) if __name__ == ‘__main__‘: now = time.strftime("%Y-%m-%d %H_%M_%S") filename = test_dir + ‘/‘ + now + ‘result.html‘ fp = open(filename, ‘wb‘) runner = HTMLTestRunner(stream=fp,title=‘集成测试报告demo‘,description= ‘用例执行情况:‘) runner.run(discover) fp.close()
执行后,结果如下:
转载: https://www.cnblogs.com/imyalost
原文:https://www.cnblogs.com/anhao521/p/10955493.html