文章目录
- (一)WebDriver 提供了八种元素定位方法:
- (二)WebDriver 控制浏览器
- (三)WebDriver API 简单元素操作
- (四)WebDriver API 鼠标事件
- (五)WebDriver API 键盘事件
- (六)WebDriver API获得验证信息
- (七)WebDriver API 设置元素等待
- (八)WebDriver API 定位一组元素
- (九)WebDriver API 多表单切换
- (十)WebDriver API 多窗口切换
- (十一)WebDriver API 警告框处理
- (十二)WebDriver API 上传文件
- (十三)WebDriver API 下载文件
- (十四)WebDriver API 操作 Cookie
- (十五)WebDriver API 调用 JavaScript
- (十六)WebDriver API 处理 HTML5 的视频播放
- (十七)WebDriver API 窗口截图、关闭窗口
- (十八)WebDriver API 验证码的处理
- (十九)WebDriver API WebDriver 原理
通过前端工具,我们看可以看到一个网页,页面上的元素都是由一行行的代码组成的,它们之间有层级地组织起来,每个元素有不同的标签名和属性值。WebDriver 就是通过这信息来找到不同的元素的。
(一)WebDriver 提供了八种元素定位方法:
(1)id
(2)name
(3)class name
(4)tag name 标签名
(5) link text
(6)partial link text 部分链接文本
(7) xpath
(8) css selector
- 定位Web 页面上的元素可以通过元素区别于其他元素的一些属性:id、name、class name、tag name 等;
- 可以通过位置属性:XPath 和 CSS ,提供了以标签名为层级关系的定位方式;
- XPath 和 CSS 同样提供了通过相关元素来查找最终元素的方式;
在 Java 语言中对应的定位方法如下:
import org.openqa.selenium.By;
...
findElement(By.id()) //方法通过 id 属性定位来元素
findElement(By.name()) //通过 name 属性来定位元素
findElement(By.className()) //通过 class 属性来定位元素
findElement(By.tagName()) //通过元素的 tag name 来定位元素
findElement(By.linkText()) //法通过元素标签对之间的文本信息来定位元素
findElement(By.partialLinkText()) //通过元素标签对之间的部分文本信息来定位元素
findElement(By.xpath()) //使用 XPath 语言来定位元素
findElement(By.cssSelector()) //用于 CSS 语言定位元素
(1)id 定位
HTML 规定 id属性在 HTML 文档中必须唯一,类似于身份证号;WebDriver提供的 id 定位方法就是通过元素 id 属性查找元素。
· 通过 id 定位百度输入框与百度搜索按钮,用法如下:
findElement(By.id("kw"))
findElement(By.id("su"))
(2)name 定位
HTML 规定 name 来指定元素的名称,类似于人的名字;name 的属性值,在当前页面中可以不唯一。
· 通过 name 定位百度输入框:
findElement(By.name("wd"))
(3)class 定位
HTML 规定 class 来指定元素的类名。其用法与 id、name 类似;
· 下面通过 class 属性定位百度输入框和搜索按钮:
findElement(By.className("s_ipt"))
findElement(By.className("bg s_btn"))
(4)tag 定位
HTML 的本质就是通过 tag 来定义实现不同的功能,每一个元素本质上也是一个 tag。因为一个 tag 往往用来定义一类功能,所以通过 tag 识别某个元素的概率很低。例如我们打开任意一个页面,查看前端都会发现大量的<div>、<input>、<a>
等 tag,所以很难通过标 tag name 去区分不同的元素。
· 通过标 tag name 定位百度的输入框与百度按钮会发现它们完全相同:
findElement(By.tagName("input"))
(5)link 定位
link 定位与前面介绍的几种定位方法有所不同,它专门用来定位文本链接。
· 百度输入框上面的几个文本链接的代码如下:
<a class="mnav" name="tj_trnews" href="http://news.baidu.com">新闻</a>
<a class="mnav" name="tj_trhao123" href="http://www.hao123.com">hao123</a>
<a class="mnav" name="tj_trmap" href="http://map.baidu.com">地图</a>
<a class="mnav" name="tj_trvideo" href="http://v.baidu.com">视频</a>
<a class="mnav" name="tj_trtieba" href="http://tieba.baidu.com">贴吧</a>
查看上面的代码发现,通过 name 属性定位是个不错的选择。不过这里是为了演示 link 定位的使用,通过 link 定位链接如下:
findElement(By.linkText("新闻"))
findElement(By.linkText("hao123"))
findElement(By.linkText("地图"))
findElement(By.linkText("视频"))
findElement(By.linkText("贴吧"))
(6)partial link 定位
parial link 定位是对 link 定位的一种补充,有些文本链接会比较长,这个时候我们可以取文本链接的一部分定位,只要这一部分信息可以唯一地标识这个链接。
<a class="mnav" name="tj_lang" href="#">一个很长很长的文本链接</a>
· 通过 partial link 定位如下:
findElement(By.partialLinkText("一个很长的"))
findElement(By.partialLinkText("文本链接"))
(7)XPath 定位
**XPath 是一种在 XML 文档中定位元素的语言,有多种定位策略。**因为 HTML 可以看作 XML 的一种实现,所以 Selenium 用户可以使用这种强大的语言在 Web 应用中定位元素。
1’绝对路径定位
如果仍把一个元素看作一个人的话,假设这个人没有任何属性特征(手机号、姓名、身份证号),但这个人一定存在于某个地理位置,如 xx 省 xx 市xx 区 xx 路 xx 号。对于页面上的元素而言也会有这样一个绝对地址。
· 参考 baidu.html 前端工具所展示的代码,我们可以通过下面的方式找到百度输入框和搜索按钮。
findElement(By.xpath("/html/body/div/div[2]/div/div/div/from/span/input"))
findElement(By.xpath("/html/body/div/div[2]/div/div/div/from/span[2]/input"))
**XPath 主要用标签名的层级关系来定位元素的绝对路径,**最外层为 html 语言,有 body 文本内,一级一级往下查找,如果一个层级下有多个相同的标签名,那么就按上下顺序确定是第几个,例如 **div[2]**表示当前层级下的第二个 div 标签。
2’利用元素属性定位
除了使用绝对路径外,XPath 也可以使用元素的属性值来定位。
同样以百度输入框和搜索按钮为例:
// // 表示当前页面某个目录下;
// input 表示定位元素的标签名;
// [@id='kw'] 表示这个元素的 id 属性值等于 kw;
findElement(By.xpath("//input[@id='kw']")) //通过id属性值来定位
findElement(By.xpath("//input[@id='su']"))
findElement(By.xpath("//input[@name='wd']")) //通过name属性值来定位
findElement(By.xpath("//input[@class='s_ipt']")) //通过class属性值来定位
findElement(By.xpath("//*[@class='bg s_btn']")) //如果不想指定标签名,则也可以用星号(*)代替
//使用 XPath 不局限于 id、name 和 class 这三个属性值,元素的任意属性值都可以使用,只要它能唯一的标识一个元素
findElement(By.xpath("//input[@maxlength='100']")) //通过maxlength属性值来定位
findElement(By.xpath("//input[@autocomplete='off']"))
findElement(By.xpath("//input[@type='submit']"))
3’层级与属性结合
如果一个元素本身并没有可以唯一标识这个元素的属性值,那么我们可以找其上一级元素,如果它的上一级元素有可以唯一标识属性的值,也可以拿来使用;
//baidu.html 文本
<form id="form" class="fm" action="/s" name="f">
<span class="bg s_ipt_wr">
<input id="kw" class="s_ipt" autocomplete="off" maxlength="100" value="" name="wd">
</span>
</form>
假如百度输入框本身没有可利用的属性值,那么我们可以查找它的上一级属性;如果父元素没有可利用的属性值,那么可以继续向上查找“爷爷”元素。通过 XPath 描述如下:
findElement(By.xpath("//span[@class='bg s_ipt_wr']/input"))
//span[@class='bg s_ipt_wr'] 通过 class 属性定位到父元素,后面/input 就表示父元素下面的子元素
findElement(By.xpath("//form[@id='form']/span/input")) //通过爷爷元素form查找input
findElement(By.xpath("//form[@id='form']/span[2]/input"))
我们可以通过这种方法一级一级地向上查找,直到找到最外层的标签,那么就是一个绝对路径的写法了。
4’使用逻辑运算符
如果一个属性不能唯一地区分一个元素,我们还可以使用逻辑运算符连接多个属性来查找元素
//baidu.html 文本
<input id="kw" class="su" name="ie">
<input id="kw" class="aa" name="ie">
<input id="bb" class="su" name="ie">
如上面的三行元素,假设我们现在要定位第一行元素,如果使用 id 将会与第二行元素重名,如果使用 class将会与第三行元素重名。如果同时使用 id 和 class 就会唯一的标识这个元素,那么这个时候就可以通过逻辑运算符“and”来连接两个条件;也可以用“and”连接更多的属性来唯一地标识一个元素;
findElement(By.xpath("//input[@id='kw' and @class='su']/span/input"))
Firebug 前端调试工具和 FirePath 插件可以方便地辅助生成 XPath 语法。
- 打开Firefox 浏览器的 FireBug 插件,单击插件左上角的鼠标箭头,再单击页面上需要定位的元素,在元素行上右击弹出快捷菜单,选择“复制 XPath”,将会获得当前元素的 XPath 语法。
- FirePath 插件的使用更加方便和快捷,选中元素后,直接在 XPath 的输入框中生成当前元素的 XPath 语法;
(8)CSS 定位
CSS(Cascading Style Sheets)是一种语言,它被用来描述 HTML 和 XML 文档的表现。CSS 使用选择器来为页面元素绑定属性。这些选择器可被 Selenium 用作另外的定位策略。CSS 可较为灵活地选择控件任意属性,一般情况下定位速度要比 XPath 快;
CSS 选择器的常见语法如下所示:
选择器 | 例 子 | 描 述 |
---|---|---|
.class | .intro | class 选择器,选择 class="intro"的所有元素 |
#id | #firstname | id 选择器,选择 id="firstname"的所有元素 |
* | * | 选择所有元素 |
element | p | 元素所有<p> 元素 |
element > element | div > input | 选择父元素为<div> 的所有 <input> 元素 |
element + element | div + input | 选择同一级中紧接在<div> 元素之后的所有 <input> 元素 |
[attribute=value] | [target=_blank] | 选择 target="_blank" 的所有元素 |
· 下面同样以百度输入框和搜索按钮为例介绍 CSS 定位的用法:
<span class="bg s_ipt_wr">
<input id="kw" class="s_ipt" autocomplete="off" maxlength="100" value="" name="wd">
</span>
<span class="bg s_btn_wr">
<input id="su" class="bg s_btn" type="submit" value="百度一下">
</span>
//1、通过 class 属性定位, 点号(.)表示通过 class 属性来定位元素;
findElement(By.cssSelector(".s_ipt"))
findElement(By.cssSelector(".bg s_btn"))
//2、通过 id 属性定位, 井号(#)表示通过 id 属性来定位元素;
findElement(By.cssSelector("#kw"))
findElement(By.cssSelector("#su"))
//3、通过标签名定位, 在 CSS 语言中,用标签名定位元素不需要任何符号标识,直接使用标签名即可;
findElement(By.cssSelector("input"))
//4、通过父子关系定位, 有标签名为span的父亲元素,查找它的所有标签名叫 input 的子元素;
findElement(By.cssSelector("span > input"))
//5、通过属性定位, 在CSS中也可以使用元素的任意可以唯一标识这个元素的属性。对于属性值来说,可加引号,也可不加,但注意和整个字符串的引号进行区分;
findElement(By.cssSelector("input[autocomplete='off']"))
findElement(By.cssSelector("input[maxlength='100']"))
findElement(By.cssSelector("input[type='submit']"))
//6、组合定位, 把上面的定位策略组合起来使用
findElement(By.cssSelector("form.fm>span>input.s_ipt"))
findElement(By.cssSelector("form#form>span>input#su"))
我们可以通过使用 Firebug 工具、FirePath插件帮助我们生成 CSS 语法,生成方法与 Xpath 相同;
XPath 与 CSS 的类似功能的简单对比:
(二)WebDriver 控制浏览器
WebDriver 主要提供的是操作页面上各种元素的方法,但它也提供了操作浏览器的一些方法,例如控制浏览器的大小、操作浏览器前进和后退等。
(1)控制浏览器窗口大小
driver.manage().window().setSize(new Dimension(480, 800));
driver.manage().window().maximize();
有时候我们希望能以某种浏览器尺寸打开,访问的页面在这种尺寸下运行。例如可以将浏览器设置成移动端大小(480* 800),然后访问移动站点,对其样式进行评估;
WebDriver 提供了 **set_window_size()**方法来设置浏览器的大小。在 PC 端执行自动化测试脚本大多的情况下是希望浏览器在全屏幕模式下执行,那么可以使用 maximize()方法使打开的浏览器全屏显示,其用法与 setSize()相同,但它不需要任何参数。
//Browser.java
package com.mypro.jase;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class Browser {
public static void main(String[] args){
System.out.println("seting brwoser");
WebDriver driver= new ChromeDriver();
driver.manage().window().setSize(new Dimension(480, 800)); //将浏览器设置成移动端大小(480* 800)
driver.get("http://m.mail.10086.cn");
driver.quit();
}
}
(2)控制浏览器后退、前进
driver.navigate().back();
driver.navigate().forward();
在使用浏览器浏览网页时,浏览器提供了后退和前进按钮,可以方便地在浏览过的网页之间切换,WebDriver也提供了对应的 **back()**和 **forward()**方法来模拟后退和前进按钮
// BrowserGo.java
package com.mypro.jase;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class BrowserGo {
public static void main(String[] args){
WebDriver driver = new ChromeDriver();
String firstUrl = "http://www.baidu.com";
System.out.printf("now accesss %s \n", firstUrl);
driver.get(firstUrl);
String secondUrl = "http://news.baidu.com";
System.out.printf("now accesss %s \n", secondUrl);
driver.get(secondUrl);
System.out.printf("now back to %s \n", firstUrl);
driver.navigate().back();
System.out.printf("forward to %s \n", secondUrl);
driver.navigate().forward();
driver.quit();
}
}
//输出结果:---------------------------------------------------------
broser back and forward.
Starting ChromeDriver 2.34.522940 (1a76f96f66e3ca7b8e57d503b4dd3bccfba87af1) on port 20680
Only local connections are allowed.
一月 07, 2018 6:17:30 下午 org.openqa.selenium.remote.ProtocolHandshake createSession
信息: Detected dialect: OSS
now access :http://www.baidu.com
now access :http://news.baidu.com
now back to :http://www.baidu.com
now back to :http://news.baidu.com
(3) 模拟浏览器刷新
driver.navigate().refresh();
(三)WebDriver API 简单元素操作
定位元素之后需要对这个元素进行操作,或单击(按钮)或输入(输入框);
WebDriver 中最常用的几个方法:
(1)clear() 清除文本输入框中的内容
clear()方法用于清除文本输入框中的内容。例如,登录框内一般默认会有“账号”“密码”等提示信息,用于引导用户输入正确的数据;但如果直接向输入框中输入数据,则可能会与输入框中的提示信息拼接。例如,本来用户输入的是“username”,但与提示信息拼接则变为“账号 username”,从而造成输入信息错误。这个时候可以先使用 clear()方法来清除输入框中的默认提示信息。
(2)sendKeys(*value) 模拟键盘向输入框里输入内容
sendKeys()方法模拟键盘向输入框里输入内容。如上面的例子中,通过这个方法向用户名和密码框中输入登录信息。当然,它的作用不仅于此,我们还可以用它发送键盘按键,甚至用它来模拟文件上传。
(3)click() 单击元素
click()方法可以用来单击一个元素,前提是它是可以被单击的对象,它与 sendKeys()方法是 Web 页面操作中最常用到的两个方法。其实 click()方法不仅仅用于单击一个按钮,它还可以单击任何可以单击的文字/图片链接、复选框、单选框、下拉框等。
(4)submit()方法用于提交表单
例如,在搜索框输入关键字之后的“回车”操作,就可以通过 submit()方法模拟。有时候 submit()可以与 click()方法互换来使用,submit()同样可以提交一个按钮,但 submit()的应用范围远不及 click()广泛;
(5)getSize() 返回元素的尺寸
(6)getText() 获取元素的文本
(7)getAttribute(name) 获得属性值
(8)isDisplayed() 设置该元素是否用户可见
执行上面的程序并查看结果:getSize 方法用于获取百度输入框的宽、高。getText 方法用于获得百度底部的
备案信息。getAttribute()用于获得百度输入的 type 属性的值。isDisplayed()用于返回一个元素是否可见,如果可
见则返回 True,否则返回 False。
当然,WebElement 接口还提供了其他方法,读者可以参考 WeBDriverAPI 官方文档学习。
WebDriver driver = new ChromeDriver();
driver.get("http://www.126.com"); //获取126邮箱地址
driver.findElement(By.id("idInput")).clear(); //清空输入框内容
driver.findElement(By.id("idInput")).sendKeys("username"); //向输入框输入内容
driver.findElement(By.id("pwdInput")).clear();
driver.findElement(By.id("pwdInput")).sendKeys("password");
driver.findElement(By.id("loginBtn")).click(); //点击登录按钮
driver.findElement(By.id("query")).sendKeys("submit");
driver.findElement(By.id("query")).submit(); //提交输入的内容
driver.quit();
-----------------------------------------------------------------------------------------
public static void main(String[] args) {
WebDriver driver = new ChromeDriver();
driver.get("http://www.baidu.com/");
WebElement size = driver.findElement(By.id("kw")); //获得百度输入框的尺寸
System.out.println(size.getSize());
WebElement text = driver.findElement(By.id("cp")); //返回百度页面底部备案信息
System.out.println(text.getText());
WebElement ty = driver.findElement(By.id("kw")); //返回元素的属性值,可以是 id、name、type 或元素拥有的其它任意属性
System.out.println(ty.getAttribute("type"));
WebElement display = driver.findElement(By.id("kw")); //返回元素的结果是否可见,返回结果为 True 或 False
System.out.println(display.isDisplayed());
driver.quit();
}
(四)WebDriver API 鼠标事件
可以使用 click()来模拟鼠标的单击操作,现在的 Web 产品中提供了更丰富的鼠标交互方式,例如鼠标右击、双击、悬停、甚至是鼠标拖动等功能。在 WebDriver 中,将这些关于鼠标操作的方法封装在 ActionChains 类提供。
Actions 类提供了鼠标操作的常用方法:
(1)contextClick() 右击
(2)clickAndHold() 模拟鼠标点击并控制的动作
鼠标悬停弹出下拉菜单也是一个十分常见的功能设计;
(3)doubleClick() 双击
(4)dragAndDrop() 拖动
**dragAndDrop(source, target)**在源元素上按下鼠标左键,然后移动到目标元素上释放。
- source:鼠标拖动的源元素。
- target:鼠标释放的目标元素。
(5)release() 释放鼠标
(6)perform() 执行所有 Actions 中存储的行为
// Mouse.java
package com.mypro.jase;
import org.openqa.selenium.By;
import org.openqa.selenium.interactions.Actions; //导入提供鼠标操作的 ActionChains 类
......
public class Mouse {
public static void main(String[] args){
WebDriver driver = new ChromeDriver();
driver.get("http://yunpan.360.cn/");
//(1)鼠标右键点击指定的元素 contextClick()
Actions action = new Actions(driver); // Actions(driver) 调用 Actions()类,将浏览器驱动 driver 作为参数传入。
action.contextClick(driver.findElement(By.id("su"))).perform();
//contexClick(xxx) context_click()方法用于模拟鼠标右键操作,在调用时需要指定元素定位。
//perform()执行所有 ActionChains 中存储的行为,可以理解成是对整个操作的提交动作。
//(2)鼠标悬停 clickAndHold()
Actions action = new Actions(driver);
action.clickAndHold(driver.findElement(By.linkText("设置"))).perform();
//(3)鼠标双击 doubleClick()
Actions action = new Actions(driver);
action.doubleClick(driver.findElement(By.name("element"))).perform();
//(4)鼠标拖动 dragAndDrop(source,target)
Actions action = new Actions(driver);
WebElement source = driver.findElement(By.name("element"));
WebElement target = driver.findElement(By.name("element"));
action.dragAndDrop(source,target).perform(); // 鼠标拖拽动作,将 source 元素拖放到 target 元素的位置。
//(5)释放鼠标 release()
Actions action = new Actions(driver);
action.release().perform();
}
}
(五)WebDriver API 键盘事件
Keys()类提供了键盘上几乎所有按键的方法。前面了解到,sendKeys()方法可以用来模拟键盘输入,除此之外,我们还可以用它来输入键盘上的按键,甚至是组合键,如 Ctrl+A、Ctrl+C 等。
以下为常用的键盘操作:
方法 | 作用 |
---|---|
sendKeys(Keys.BACK_SPACE) | 删除键(BackSpace) |
sendKeys(Keys.SPACE) | 空格键(Space) |
sendKeys(Keys.TAB) | 制表键(Tab) |
sendKeys(Keys.ESCAPE) | 回退键(Esc) |
sendKeys(Keys.ENTER) | 回车键(Enter) |
sendKeys(Keys.CONTROL,‘a’) | 全选(Ctrl+A) |
sendKeys(Keys.CONTROL,‘c’) | 复制(Ctrl+C) |
sendKeys(Keys.CONTROL,‘x’) | 剪切(Ctrl+X) |
sendKeys(Keys.CONTROL,‘v’) | 粘贴(Ctrl+V) |
sendKeys(Keys.F1) | 键盘 F1 |
sendKeys(Keys.F12) | 键盘 F12 |
// Keyboard.java
package com.mypro.jase;
import org.openqa.selenium.Keys; // 在使用键盘按键方法前需要先导入 keys 类
.............
public class keyboard {
public static void main(String[] args){
WebDriver driver = new ChromeDriver();
driver.get("http://www.baidu.com");
WebElement input = driver.findElement(By.id("kw"));
input.sendKeys("seleniumm"); //输入框输入内容"seleniumm"
input.sendKeys(Keys.BACK_SPACE); //删除多输入的一个 m;
input.sendKeys(Keys.SPACE); //输入空格键+“教程”;
input.sendKeys("教程");
input.sendKeys(Keys.TAB); //输入制表符
input.sendKeys(Keys.CONTROL,"a"); //ctrl+a 全选输入框内容;
input.sendKeys(Keys.CONTROL,"x"); //ctrl+x 剪切输入框内容;
input.sendKeys(Keys.CONTROL,"v"); //ctrl+v 粘贴内容到输入框;
input.sendKeys(Keys.ENTER); //通过回车键盘来代替点击操作;
driver.quit();
}
}
(六)WebDriver API获得验证信息
在自动化用例执行完成之后,我们可以从页面上获取一些信息来“证明” 用例执行是成功还是失败。
通常用得最多的几种验证信息分别是 title 、URL 和 text。text 方法在前面已经讲过,它用于获取标签对之间的文本信息。
getText() :获取元素的文本;
getTitle():用于获得当前页面的 title;
getCurrentUrl() :用户获得当前页面的 URL。
package com.mypro.jase;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class titleRul {
public static void main(String[] args){
WebDriver driver = new ChromeDriver();
driver.get("http://www.126.com");
System.out.println("Before login================");
//获取当前的 title 和 url
System.out.println("title of current page is: " + driver.getTitle());
System.out.println("url of current page is ;" + driver.getCurrentUrl());
//登录 126 邮箱
driver.findElement(By.id("idInput")).clear();
driver.findElement(By.id("idInput")).sendKeys("testingwtb");
driver.findElement(By.id("pwdInput")).clear();
driver.findElement(By.id("pwdInput")).sendKeys("a123456");
driver.findElement(By.id("loginBtn")).click();
System.out.println("After login================");
//获取当前的 title 和 url
System.out.println("title of current page is ;" + driver.getTitle());
System.out.println("url of current page is ;" + driver.getCurrentUrl());
//获得登录用户名
String text = driver.findElement(By.id("spnUid")).getText();
System.out.println(text);
driver.quit();
}
}
(七)WebDriver API 设置元素等待
如今大多数 Web 应用程序使用 AJAX 技术。当浏览器在加载页面时,页面上的元素可能并不是同时被加载完成的,这给元素的定位增加了困难。如果因为在加载某个元素时延迟而造成元素定位失败的情况,那么就会降低自动化脚本的稳定性。我们可以通过设置元素等待提高这种问题而造成的不稳定。
(1)timeouts 方法
1、implicitlyWait
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
识别对象时的超时时间。过了这个时间如果对象还没找到的话就会抛出NoSuchElement 异常。
2、setScriptTimeout
driver.manage().timeouts().setScriptTimeout(3, TimeUnit.SECONDS);
异步脚本的超时时间。WebDriver 可以异步执行脚本,这个是设置异步执行脚本脚本返回结果的超时时间。
3、pageLoadTimeout
driver.manage().timeouts().pageLoadTimeout(5, TimeUnit.SECONDS);
页面加载时的超时时间。因为 WebDriver 会等页面加载完毕再进行后面的操作, 所以如果页面超过设置时间依然没有加载完成,那么 WebDriver 就会抛出异常;
public static void main(String[] args) {
WebDriver driver = new ChromeDriver();
driver.manage().timeouts().pageLoadTimeout(5, TimeUnit.SECONDS); //页面加载超时时间设置为 5s
driver.get("http://www.baidu.com/");
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); //定位对象时给 10s 的时间, 如果 10s 内还定位不到则抛出异常
driver.findElement(By.id("kw33")).sendKeys("selenium");
driver.manage().timeouts().setScriptTimeout(3, TimeUnit.SECONDS); //异步脚本的超时时间设置成 3s
driver.quit();
}
(2)sleep 休眠方法
有时间我们希望脚本执行到某一位置时做固定时间的休眠,尤其是在脚本调试的过程中。那么可以使用Java 提供的 Thread.sleep(2000)方法;当执行到 sleep()方法时会固定的休眠所设置的时长(这里以毫秒为单位);然后再继续执行。
public static void main(String[] args){
WebDriver driver = new ChromeDriver();
driver.get("http://www.baidu.com/");
try { //必须异常处理
Thread.sleep(2000) ;
} catch (InterruptedException e) {
e.printStackTrace();
}
driver.findElement(By.id("kw")).sendKeys("selenium");
driver.findElement(By.id("su")).click();
try { //必须异常处理
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
driver.quit();
}
(八)WebDriver API 定位一组元素
除了8种针对单个元素定位的定位方法,WebDriver 还提供了与之对应的 8 种用于定位一组元素定位方法。
定位一组元素的方法与定位单个元素的方法类似,唯一的区别是在单词 element 后面多了一个 s 表示复数。
- findElements(By.id())
- findElements(By.name())
- findElements(By.className())
- findElements(By.tagName())
- findElements(By.linkText())
- findElements(By.partialLinkText())
- findElements(By.xpath())
- findElements(By.cssSelector())
定位一组元素一般用于以下场景:
- 批量操作元素,例如勾选页面上所有的复选框。
- 先获取一组元素,再从这组对象中过滤出需要操作的元素。例如定位出页面上所有的 checkbox,然后选择其中的一个进行操作。
常用方法
- driver.navigate().refresh(); 这个方法用于刷新页面。
- allCheckboxes.size(); size()方法可以计算获得元素的个数。
- allCheckboxes.get().click() ; get()指定得到元素组中的第几个元素,并对其时行 click()操作。
public static void main(String[] args) throws InterruptedException {
WebDriver driver = new ChromeDriver();
File file = new File("E:/jase/checkbox.html");//通过浏览器打开的是一个本地的 html 文件,所以需要用到 Java 的 File()方法本地路径下的文件
String filePath = file.getAbsolutePath(); //获取文件的绝对路径
driver.get(filePath);
List<WebElement> inputs = driver.findElements(By.tagName("input")); //通过findElements(By.tagName())找到一组标签名为input 的元素
for(WebElement checkbox : inputs){ //通过for循环遍历获取到的一组input标签
String type = new String(checkbox.getAttribute("type")); //通过 getAttribute()方法获取元素的 type 属性
if (type.equals("checkbox")){ //判断元素的 type 属性是否为“checkbox”
checkbox.click(); //如果为“checkbox”,那么就认为这个元素是一个复选框,对其进行勾选操作
Thread.sleep(2000);
}
}
driver.quit();
}
使用 XPath 或 CSS 来直接判断属性值,从而进行单击操作
public static void main(String[] args) throws InterruptedException {
WebDriver driver = new ChromeDriver();
File file = new File("E:/jase/checkbox.html");
String filePath = file.getAbsolutePath();
driver.get(filePath);
List<WebElement> checkboxes = driver.findElements(By.cssSelector("input[type=checkbox]"));//通过 css 找到一组元素
List<WebElement> checkboxes = driver.findElements(By.xpath("//input[@type='checkbox']"));//通过 xpath 找到一组元素
for(WebElement checkbox : checkboxes) {
checkbox.click();
}
Thread.sleep(3000);
driver.navigate().refresh(); //刷新
List<WebElement> allCheckboxes = driver.findElements(By.cssSelector("input[type=checkbox]")); //把页面上最后 1 个 checkbox 的勾给去掉
System.out.println(allCheckboxes.size());
allCheckboxes.get(allCheckboxes.size() - 1).click();
Thread.sleep(5000);
driver.quit();
}
(九)WebDriver API 多表单切换
常用方法:
- switchTo().frame() : 将当前定位的主体切换为 frame/iframe 表单的内嵌页面中;
- switchTo().defaultContent() : 方法跳出表单;
在 Web 应用中经常会遇到 frame/iframe 表单嵌套页面的应用,WebDriver 只能在一个页面上对元素识别与定位,对于 frame/iframe 表单内嵌页面上的元素无法直接定位。这时就需要通过 switchTo().frame()方法将当前定位的主体切换为 frame/iframe 表单的内嵌页面中。
// frame.html
<html>
<head>
<link href="http://cdn.bootcss.com/bootstrap/3.3.0/css/bootstrap.min.css" rel="stylesheet" />
<script type="text/javascript">
$(document).ready(function(){});
</script>
</head>
<body>
<div class="row-fluid">
<div class="span10 well">
<h3>frame</h3>
<iframe id="if" name="nf" src="http://www.baidu.com" width="800"height="300">
</iframe>
</div>
</div>
</body>
<scriptsrc="http://cdn.bootcss.com/bootstrap/3.3.0/css/bootstrap.min.js"> </script>
</html>
在 html 代码中,通过 iframe 表单嵌入一个百度页面;这 个 时 候 直 接 定 位 页 面 上 的 百 度 的 输 入 框 一 定 会 报 找 不 到 元 素 的 错 误 , 因 此 可 以 使 用switchTo().frame()先找到 frame.html 中的<iframe>
标签,然后再定位百度输入框。
public static void main(String[] args) throws InterruptedException {
WebDriver driver = new ChromeDriver();
File file = new File("E:/jase/frame.html");
String filePath = file.getAbsolutePath();
driver.get(filePath);
driver.switchTo().frame("if"); //切换到 iframe(id = "if")
driver.findElement(By.id("kw")).sendKeys("webdriver");
driver.findElement(By.id("su")).click();
Thread.sleep(5000);
driver.quit();
}
switchTo().frame()默认可以直接取表单的 id 或 name 属性。如果 iframe 没有可用的 id 和 name 属性,则可以通过下面的方式进行定位。
WebElement xf = driver.findElement(By.xpath("//iframe[@id='if']")); //先通过 xpth 定位到 iframe
driver.switchTo().frame(xf); ……
driver.switchTo().defaultContent(); //退回上一级表单
如果完成了在当前表单上的操作,则可以通过 switchTo().defaultContent()方法跳出表单。
(十)WebDriver API 多窗口切换
- switchTo().window() : 方法可以实现在不同的窗口之间切换;window参数为将要切换到的页面的句柄;
- getWindowHandle():获得当前窗口句柄。
- getWindowHandles():返回的所有窗口的句柄到当前会话。
在页面操作过程中有时候点击某个链接会弹出新的窗口,这时就需要主机切换到新打开的窗口上进行
操作。WebDriver 提供了 switchTo().window()方法可以实现在不同的窗口之间切换。
public static void main(String[] arge) throws InterruptedException{
WebDriver driver = new ChromeDriver();
driver.get("http://www.baidu.com");
String sreach_handle = driver.getWindowHandle(); //获得当前窗口句柄
System.out.println(sreach_handle); //打开百度注册窗口
driver.findElement(By.linkText("登录")).click();
Thread.sleep(3000);
driver.findElement(By.linkText("立即注册")).click();
Set<String> handles = driver.getWindowHandles(); //获得所有窗口句柄
for(String handle : handles){ //判断是否为注册窗口,并操作注册窗口上的元素
if (handle.equals(sreach_handle)==false){
driver.switchTo().window(handle); //切换到注册页面
System.out.println("now register window!");
Thread.sleep(2000);
driver.findElement(By.name("account")).clear();
driver.findElement(By.name("account")).sendKeys("username");
driver.findElement(By.name("password")).sendKeys("password");
Thread.sleep(2000);
driver.close(); //关闭当前窗口
}
}
for(String handle : handles){ //判断是否为百度首页,并操作首页上的元素
if (handle.equals(sreach_handle)){
driver.switchTo().window(handle); //切换到百度搜索页面
Thread.sleep(2000);
driver.findElement(By.className("close-btn")).click();
System.out.println("now baidu sreach page!");
driver.findElement(By.id("kw")).sendKeys("webdriver");
driver.findElement(By.id("su")).click();
Thread.sleep(2000);
}
}
driver.quit();
}
脚本的执行过程:首先打开百度首页,通过 getWindowHandle()获得当前窗口的句柄,并赋值给变量sreach_handle。接着打开登录弹窗,在登录弹窗上单击“立即注册”,从而打开新的注册窗口。通过getWindowHandles()获得当前打开的所有窗口的句柄,并赋值给变量 handles。
第一个循环遍历 handles,如果 handle 不等于 sreach_handle,那么一定是注册窗口,因为脚本执行过程中只打开两个窗口。所以,通过 switchTo().window()切换到注册页进行注册操作。第二个循环类似,不过这一次判断如果 handle 等于 sreach_handle,那么切换到百度搜索页,然后进行搜索操作。
(十一)WebDriver API 警告框处理
- driver.switchTo().alert().accept(); 定位到 alert/confirm/prompt,然后使用 text/accept/dismiss/ sendKeys 等方法进行操作;
- getText():返回 alert/confirm/prompt 中的文字信息。
- accept(): 接受现有警告框。
- dismiss():解散现有警告框。
- sendKeys(keysToSend): 发送文本至警告框。keysToSend:将文本发送至警告框。
在 WebDriver 中 处 理 JavaScript 所 生 成 的 alert 、 confirm 以 及 prompt 十 分 简 单 , 具 体 做 法 是 使 用**switch_to_alert()**方法定位到 alert/confirm/prompt,然后使用 text/accept/dismiss/ sendKeys 等方法进行操作。
Eg:百度搜索设置弹出的窗口是不能通过前端工具对其进行定位的,这个时候就可以通过switch_to_alert()方法接受这个弹窗。
public static void main(String[] args) throws InterruptedException{
WebDriver driver = new ChromeDriver();
driver.get("http://www.baidu.com");
Actions action = new Actions(driver); //鼠标悬停到“设置”链接
action.clickAndHold(driver.findElement(By.linkText("设置"))).perform();
driver.findElement(By.className("setpref")).click(); //打开搜索设置
Thread.sleep(2000);
driver.findElement(By.className("prefpanelgo")).click(); //保存设置
Thread.sleep(2000);
driver.switchTo().alert().accept(); //接收弹窗
driver.quit();
}
上例中使用了 ActionChains 类所提供的 clickAndHold()鼠标点击并控制的使用,将将鼠标点击并控制在“设置”链接上,然后在弹出的下拉菜单中单击“搜索设置”按钮,设置完成后单击“保存设置”,弹出保存确认警告框。通过 **switch_to_alert()**方法获取当前页面上的警告框,并使用 **accept()**方法接受警告框。
(十二)WebDriver API 上传文件
上传文件是比较常见的 Web 功能之一,但 WebDriver 并没有提供专门用于上传的方法,如何实现上传操作关键在于上传文件的思路。一般 Web 页面的上传功能的操作,需要单击“上传”按钮后需要打开本地的 Window 窗口,从窗口中选择本地文件进行上传。而 WebDriver 是无法操作 Windows 控件的,所以,对于初学者来说,一般思路会卡在如何自动化识别 Window 控件这个问题上。
对于 Web 页面的上传功能实现一般有以下两种方式。
- 普通上传:普通的附件上传是将本地文件的路径作为一个值放在 input 标签中,通过 form 表单将这个值提交给服务器。
- 插件上传:一般是指基于 Flash、JavaScript 或 Ajax 等技术所实现的上传功能。
(1)sendKeys 实现上传
对于通过 input 标签实现的上传功能,可以将其看作一个输入框,即通过 **sendKeys()**指定本地文件路径的方式实现文件上传。
<body>
<div class="row-fluid">
<div class="span6 well">
<h3>upload_file</h3>
<input type="file" name="file" />
</div>
</div>
</body>
public static void main(String[] args) throws InterruptedException {
WebDriver driver = new ChromeDriver();
File file = new File("E:/jase/upfile.html");
String filePath = file.getAbsolutePath();
driver.get(filePath);
driver.findElement(By.name("file")).sendKeys("D:\\upload_file.txt"); //定位上传按钮,添加本地文件
Thread.sleep(5000);
driver.quit();
}
通过这种方法上传,就避免了操作 Windows 控件的步骤。如果能找到上传的 input 标签,那么基本上就可以通过 sendKeys()方法向其输入一个文件地址来实现上传。
(2)AutoIt 实现上传
AutoIt 目前最新是 v3 版本,它是一个使用类似 BASIC 脚本语言的免费软件,它被设计用来进行 WindowsGUI(图形用户界面)的自动化测试。它利用模拟键盘按键,鼠标移动和窗口/控件的组合来实现自动化任务。
- 官方网站:https://www.autoitscript.com/site/
从网站上下载 AutoIt 并安装,安装完成后,在菜单中会看到 Auto Lt 菜单:
- AutoIt Windows Info: 用于识别 Windows 控件信息。
- Compile Script to.exe: 用于将 AutoIt 生成 exe 执行文件。
- Run Script: 用于执行 AutoIt 脚本。
- SciTE Script Editor: 用于编写 AutoIt 脚本。
下面以操作 upload.html 上传弹出的窗口为例,讲解 AutoIt 上传过程。
- 1、首先打开 AutoIt Windows Info 工具,用鼠标单击 Finder Tool,鼠标将变成一个小风扇形状的图标,如图所示。按住鼠标左键,将其拖动到需要识别的控件上(如“打开”按钮控件)如图所示。
可以通过 AutoIt Windows Info 获得以下信息:
(1)窗口的 title 为“选择要加载的文件”,标题的 Class 为“#32770”。
(2)文件名输入框的 class 为“Edit”,Instance 为“1” ,所以 ClassnameNN 为“Edit1”。
(3)打开按钮的 class 为“Button”,Instance 为“1” ,所以 ClassnameNN 为“Button1”。
- 2、根据 AutoIt Windows Info 所识别到的控件信息,打开 SciTE Script Editor 编辑器,编写 AutoIt 脚本。
;ControlFocus("title","text",controlID) Edit1=Edit instance 1
ControlFocus("选择要加载的文件", "","Edit1")
; Wait 10 seconds for the Upload window to appear
WinWait("[CLASS:#32770]","",10)
; Set the File name text on the Edit field
ControlSetText("选择要加载的文件", "", "Edit1", "D:\\upload_file.txt") Sleep(2000)
; Click on the Open button
ControlClick("选择要加载的文件", "","Button1");
-
**ControlFocus()**方法用于识别 Window 窗口;
-
**WinWait()**方法设置10 秒钟用于等待窗口的显示;
-
ControlSetText() 方法用于向“文件名”输入框内输入本地上传文件的路径;
-
**ControlClick()**用于单击上传窗口中的“打开”按钮。
-
3、AutoIt 的脚本已经写好了,可以通过菜单栏“Tools”–>“Go” (或按键盘 F5)来运行脚本!注意:在运
行时文件上传窗口应处于打开状态。 -
4、、脚本运行正常,将其保存为 upfile.au3 文件。这里保存的脚本可以通过 Run Script 工具将其打开运行,但我们的目的是希望这个脚本被 Java 程序调用,那么就需要将其生成为 exe 程序。打开 Compile Script to.exe 工具,将其生成为 exe 可执行文件
单击“Browse”按钮,选择 upfile.au3 文件,单击“Convert”按钮将其生成为 upfile.exe 程序。 -
5、接下来是通过自动化测试脚本调用 upfile.exe 程序,实现上传
public static void main(String[] args) throws InterruptedException {
WebDriver driver = new ChromeDriver();
File file = new File("E:/jase/upfile.html");
String filePath = file.getAbsolutePath();
driver.get(filePath);
driver.findElement(By.name("file")).click();
Thread.sleep(3000);
Runtime rn = Runtime.getRuntime();
try{
String str = "D://upload.exe" ;
rn.exec(str);
} catch (Exception e){
System.out.println("Error to run the exe");
}
Thread.sleep(10000);
driver.quit();
}
通过 Java 的 Runtime 模块的 **getruntime.exec()**方法可以调用 exe 程序并执行。
这种方法不推荐,因为通过 Java调用的 exe 程序并不在 Java 的可控范围内。换句话说,exe 执行多长时间,执行是否出错,Java 程序都无法得知。
(十三)WebDriver API 下载文件
WebDriver 允许我们设置默认的文件下载路径,也就是说,文件会自动下载并且存放到设置的目录中。
public static void main(String[] args){
FirefoxProfile firefoxProfile = new FirefoxProfile();
firefoxProfile.setPreference("browser.download.folderList",2);
firefoxProfile.setPreference("browser.download.manager.showWhenStarting", false);
firefoxProfile.setPreference("browser.download.dir","d:\\java");
firefoxProfile.setPreference("browser.helperApps.neverAsk.saveToDisk","application/octet-stream");
WebDriver driver = new FirefoxDriver(firefoxProfile);
driver.get("https://pypi.Python.org/pypi/selenium");
driver.findElement(By.partialLinkText("selenium-2")).click();
}
为了让 Firefox 浏览器能实现文件下载,我们需要通过 **FirefoxProfile()**对其做一些设置:
- browser.download.folderList : 设置成 0 代表下载到浏览器默认下载路径,设置成 2 则可以保存到指定目录。
- browser.download.manager.showWhenStarting : 是否显示开始;Ture 为显示,Flase 为不显示。
- browser.download.dir : 用于指定所下载文件的目录。os.getcwd() 函数不需要传递参数,用于返回当前的目录。
- browser.helperApps.neverAsk.saveToDisk : 指定要下载页面的 Content-type 值,“application/octet-stream”为文件的类型: .*( 二进制流,不知道下载文件类型)
HTTP Content-type 常用对照表:http://tool.oschina.net/commons
这些参数的设置可以通过在 Firefox 浏览器地址栏输入:about:config 进行设置,如图
将所有设置信息在调用 webdriver 的 Firefox()方法时作为参数传递给浏览器。FireFox 浏览器在下载时就根据这些设置信息将文件下载到当前脚本的目录下。
上面例子中的设置只针对 Firefox 浏览器,不同的浏览器设置方法会有所不同。通用的方法的还是借助 AutoIt来操作 Windows 控件进行下载;
(十四)WebDriver API 操作 Cookie
有时候我们需要验证浏览器中 cookie 是否正确,因为基于真实 cookie 的测试是无法通过白盒测试和集成测试进行的。
WebDriver 提供了操作 Cookie 的相关方法可以读取、添加和删除 cookie 信息:
WebDriver 操作 cookie 的方法:
- driver.manage().getCookies(): 获得所有 cookie 信息;
- driver.manage().getCookieNamed(String name) : 返回字典的 key 为“name”的 cookie 信息;
- driver.manage().addCookie(cookie dict) : 添加 cookie。“cookie_dict”指字典对象,必须有 name 和 value 值;
- driver.manage().deleteCookieNamed(String name) : 删除 cookie 信息。“name”是要删除的 cookie 的名称;
“optionsString”是该 cookie 的选项,目前支持的选项包括“路径”,“域”。 - driver.manage().deleteAllCookies() :删除所有 cookie 信息;
public static void main(String[] args){
WebDriver driver = new ChromeDriver();
driver.get("http://www.youdao.com");
Set<Cookie> coo = driver.manage().getCookies(); //获得 cookie
System.out.println(coo); //打印 cookie
driver.quit();
}
执行结果:
[JSESSIONID=abc6Pheyjzl7M_fdLPy3u;
path=/;
domain=www.youdao.com,
OUTFOX_SEARCH_USER_ID=-1975491366@183.61.23.26;
expires=星期四, 01 六月 2045 10:08:10 CST;
path=/;
domain=.youdao.com]
从执行结果可以看出,cookie 数据是以字典的形式进行存放的。知道了 cookie 的存放形式,接下来我们就可以按照这种形式向浏览器中写入 cookie 信息。
public static void main(String[] args){
WebDriver driver = new ChromeDriver();
driver.get("http://www.youdao.com");
Cookie c1 = new Cookie("name", "key-aaaaaaa");
Cookie c2 = new Cookie("value", "value-bbbbbb");
driver.manage().addCookie(c1);
driver.manage().addCookie(c2);
Set<Cookie> coo = driver.manage().getCookies(); //获得 cookie
System.out.println(coo); //打印 cookie
driver.manage().deleteAllCookies(); //删除所有 cookie
driver.quit();
}
执行结果:
[name=key-aaaaaaa;
path=/;
domain=www.youdao.com,
value=value-bbbbbb;
path=/;
domain=www.youdao.com]
从执行结果可以看到,最后一条 cookie 信息是在脚本执行过程中通过 addCookie()方法添加的。通过遍历得到的所有 cookie 信息,从而找到 key 为“name”和“value”的特定 cookie 的 value。
那么在什么情况下会用到 cookie 的操作呢?
例如开发人员开发一个功能,当用户登录后,会将用户的用户名写入浏览器 cookie,指定的 key 为“username”,那么我们就可以通过 getCookies() 找到 useranme,打印 vlaue。如果找不到 username 或对应的 value 为空,那么说明 cookie 没有成功的保存到浏览器中。
(十五)WebDriver API 调用 JavaScript
- ((JavascriptExecutor)driver).executeScript(“window.scrollTo(100,450);”);
虽然 WebDriver 提供了操作浏览器的前进和后退方法,但对于浏览器滚动条并没有提供相应的操作方法。
在这种情况下,就可以借助 JavaScript 来控制浏览器的滚动条。WebDriver 提供了 **execute_script()**方法来执行JavaScript 代码。
用于调整浏览器滚动条位置的 JavaScript 代码如下:
window.scrollTo(0,450); //window.scrollTo(左边距,上边距)
- **window.scrollTo()**方法用于设置浏览器窗口滚动条的水平和垂直位置。方法的第一个参数表示水平的左间距,第二个参数表示垂直的上边距。
其代码如下:
public static void main(String[] args) throws InterruptedException{
WebDriver driver = new ChromeDriver();
driver.manage().window().setSize(new Dimension(700, 600)); //设置窗口大小
driver.get("http://www.baidu.com");
driver.findElement(By.id("kw")).sendKeys("webdriver api");
driver.findElement(By.id("su")).click();
Thread.sleep(2000);
((JavascriptExecutor)driver).executeScript("window.scrollTo(100,450);"); //将页面滚动条拖到底部
Thread.sleep(3000);
System.out.println("end");
driver.quit();
}
通过浏览器打开百度进行搜索,并且提前通过 setSize()方法将浏览器窗口设置为固定宽高显示,目的是让窗口出现水平和垂直滚动条。然后通过 executeScript()方法执行 JavaScripts 代码来移动滚动条的位置,如图所示:
当然,JavaScript 的作用不仅仅体现在浏览器滚动条的操作上,例如,还可以用它向页面中 textarea 文本框输入内容。
文本框的前端代码:
<textarea id="id" style="width: 98%" cols="50" rows="5" class="txtarea">
</textarea>
虽然我们可以通过 id 的方式将其进行定位,但却不能通过 sendKeys()向文本框中输入文本信息。这种情况下,也需要借助 JavaScript 代码完成输入;
- JS.java:
String text = "input text";
String js = " var sum=document.getElementById('id'); sum.value='" + text + "'; ";
((JavascriptExecutor)driver).executeScript(js);
首先定义了要输入的内容 text,然后将 text 与 JavaScript 代码通过“+”进行拼接。这样做的目的是为了使输入内容变得可自定义。最后,通过 executeScript()执行 JavaScript 代码。
(十六)WebDriver API 处理 HTML5 的视频播放
目前 HTML5 技术已经渐渐成为了主流,主流的浏览器都已支持 HTML5。越来越多的应用使用了 HTML5 的元素,如 canvas,video 等,另外网页存储功能更增加了用户的网络体验,使得越来越多的开发者在使用这样的标准,所以我们也需要学习如何使用自动化技术来测试它们。
WebDriver 支持在指定的浏览器上测试 HTML5,另外,我们还可以使用 JavaScript 来测试这些功能,这样就可以在任何的浏览器上测试 HTML5 了。
大多数浏览器使用控件(如 Flash) 来播放规频,但是,不同的浏览器需要使用不同的插件。HTML5 定义了一个新的元素**<video>
**,指定了一个标准的方式来嵌入电影片段,该元素提供了 JavaScript 接口和多种方法及属性; IE9+、Firefox、Opera、Chrome都支持该元素。
public static void main(String args[]) throws InterruptedException {
WebDriver driver = new ChromeDriver();
driver.get("http://videojs.com/");
WebElement video = driver.findElement(By.xpath("//body/section/div/video")); //获取video控件
JavascriptExecutor jse = (JavascriptExecutor)driver;
jse.executeScript("return arguments[0].currentSrc;",video); //获得视屏的 URL
jse.executeScript("return arguments[0].play()", video); //播放视屏,播放 15 秒钟
Thread.sleep(15000);
jse.executeScript("arguments[0].pause()", video); //暂停视屏
driver.quit();
}
JavaScript 函数有个内置的对象叫作 arguments。
- argument 对象包含了函数调用的参数数组,[0]表示取对象的第 1 个值。
- currentSrc 返回当前音频/视频的 URL。如果未设置音频/视频,则返回空字符串;
- load()、play()、pause() 等控制着视频的加载、播放和暂停。
(十七)WebDriver API 窗口截图、关闭窗口
- quit()方法:退出相关的驱动程序和关闭所有窗口;
- close()方法 :关闭当前窗口;-
- getScreenshotAs() : 截取当前窗口
自动化用例是由程序去执行,因此有时候打印的错误信息并不十分明确。如果在脚本执行出错的时候 能对当前窗口截图保存,那么通过图片就可以非常直观地看出出错的原因。WebDriver 提供了截图函数getScreenshotAs()来截取当前窗口。
public static void main(String[] args){
WebDriver driver = new ChromeDriver();
driver.get("http://www.baidu.com");
try {
File srcFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(srcFile,new File("d:\\screenshot.png")); //指定图片的保存路径及文件名
} catch (Exception e) {
e.printStackTrace();
}
driver.quit();
}
在本例中用到了 Java 的异常处理,打开百度首页,执行 getScreenshotAs()对当前窗口进行截图,这里需要指定图片的保存路径及文件名,并且关闭当前驱动。
脚本运行完成后打开 D 盘,就可以找到 screenshot.png 图片文件了。
(十八)WebDriver API 验证码的处理
对于 Web 应用来说,大部分的系统在用户登录时都要求用户输入验证码。验证码的类型很多,有字母数字的、有汉字的,甚至还有需要用户输入一道算术题的答案的。对于系统来说,使用验证码可以有效地防止采用机器猜测方法对口令的刺探,在一定程度上增加了安全性。
但对于测试人员来说,不管是进行性能测试还是自动化测试,都是一个比较棘手的问题。在 WebDriver 中并没有提供相应的方法来处理验证码;
谈处理验证码的几种常见方法:
(1)去掉验证码
这是最简单的方法,对于开发人员来说,只是把验证码的相关代码注释掉即可。
如果是在测试环境,这样做可省去测试人员不少的麻烦;但如果自动化脚本是在正式环境测试,那么这样就给系统带来了一定的风险。
(2)设置万能验证码
去掉验证码的主要问题是安全,为了应对在线系统的安全威胁,可以在修改程序时不取消验证码,而是在程序中留一个“后门”,即设置一个“万能验证码”。只要用户输入这个“万能验证码”,程序就认为验证通过,否则就判断用户输入的验证码是否正确。
设计万能验证码的方式非常简单,只需对用户的输入信息多加一个逻辑判断,下面通过例子演示:
public static void main(String[] args){
int min=1000;
int max=9999;
Random rand = new Random(); //创建随机数对象
int s = rand.nextInt(max)%(max-min+1) + min; //nextInt()用于生成随机数,设置随机数的范围为1000~9999之间
String ss = String.valueOf(s); //将随机数赋值给ss
System.out.println(ss);
Scanner sc=new Scanner(System.in); //创建输入对象
System.out.print("请输入随即验证码:"); //获取用户输入的字符串
String str=sc.nextLine();
if(str.equals(ss)){
System.out.println("输入正确");
}else if(str.equals("98765454")){
System.out.println("输入正确");
}else{
System.out.println("输入错误");
}
}
运行程序分别输入正确的验证码、万能验证码和错误的验证码,执行结果如下:
4238
请输入随即验证码:4238
输入正确
=================>>>
7845
请输入随即验证码:98765454
输入正确
=================>>>
7476
请输入随即验证码:1234
输入错误
(3)验证码识别技术
例如,JCaptcha 是一个用来生成验证码的开源 Java 类库。不过,目前市面上的验证码形式繁多,大多验证码识别技术,识别率都很难达到 100% 。
(4)记录 cookie。
通过向浏览器中添加 cookie 可以绕过登录的验证码,这是比较有意思的一种解决方案。例如我们在第一次登录某网站时勾选“记住密码”的选项,当下次再访问该网站时自动就处于登录状态了。这样自然就绕过了验证码问题。那么这个“记住密码”的功能其实就记录在了浏览器的 cookie 中。前面已经学了通过 WebDriver 来操作浏览器的 cookie,可以通过 add_cookie()方法将用户名密码写入浏览器 cookie ,当再次访问网站时,服务器将直接读取浏览器 cookie 登录。
public static void main(String[] args) throws InterruptedException {
WebDriver dr = new ChromeDriver();
String url = "http://www.baidu.com";
System.out.println("now accesss :" + url);
dr.get(url);
Thread.sleep(2000);
System.out.println(dr.manage().getCookies());
dr.manage().deleteAllCookies();
Cookie c1 = new Cookie("BAIDUID", "xxxxxxxxxx");
Cookie c2 = new Cookie("BDUSS", "xxxxxxxxxx");
dr.manage().addCookie(c1);
dr.manage().addCookie(c2);
System.out.println("browser will be close");
dr.quit();
}
这种方式最大的问题是如何从浏览器的 cookie 中找到用户名和密码对应的 key 值,并传输入对应的登录信息。
可以用 getCookies()方法来获取登录的所有的 cookie 信息,从中找到用户名和密码的 key。
(十九)WebDriver API WebDriver 原理
WebDriver 属于 Selenium 体系中设计出来操作浏览器的一套 API,它支持多种编程语言 。站在编程语言的角度来看,Selenium WebDriver 只是 Java 的一个第三方框架, 和 Spring web 开发框架属于同一性质,只是 Spring 只在 Java 语言中存在,其它语言也有用于 web 开发框架,但不叫 Spring。而 Selenium WebDriver 框架针对不同语言分别开发了该框架,所以,在不同的编程语言里它都叫 Selenium WebDriver。本文,我们将详细介绍这个框架所提供的操作 web 页面的各种常用方法;
WebDriver 是按照 Server – Client 的经典设计模式设计的;
- Server 端就是 Remote Server,可以是任意的浏览器。当我们的脚本启动浏览器后,该浏览器就是 Remote Server,它的职责就是等待 Client 发送请求并做出响应。
- Client 端简单说来就是我们的测试代码。我们测试代码中的一些行为,例如打开浏览器,转跳到特定的 url等操作是以 http 请求的方式发送给被测试浏览器的,也就是 Remote Server。Remote Server 接受请求,并执行相应操作,并在Response 中返回执行状态、返回值等信息。
WebDriver 的工作流程:
-
- WebDriver 启动目标浏览器,并绑定到指定端口。该启动的浏览器实例,作为 WebDriver 的 Remote Server。
-
- Client 端通过 CommandExcuter 发送 HTTPRequest 给 Remote Server 的侦听端口(通信协议:the webriver wire protocol)。
-
- Remote Server 需要依赖原生的浏览器组件(如 IEDriverServer.exe、chromedriver.exe),来转化浏览器的native 调用。
【整理自虫师书籍】:博客地址