java之webdriver教程(UI自动化)类推python
其实python也有一套,逻辑一模一样,就语法也只是差那么一点点。
语言差异但是逻辑不变
本教程浏览器用firefox其实chrome也是可以的,但是firefox好处是可以装插件,比如selenium IDE
步骤:
1,安装firebug插件:将firebug-2.0.8-fx.xpi拖到FireFox36浏览器中就会安装
2,安装selenium IDE 直接在扩展组件里下载
3,定位节点
(1)单斜线“/”代表绝对路径,而双斜线“//”符合都会被选出来
(2)/*代表通配符
(3)选择分支 /cd[0] /cd[last()]
(4)选择一个以上的路径用“|”
(5)选择属性用“@”
软件测试的方法:等价类划分法、边界值分析法、错误猜测法、
数据驱动方式有好多种,既可以从Excel 中读取数据,也可以 从XML 中读取,还可以从代码数据提供者中读取
WD演变:IDE,断言,二次封装,数据驱动(数据与代码分离),POM 页面对象管理(测试元素与代码分离),关键字驱动,自动化管理平台(元素录入,用例管理,测试报告检索)
前提准备:
工具:myeclipse+firefox 36+selenium2.48+jdk1.7+testng5.12+selenium ide
+Xpath checker
1,新建java project
2,导入selenium2.48包
(2.1)工程项目右键properties>java bulid path>libraries>add jars
把libs文件全部jar包添加上,再添加selenium 2.48两个jar
(2.2)关联webdriver源码:将selenium2.48右键>java source attachment选中2.48-srcs>ok
3,将org.testng复制至D:\MyEclipse10\dropins;将testng导入到项目中
Webdriver基础知识:
tsetng的介绍:
TestNG 是一个设计用来简化广泛的测试需求的测试框架,从单元测试(隔
离测试一个类)到集成测试(测试由有多个类多个包甚至多个外部框架组成的整
个系统,例如运用服务器)。
a. TestNG 是一个设计用来简化广泛的测试需求的测试框架,从单元测试到
集成测试
这个是TestNG 设计的出发点,不仅仅是单元测试,而且可以用于集成测试。
设计目标的不同,对比junit 的只适合用于单元测试,TestNG 无疑走的更远。
可以用于集成测试,这个特性是我选择TestNG 的最重要的原因。
b. 测试的过程的三个典型步骤,注意和junit(4.0)相比,多了一个将测试
信息添加到testng.xml 文件或者build.xml
测试信息尤其是测试数据不再写死在测试代码中,好处就是修改测试数据
时不需要修改代码/编译了,从而有助于将测试人员引入单元测试/集成测试。
c. 基本概念,相比junit 的TestCase/TestSuite,TestNG 有
suite/test/test method 三个级别,即将test/test method 明确区分开了。
【对浏览器操作】
1,打开一个浏览器
public class OpenBrowsers {
public static void main(String[] args) {
//打开默认路径的firefox
WebDriver diver = new FirefoxDriver();
//打开指定路径的firefox,方法1
System.setProperty("webdriver.firefox.bin","D:\\ProgramFiles\\Mozilla Firefox\\firefox.exe");
WebDriver dr = new FirefoxDriver();
//打开指定路径的firefox,方法2
File pathToFirefoxBinary = new File("D:\\Program Files\\Mozilla Firefox\\firefox.exe");
FirefoxBinary firefoxbin = new FirefoxBinary(pathToFirefoxBinary);
WebDriver driver1 = new FirefoxDriver(firefoxbin,null);
}
}
2,打开具体的url
public class OpenUrl {
public static void main(String []args){
String url = "http://www.51.com";
WebDriver driver = new FirefoxDriver();
//用get方法
driver.get(url);
//用navigate方法,然后再调用to方法
driver.navigate().to(url);
}
}
3,关闭浏览器
public class CloseBrowser {
public static void main(String []args){
String url = "http://www.51.com";
WebDriver driver = new FirefoxDriver();
driver.get(url);
//用quit方法
driver.quit();
//用close方法
driver.close();
}
}
4,返回当前的url和title
public class GetUrlAndTitle {
public static void main(String []args){
String url = "http://www.google.com";
WebDriver driver = new FirefoxDriver();
driver.get(url);
//得到title
String title = driver.getTitle();
//得到当前页面url
String currentUrl = driver.getCurrentUrl();
//输出title和currenturl
System.out.println(title+"\n"+currentUrl);
}
}
5,其他方法getWindowHandle() 返回当前的浏览器的窗口句柄
getWindowHandles() 返回当前的浏览器的所有窗口句柄
getPageSource() 返回当前页面的源码
【定位页面元素】
selenium-webdriver提供了强大的元素定位方法,支持以下三种方法。
单个对象的定位方法
多个对象的定位方法
层级定位
定位单个元素
在定位单个元素时,selenium-webdriver提示了如下一些方法对元素进行定位。
By.className(className))
By.cssSelector(selector)
By.id(id)
By.linkText(linkText)
By.name(name)
By.partialLinkText(linkText)
By.tagName(name)
By.xpath(xpathExpression)
注意:selenium-webdriver通过findElement()\findElements()等find方法调用"By"对象来定位 和查询元素。By类只是提供查询的方式进行分类。findElement返回一个元素对象否则抛出异常,findElements返回符合条件的元素 List,如果不存在符合条件的就返回一个空的list。
1.使用className进行定位
当所定位的元素具有class属性的时候我们可以通过classname来定位该元素。
下面的例子定位了51.com首页上class为"username"的li。
Java代码
public class ByClassName {
public static void main(String[] args) {
WebDriver driver = new FirefoxDriver();
driver.get("http://www.51.com");
WebElement element = driver.findElement(By.className("username"));
System.out.println(element.getTagName());
}
}
输出结果:
Java代码
Li
2.使用id属性定位
51.com首页的帐号输入框的html代码如下:
Java代码
<input id="passport_51_user" type="text" value="" tabindex="1" title="用户名/彩虹号/邮箱"
name="passport_51_user">
在下面的例子中用id定位这个输入框,并输出其title,借此也可以验证代码是否工作正常。
Java代码
public class ByUserId {
public static void main(String[] args) {
// TODO Auto-generated method stub
WebDriver dr = new FirefoxDriver();
dr.get("http://www.51.com");
WebElement element = dr.findElement(By.id("passport_51_user"));
System.out.println(element.getAttribute("title"));
}
}
输出结果:
Java代码
用户名/彩虹号/邮箱
3.使用name属性定位
51.com首页的帐号输入框的html代码如下:
Java代码
<input id="passport_51_user" type="text" value="" tabindex="1" title="用户名/彩虹号/邮箱"
name="passport_51_user">
使用name定位
Java代码
public class ByUserId {
public static void main(String[] args) {
// TODO Auto-generated method stub
WebDriver dr = new FirefoxDriver();
dr.get("http://www.51.com");
WebElement e = dr.findElement(By.name("passport_51_user")); System.out.println(element.getAttribute("title"));
}
}
输出结果:
Java代码
用户名/彩虹号/邮箱
4.使用css属性定位
51.com首页的帐号输入框的html代码如下:
Java代码
<input id="passport_51_user" type="text" value="" tabindex="1" title="用户名/彩虹号/邮箱"
name="passport_51_user">
使用css定位
Java代码
WebElement e1 = dr.findElement(By.cssSelector("#passport_51_user"));
选择器:.class、#id、*、element、element>element、element+element、[attribute=value]
5.使用 XPATH定位
51.com首页的帐号输入框的html代码如下:
Java代码
<input id="passport_51_user" type="text" value="" tabindex="1" title="用户名/彩虹号/邮箱"
name="passport_51_user">
通过xpath查找:
Java代码
WebElement element =driver.findElement(By.xpath("//input[@id=' passport_51_user ']"));
语法:http://www.studyofnet.com/news/466.html
【robot framework的写法】
1;Xpath=//*[@id=”kw”]
//表示某个层级下 *表示某个标签名 @id=kw表示这个元素有个id等于kw
找上级
<form id=”form1” class=”fm” action=”/s” name=”f1” >
<span class=” bg s_ipt_wr”>
<input id=”kw1” class=”s_ipt” type=”text” maxlength=”100” name=”wd” utocpmplete=”off”>
找爸爸:
2;Xpath=//span[@class=”bg s_ipt_wr”]/input
如果爸爸没有唯一的属性值,可以找爷爷
Xpath=//form[@id=””form1]/span/input
一级一级往上找,直到找到html就是绝对路径
布尔值写法:
3;Xpath=//input[@id=”kw” and @name=”wd”]
先定位父级元素,再定位具体子元素:
WebElement类也可以支持查询子类元素。例如,假设页面上有一些重复的元素。但是,他们在不同的<div>中。可以先定位到其父元素<div>然后在定位其子元素,方法如下:
WebElement div = driver.findElement(By.id("div1"));
WebElement topLink = div.findElement(By.linkText("top"));
你也可以将他们缩写成一行:
WebElement topLink = driver.findElement
(By.id("div1")).findElement(By.linkText("top"));
6.使用其他方式定位
在定位link元素的时候,可以使用link和link_text属性;
假设页面元素写成这样:
<ahref="http://www.google.com/search?q=cheese">cheese</a>>
那么可以通过这样查找:
WebElement cheese =driver.findElement(By.linkText("cheese"));
另外还可以使用tag_name属性定位任意元素;
7.定位多个元素
上面提到findElements()方法可以返回一个符合条件的元素List组。看下面例子。
Java代码
public class FindElementsStudy {
public static void main(String[] args) {
WebDriver driver = new FirefoxDriver();
driver.get("http://www.51.com");
//定位到所有<input>标签的元素,然后输出他们的id
List<WebElement> element = driver.findElements(By.tagName("input"));
for (WebElement e : element){
System.out.println(e.getAttribute("id"));
}
driver.quit();
}
}
输出结果:
Java代码
passport_cookie_login
gourl
passport_login_from
passport_51_user
passport_51_password
passport_qq_login_2
btn_reg
passport_51_ishidden
passport_auto_login
上面的代码返回页面上所有input对象
8.层级定位
层级定位的思想是先定位父元素,然后再从父元素中精确定位出其我们需要选取的子元素。
层级定位一般的应用场景是无法直接定位到需要选取的元素,但是其父元素比较容易定位,通过定位父元素再遍历其子元素选择需要的目标元素,或者需要定位某个元素下所有的子元素。
下面的代码演示了如何使用层级定位class为"login"的div,然后再取得它下面的所有label,并打印出他们的文本
Java代码
public class LayerLocator {
public static void main(String[] args) {
WebDriver driver = new FirefoxDriver();
driver.get("http://www.51.com");
//定位class为"login"的div,然后再取得它下面的所有label,并打印出他们的值
WebElement element = driver.findElement(By.className("login"));
List<WebElement> el = element.findElements(By.tagName("label"));
for(WebElement e : el)
System.out.println(e.getText());
}
}
输出结果:
Java代码
帐号:
密码:
隐身
【页面元素的的操作】
1. 输入框(text field or textarea)
找到输入框元素:
WebElement element = driver.findElement(By.id("passwd-id"));
在输入框中输入内容:
element.sendKeys(“test”);
将输入框清空:
element.clear();
获取输入框的文本内容:
element.getText();
2. 下拉选择框(Select)
找到下拉选择框的元素:
Select select = new Select(driver.findElement(By.id("select")));
选择对应的选择项:
select.selectByVisibleText(“mediaAgencyA”);
或
select.selectByValue(“MA_ID_001”);
不选择对应的选择项:
select.deselectAll();
select.deselectByValue(“MA_ID_001”);
select.deselectByVisibleText(“mediaAgencyA”);
或者获取选择项的值:
select.getAllSelectedOptions();
select.getFirstSelectedOption();
对下拉框进行操作时首先要定位到这个下拉框,new 一个Selcet对象,然后对它进行操作
3. 单选项(Radio Button)
找到单选框元素:
WebElement bookMode =driver.findElement(By.id("BookMode"));
选择某个单选项:
bookMode.click();
清空某个单选项:
bookMode.clear();
判断某个单选项是否已经被选择:
bookMode.isSelected();
4. 多选项(checkbox)
多选项的操作和单选的差不多:
WebElement checkbox =driver.findElement(By.id("myCheckbox."));
checkbox.click();
checkbox.clear();
checkbox.isSelected();
checkbox.isEnabled();
5. 按钮(button)
找到按钮元素:
WebElement saveButton = driver.findElement(By.id("save"));
点击按钮:
saveButton.click();
判断按钮是否enable:
saveButton.isEnabled ();
6. 左右选择框
也就是左边是可供选择项,选择后移动到右边的框中,反之亦然。例如:
Select Select(driver.findElement(By.id("languages")));
lang.selectByVisibleText(“English”);
WebElement addLanguage =driver.findElement(By.id("addButton"));
addLanguage.click();
7. 弹出对话框(Popup dialogs)
Alert alert = driver.switchTo().alert();
alert.accept();
alert.dismiss();
alert.getText();
8. 表单(Form)
Form中的元素的操作和其它的元素操作一样,对元素操作完成后对表单的提交可以:
WebElement approve = driver.findElement(By.id("approve"));
approve.click();
或
approve.submit();//只适合于表单的提交
9. 上传文件 (Upload File)
上传文件的元素操作:
WebElement adFileUpload = driver.findElement(By.id("WAP-upload"));
String filePath = "C:\test\\uploadfile\\media_ads\\test.jpg";
adFileUpload.sendKeys(filePath);
10.拖拉(Drag andDrop)
WebElement element =driver.findElement(By.name("source"));
WebElement target = driver.findElement(By.name("target"));
(new Actions(driver)).dragAndDrop(element, target).perform();
11.导航 (Navigationand History)
打开一个新的页面:
driver.navigate().to("http://www.example.com");
通过历史导航返回原页面:
driver.navigate().forward();
driver.navigate().back();
【iframe的处理】
有时候我们在定位一个页面元素的时候发现一直定位不了,反复检查自己写的定位器没有任何问题,代码也没有任何问题。这时你就要看一下这个页面元素是 否在一个iframe中,这可能就是找不到的原因之一。如果你在一个default content中查找一个在iframe中的元素,那肯定是找不到的。反之你在一个iframe中查找另一个iframe元素或default content中的元素,那必然也定位不到。
selenium webdriver中提供了进入一个iframe的方法:
WebDriver org.openqa.selenium.WebDriver.TargetLocator.frame(String nameOrId)
也提供了一个返回default content的方法:
WebDriver org.openqa.selenium.WebDriver.TargetLocator.defaultContent()
这样使我们面对iframe时可以轻松应对。
以下面的html代码为例,我们看一下处现iframe。
Html代码
main.html
<html>
<head>
<title>FrameTest</title>
</head>
<body>
<div id = "id1">this is a div!</div>
<iframe id = "frame" frameborder="0" scrolling="no" style="left:0;position:absolute;" src = "frame.html"></iframe>
</body>
</html>
frame.html
<html>
<head>
<title>this is a frame!</title>
</head>
<body>
<div id = "div1">this is a div,too!</div>
<label>input:</label>
<input id = "input1"></input>
</body>
</html>
Java代码
public class FameStudy {
public static void main(String[] args) {
WebDriver dr = new FirefoxDriver();
String url = "\\Your\\Path\\to\\main.html";
dr.get(url);
//在default content定位id="id1"的div
dr.findElement(By.id("id1"));
//此时,没有进入到id="frame"的frame中时,以下两句会报错
dr.findElement(By.id("div1"));//报错
dr.findElement(By.id("input1"));//报错
//进入id="frame"的frame中,定位id="div1"的div和id="input1"的输入框。
dr.switchTo().frame("frame");
dr.findElement(By.id("div1"));
dr.findElement(By.id("input1"));
//此时,没有跳出frame,如果定位default content中的元素也会报错。
dr.findElement(By.id("id1"));//报错
//跳出frame,进入default content;重新定位id="id1"的div
dr.switchTo().defaultContent();
dr.findElement(By.id("id1"));
}
}
小结:
switch_to方法会new1个TargetLocator对象,使用该对象的frame方法可以将当前识别的”主体”移动到需要定位的frame上去。
【得到弹出的窗口】
在selenium 1.X里面得到弹出窗口是一件比较麻烦的事,特别是新开窗口没有id、name的时候。在selenium webdriver中得到新开窗口相对简单的多,它无关新开窗口的id、name等属性。以下面的html为例:
Html代码
<span style="white-space: normal; background-color: #ffffff;">test.html</span>
<html>
<head><title>Test Popup Window</title></head>
<body>
<a id = "51" href = "http://www.51.com/" target = "_blank">Let's go!</a>
</body>
</html>
下面的代码演示了如何去得到弹出的新窗口
Java代码
public class PopupWindowTest {
public static void main(String[] args) {
System.setProperty("webdriver.firefox.bin","D:\\Program Files\\Mozilla Firefox\\firefox.exe");
WebDriver dr = new FirefoxDriver();
String url ="\\Your\\Path\\to\\main.html";
dr.get(url);
dr.findElement(By.id("51")).click();
//得到当前窗口的句柄
String currentWindow = dr.getWindowHandle();
//得到所有窗口的句柄
Set<String> handles = dr.getWindowHandles();
Iterator<String> it = handles.iterator();
while(it.hasNext()){
if(currentWindow == it.next()) continue;
dr.switchTo().window(it.next());
}
}
}
输出结果:
title,url = 51.com 真人配对玩游戏,http://www.51.com/
小结:
捕获或者说定位弹出窗口的关键在于获得弹出窗口的句柄。(
在上面的代码里,使用windowhandle方法来获取当前浏览器窗口的句柄,使用了windowhandles方法获取所有弹出的浏览器窗口的句柄,然后通过排除当前句柄的方法来得到新开窗口的句柄。
在获取新弹出窗口的句柄后,使用switchto.window(newwindow_handle)方法,将新窗口的句柄作为参数传入既可捕获到新窗口了。
如果想回到以前的窗口定位元素,那么再调用1次switchto.window方法,传入之前窗口的句柄既可达到目的。
【处理alert,confirm,prompt对话框】
Html代码
Dialogs.html
<html>
<head>
<title>Alert</title>
</head>
<body>
<input id = "alert" value = "alert" type = "button" onclick = "alert('欢迎!请按确认继续!');"/>
<input id = "confirm" value = "confirm" type = "button" onclick = "confirm('确定吗?');"/>
<input id = "prompt" value = "prompt" type = "button" onclick = "var name = prompt('请输入你的名字:','请输入
你的名字'); document.write(name) "/>
</body>
</html>
以上html代码在页面上显示了三个按钮,点击他们分别弹出alert、confirm、prompt对话框。如果在prompt对话框中输入文字点击确定之后,将会刷新页面,显示出这些文字 。
selenium webdriver 处理这些弹层的代码如下:
Java代码
public class DialogsStudy {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.setProperty("webdriver.firefox.bin","D:\\Program Files\\Mozilla Firefox\\firefox.exe");
WebDriver dr = new FirefoxDriver();
String url = "file:///C:/Documents and Settings/gongjf/桌面/selenium_test/Dialogs.html";// "/Your/Path/to/main.html"
dr.get(url);
//点击第一个按钮,输出对话框上面的文字,然后叉掉
dr.findElement(By.id("alert")).click();
Alert alert = dr.switchTo().alert();
String text = alert.getText();
System.out.println(text);
alert.dismiss();
//点击第二个按钮,输出对话框上面的文字,然后点击确认
dr.findElement(By.id("confirm")).click();
Alert confirm = dr.switchTo().alert();
String text1 = confirm.getText();
System.out.println(text1);
confirm.accept();
//点击第三个按钮,输入你的名字,然后点击确认,最后
dr.findElement(By.id("prompt")).click();
Alert prompt = dr.switchTo().alert();
String text2 = prompt.getText();
System.out.println(text2);
prompt.sendKeys("jarvi");
prompt.accept();
}
}
小结:
从以上代码可以看出dr.switchTo().alert();这句可以得到alert\confirm\prompt对话框的对象,然后运用其方法对它进行操作。对话框操作的主要方法有:
getText() 得到它的文本值
accept() 相当于点击它的"确认"
dismiss() 相当于点击"取消"或者叉掉对话框
sendKeys() 输入值,这个alert\confirm没有对话框就不能用了,不然会报错。
【下载】
webdriver允许我们设置默认的文件下载路径。也就是说文件会自动下载并且存在设置的那个目录中。
下面会给出firefox浏览器的具体设置方法。
代码
driver = Selenium::WebDriver.for :chrome, :profile => profile
# for firefox
FirefoxProfile firefoxProfile = new FirefoxProfile();
firefoxProfile.setPreference("browser.download.folderList",2);
firefoxProfile.setPreference("browser.download.manager.showWhenStarting",false);
firefoxProfile.setPreference("browser.download.dir","c:\\downloads");
firefoxProfile.setPreference("browser.helperApps.neverAsk.saveToDisk","text/csv");
WebDriver driver = new FirefoxDriver(firefoxProfile);
//new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"), capability);
driver.navigate().to(http://www.myfile.com/hey.csv);
【操作cookies】
Web 测试中我们经常会接触到Cookies,一个Cookies主要属性有”所在域、name、value、有效日期和路径",下面来讲一下怎么操作Cookies
Java代码
public class CookiesStudy {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.setProperty("webdriver.firefox.bin","D:\\Program Files\\Mozilla Firefox\\firefox.exe");
WebDriver dr = new FirefoxDriver();
dr.get("http://www.51.com");
//增加一个name = "name",value="value"的cookie
Cookie cookie = new Cookie("name", "value");
dr.manage().addCookie(cookie);
//得到当前页面下所有的cookies,并且输出它们的所在域、name、value、有效日期和路径
Set<Cookie> cookies = dr.manage().getCookies();
System.out.println(String.format("Domain -> name -> value -> expiry -> path"));
for(Cookie c : cookies)
System.out.println(String.format("%s -> %s -> %s -> %s -> %s",
c.getDomain(), c.getName(), c.getValue(),c.getExpiry(),c.getPath()));
//删除cookie有三种方法
//第一种通过cookie的name
dr.manage().deleteCookieNamed("CookieName");
//第二种通过Cookie对象
dr.manage().deleteCookie(cookie);
//第三种全部删除
dr.manage().deleteAllCookies();
}
附加cookies:
获取cookie的值:
Set<Cookie> allCookies = driver.manage().getCookies();
for (Cookie loadedCookie : allCookies) {
System.out.println(String.format("%s -> %s",loadedCookie.getName(), loadedCookie.getValue()));
}
根据某个cookie的name获取cookie的值:
driver.manage().getCookieNamed("mmsid");
删除cookie:
// You can delete cookies in 3 ways
// By name
driver.manage().deleteCookieNamed("CookieName");
// By Cookie
driver.manage().deleteCookie(loadedCookie);
// Or all of them
driver.manage().deleteAllCookies();
小结:
上面的代码首先在页面中增加了一个cookie,然后遍历页面的所有cookies,并输出他们的主要属性。最后就是三种删除cookie的方法。
【调用javascript】
Web driver对Java Script的调用是通过JavascriptExecutor来实现的,例如:
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("(function(){inventoryGridMgr.setTableFieldValue('"+ inventoryId + "','" + fieldName + "','"+ value + "');})()");
打开一个alter框,然后这里driver被强制转换成JavaScriptExecutor:
public static void main(String[] agrs){
WebDriver driver=new FirefoxDriver();
((JavascriptExecutor)driver).executeScript("alter"(\"hello\")");
}
改变user agent
【改变user agent】
User Agent的设置是平时使用得比较多的操作:
FirefoxProfile profile = new FirefoxProfile();
profile.addAdditionalPreference("general.useragent.override","some UA string");
WebDriver driver = new FirefoxDriver(profile);
【等待页面元素加载完】
web的自动化测试中,我们经常会遇到这样一种情况:当我们的程序执行时需要页面某个元素,而此时这个元素还未加载完成,这时我们的程序就会报错。怎么办?等待。等待元素出现后再进行对这个元素的操作。
在selenium-webdriver中我们用两种方式进行等待:明确的等待和隐性的等待。
明确的等待
明确的等待是指在代码进行下一步操作之前等待某一个条件的发生。最不好的情况是使用Thread.sleep()去设置一段确认的时间去等待。但为 什么说最不好呢?因为一个元素的加载时间有长有短,你在设置sleep的时间之前要自己把握长短,太短容易超时,太长浪费时间。selenium webdriver提供了一些方法帮助我们等待正好需要等待的时间。利用WebDriverWait类和ExpectedCondition接口就能实现这一点。
下面的html代码实现了这样的一种效果:点击click按钮5秒钟后,页面上会出现一个红色的div块。我们需要写一段自动化脚本去捕获这个出现的div,然后高亮之。
Html代码
Wait.html
<html>
<head>
<title>Set Timeout</title>
<style>
.red_box {background-color: red; width = 20%; height: 100px; border: none;}
</style>
<script>
function show_div(){
setTimeout("create_div()", 5000);
}
function create_div(){
d = document.createElement('div');
d.className = "red_box";
document.body.appendChild(d);
}
</script>
</head>
<body>
<button id = "b" onclick = "show_div()">click</button>
</body>
</html>
下面的代码实现了高亮动态生成的div块的功能:
Java代码
public class WaitForSomthing {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.setProperty("webdriver.firefox.bin","D:\\Program Files\\Mozilla Firefox\\firefox.exe");
WebDriver dr = new FirefoxDriver();
String url = "file:///C:/Documents and Settings/gongjf/桌面/selenium_test/Wait.html";// "/Your/Path/to/Wait.html"
dr.get(url);
WebDriverWait wait = new WebDriverWait(dr,10);
wait.until(new ExpectedCondition<WebElement>(){
@Override
public WebElement apply(WebDriver d) {
return d.findElement(By.id("b"));
}}).click();
WebElement element = dr.findElement(By.cssSelector(".red_box"));
((JavascriptExecutor)dr).executeScript("arguments[0].style.border = \"5px solid yellow\"",element);
}
}
上面的代码WebDriverWait类的构造方法接受了一个WebDriver对象和一个等待最长时间(10秒)。然后调用until方法,其中重写了 ExpectedCondition接口中的apply方法,让其返回一个WebElement,即加载完成的元素,然后点击。默认情况下,WebDriverWait每500毫秒调用一次ExpectedCondition,直到有成功的返回,当然如果超过设定的值还没有成功的返回,将抛出异常。
附加 显性等待:
WebDriver driver =new FirefoxDriver();
driver.get("http://somedomain/url_that_delays_loading");
WebElement myDynamicElement = (new WebDriverWait(driver, 10))
.until(new ExpectedCondition<WebElement>(){
@Override
public WebElement apply(WebDriver d) {
returnd.findElement(By.id("myDynamicElement"));
}});
隐性等待
隐性等待是指当要查找元素,而这个元素没有马上出现时,告诉WebDriver查询Dom一定时间。默认值是0,但是设置之后,这个时间将在WebDriver对象实例整个生命周期都起作用。上面的代码就变成了这样:
Java代码
public class WaitForSomthing {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.setProperty("webdriver.firefox.bin","D:\\Program Files\\Mozilla Firefox\\firefox.exe");
WebDriver dr = new FirefoxDriver();
//设置10秒
dr.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
String url = "file:///C:/Documents and Settings/gongjf/桌面/selenium_test/Wait.html";// "/Your/Path/to/Wait.html"
dr.get(url);
//注释掉原来的
/*WebDriverWait wait = new WebDriverWait(dr,10);
wait.until(new ExpectedCondition<WebElement>(){
@Override
public WebElement apply(WebDriver d) {
return d.findElement(By.id("b"));
}}).click();*/
dr.findElement(By.id("b")).click();
WebElement element = dr.findElement(By.cssSelector(".red_box"));
((JavascriptExecutor)dr).executeScript("arguments[0].style.border = \"5px solid yellow\"",element);
}
}
小结:
两种方法任选其一
【截图】
在自动化测试中常常会用到截图功能。可以截取页面全图,不管页面有多长。
下面的代码演示了如何使用webdriver进行截图:
driver = webdriver.Firefox()driver.save_screenshot("C:\error.jpg")
Java代码
public class ShotScreen {
public static void main(String[] args) throws IOException, InterruptedException {
System.setProperty("webdriver.firefox.bin","D:\\Program Files\\Mozilla Firefox\\firefox.exe");
WebDriver dr = new FirefoxDriver();
dr.get("http://www.baidu.com");
//这里等待页面加载完成
Thread.sleep(5000);
//下面代码是得到截图并保存在D盘下
File screenShotFile = ((TakesScreenshot)dr).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(screenShotFile, new File("D:/test.png"));
}
}
【超时设置】
webdriver中可以设置很多的超时时间
· implicitlyWait。识别对象时的超时时间。过了这个时间如果对象还没找到的话就会抛出NoSuchElement异常
· setScriptTimeout。异步脚本的超时时间。webdriver可以异步执行脚本,这个是设置异步执行脚本脚本返回结果的超时时间
· pageLoadTimeout。页面加载时的超时时间。因为webdriver会等页面加载完毕在进行后面的操作,所以如果页面在这个超时时间内没有加载完成,那么webdriver就会抛出异常
代码
# 定位对象时给3s的时间
# 如果3s内还定位不到则抛出异常
driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
# 页面加载超时时间设置为5s
dr.manage().timeouts().pageLoadTimeout(5, TimeUnit.SECONDS);
# 异步脚本的超时时间设置成3s
dr.manage().timeouts().setScriptTimeout(3, TimeUnit.SECONDS);
【封装和重用】
WebDriver对页面的操作,需要找到一个WebElement,然后再对其进行操作,比较繁琐:
// Find the text inputelement by its name
WebElement element = driver.findElement(By.name("q"));
// Enter something to search for
element.sendKeys("Cheese!");
我们可以考虑对这些基本的操作进行一个封装,简化操作。比如,封装代码:
protected void sendKeys(Byby, String value){
driver.findElement(by).sendKeys(value);
}
那么,在测试用例可以这样简化调用:
sendKeys(By.name("q"),”Cheese!”);
看,这就简洁多了。
类似的封装还有:
public class WebDriverAction {
//protected WebDriverdriver;
protected RemoteWebDriverdriver;
protected WebDriverWaitdriverWait;
protected booleanisWebElementExist(By selector) {
try {
driver.findElement(selector);
return true;
} catch(NoSuchElementException e) {
return false;
}
}
protected StringgetWebText(By by) {
try {
return driver.findElement(by).getText();
} catch (NoSuchElementException e) {
return "Textnot existed!";
}
}
protected voidclickElementContainingText(By by, String text){
List<WebElement>elementList = driver.findElements(by);
for(WebElement e:elementList){
if(e.getText().contains(text)){
e.click();
break;
}
}
}
protected StringgetLinkUrlContainingText(By by, String text){
List<WebElement>subscribeButton = driver.findElements(by);
String url = null;
for(WebElement e:subscribeButton){
if(e.getText().contains(text)){
url =e.getAttribute("href");
break;
}
}
return url;
}
protected void click(Byby){
driver.findElement(by).click();
driver.manage().timeouts().implicitlyWait(TestConstant.WAIT_ELEMENT_TO_LOAD,TimeUnit.SECONDS);
}
protected StringgetLinkUrl(By by){
return driver.findElement(by).getAttribute("href");
}
protected void sendKeys(Byby, String value){
driver.findElement(by).sendKeys(value);
}
小结:
按照上面的例子你可以对各个方法进行封装,使自己的代码更加简洁!
【调用selenium1的api】
Selenium2.0中使用WeDriver API对页面进行操作,它最大的优点是不需要安装一个selenium server就可以运行,但是对页面进行操作不如selenium1.0的Selenium RC API那么方便。Selenium2.0提供了使用Selenium RC API的方法:
// 我用火狐浏览器作为例子
WebDriver driver = new FirefoxDriver();
String baseUrl ="http://www.google.com";
Selenium selenium = new WebDriverBackedSelenium(driver, baseUrl);
// 执行selenium命令
selenium.open("http://www.google.com");
selenium.type("name=q", "cheese");
selenium.click("name=btnG");
WebDriver driverInstance = ((WebDriverBackedSelenium)selenium).getUnderlyingWebDriver();
selenium.stop();
我分别使用WebDriver API和SeleniumRC API写了一个Login的脚本,很明显,后者的操作更加简单明了。
WebDriver API写的Login脚本:
public void login() {
driver.switchTo().defaultContent();
driver.switchTo().frame("mainFrame");
WebElement eUsername= waitFindElement(By.id("username"));
eUsername.sendKeys([email protected]);
WebElement ePassword= waitFindElement(By.id("password"));
ePassword.sendKeys(manager);
WebElementeLoginButton = waitFindElement(By.id("loginButton"));
eLoginButton.click();
}
SeleniumRC API写的Login脚本:
public void login() {
selenium.selectFrame("relative=top");
selenium.selectFrame("mainFrame");
selenium.type("username","[email protected]");
selenium.type("password","manager");
selenium.click("loginButton");
}
u 使用findElements方法来定位元素
findElements()方法会返回匹配指定查询条件的WebElements的集合(即:可以得到匹配指定规则的集合)。如果没有找到则返回为空。
JAVA实例代码:
package com.example.tests;
import static org.junit.Assert.*;
import java.util.*;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.ie.InternetExplorerDriver;
public class Selenium2
{
@Test
public void test()
{
WebDriver driver = new InternetExplorerDriver();
driver.get("http://www.baidu.com");
List<WebElement> links = driver.findElements(By.cssSelector("#nv a"));
//验证链接数量
assertEquals(10, links.size());
//打印href属性
for (int i = 0; i < links.size(); i++)
{
System.out.println(links.get(i).getAttribute("href"));
}
driver.close();
}
}
u 定位链接
WebElement gmailLink = driver.findElement(By.linkText("GMail"));
assertEquals("http://mail.google.com/",gmailLink.getAttribute("href"));
通过部分链接名定位链接
WebElement inboxLink =
driver.findElement(By.partialLinkText("Inbox"));
System.out.println(inboxLink.getText());
u 通过标签名称定位元素
WebElement table = driver.findElement(By.id("summaryTable"));
List<WebElement> rows = table.findElements(By.tagName("tr"));
assertEquals(10, rows.size());
u 使用CSS选择器定位元素
使用绝对路径定位元素:
WebElement userName = driver.findElement(By.cssSelector("html body div div form input"));
使用相对路径定位元素:
当我们使用CSS选择器来查找元素的时候,我们可以使用class属性来定位元素。我们可以先指定一个HTML的标签,然后加一个“.”符号,跟上class属性的值,方法如下:
WebElement loginButton =
driver.findElement(By.cssSelector("input.login"));
ID选择器定位元素:
先指定一个HTML标签,然后加上一个“#”符号,跟上id的属性值,如下所示:
WebElement userName =
driver.findElement(By.cssSelector("input#username"));
使用其他属性的选择器定位元素:
使用name选择器:
WebElement userName =
driver.findElement(By.cssSelector("input[name=username]"));
使用alt选择器:
WebElement previousButton =
driver.findElement(By.cssSelector("img[alt='Previous']"));
使用多个属性选择器定位元素:
WebElement previousButton = driver.findElement(By.cssSelector("input[type='submit'][value='Login']"));
u 使用XPath定位元素
使用绝对路径:
WebElement userName =
driver.findElement(By.xpath("html/body/div/div/form/input"));
使用相对路径:
处于DOM中第一个<input>元素:
WebElement userName = driver.findElement(By.xpath("//input"));
使用索引定位DOM中的第二个<input>元素:
WebElement passwd=driver.findElement(By.xpath("//input[2]"));
使用Xpath和属性值定位元素:
WebElement previousButton = driver.findElement
(By.xpath("//input[@type='submit'and @value='Login']"));
u 使用jQuery选择器
以百度首页为例,百度首页没有jQuery库。我们想定位百度导航栏上面的所有超链接元素,并输出结果。
package com.example.tests;
import static org.junit.Assert.*;
import java.util.*;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.ie.InternetExplorerDriver;
public class Selenium2 {
WebDriver driver = new InternetExplorerDriver();
JavascriptExecutor jse = (JavascriptExecutor)driver;
@Test
public void jQueryTest() {
driver.get("http://www.baidu.com/");
injectjQueryIfNeeded();
List<WebElement> elements =
(List<WebElement>)jse.executeScript
("return jQuery.find('#nv a')");
assertEquals(7,elements.size()); //验证超链接的数量
for (int i = 0; i < elements.size(); i++) {
System.out.print(elements.get(i).getText() + "、");
}
driver.close();
}
private void injectjQueryIfNeeded() {
if (!jQueryLoaded())
injectjQuery();
}
//判断是已加载jQuery
public Boolean jQueryLoaded() {
Boolean loaded;
try {
loaded = (Boolean)jse.executeScript("return " +
"jQuery()!=null");
} catch (WebDriverException e) {
loaded = false;
}
return loaded;
}
//通过注入jQuery
public void injectjQuery() {
jse.executeScript(" var headID = "
+"document.getElementsByTagName(\"head\")[0];"
+ "var newScript = document.createElement('script');"
+ "newScript.type = 'text/javascript';"
+ "newScript.src = "
+"'http://ajax.googleapis.com/ajax/"
+"libs/jquery/1.7.2/jquery.min.js';"
+ "headID.appendChild(newScript);");
}
}
injectjQueryIfNeeded()方法首先通过jQueryLoaded()方法来判断网页中是否加有jQuery对象。如果没有,再调用injectjQuery()方法通过增加一个<Script>元素来实时加载jQuery库,参考的是Google在线库,可修改例子中的版本,使用最新的jQuery版本。
u 定位表格的行和列
表格相关的页面元素
package com.example.tests;
import static org.junit.Assert.*;
import java.util.*;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.ie.InternetExplorerDriver;
public class Selenium2
{
WebDriver driver = new InternetExplorerDriver();
JavascriptExecutor jse = (JavascriptExecutor)driver;
@Test
public void tableTest()
{
driver.get
("http://www.w3school.com.cn/html/html_tables.asp");
//首先得到所有tr的集合
List<WebElement> rows =
driver.findElements(By.cssSelector(".dataintable tr"));
//验证表格的行数
assertEquals(11,rows.size());
//打印出所有单元格的数据
for (WebElement row : rows)
{
//得到当前tr里td的集合
List<WebElement> cols =
row.findElements(By.tagName("td"));
for (WebElement col : cols)
{
System.out.print(col.getText());//得到td里的文本
}
System.out.println();
}
driver.close();
}
}
u 检查元素的文本
@Test
public void testElementText()
{
//取得元素
WebElement message = driver.findElement(By.id("message"));
//得到元素文本
String messageText = message.getText();
//验证文本为"Click on me and mycolor will change"
assertEquals("Click on me and my color will change", messageText);
//获得area元素
WebElement area = driver.findElement(By.id("area"));
//验证文本为"Div's Text\nSpan's Text"
assertEquals("Div's Text\nSpan's Text",area.getText());
}
WebElement中的getText()方法返回元素的innerText属性。所以元素里面如果有子节点一样也会被反回出来
也可以使用JavaString API方法如contains(),startsWith(),endsWith()来进行部分匹配。方法如下:
assertTrue(messageText.contains("color"));
assertTrue(messageText.startsWith("Click on"));
assertTrue(messageText.endsWith("will change"));
u 检查元素的属性值
此处需要使用getAttribute()方法来检查元素的属性。
创建一个测试,定位元素再检查它的属性,方法如下:
@Test
public void testElementAttribute()
{
WebElement message = driver.findElement(By.id("message"));
assertEquals("justify",message.getAttribute("align"));
}
此例子中验证了元素的属性align的值是否为justify。
u 检查元素的CSS属性值
让我们创建一个测试,读取元素的CSS的width属性并验证它的值。
@Test
public void testElementStyle()
{
WebElement message = driver.findElement(By.id("message"));
String width = message.getCssValue("width");
assertEquals("150px",width);
}
u 针对鼠标和键盘事件使用高级的用户交互API
Selenium WebDriver高级用户交互API允许我们通过使用Actions类执行从键盘事件到简单或复杂的鼠标事件,如拖拽操作,按住一个按键然后执行鼠标操作,创建一个复杂的事件链就像用户真正的在手动操作一样。
我们创建一个测试使用Ctrl按键来选择表格的多个行。我们可以先选择第一行,然后按住ctrl键,再选择另一行后释放ctrl键。这样就可以选择所需要的行。
@Test
public void testRowSelectionUsingControlKey()
{
List<WebElement> tableRows = driver.findElements
(By.xpath("//table[@class='iceDatTbl']/tbody/tr"));
//Select second and fourth row from table using Control Key.
//Row Index start at 0
Actions builder = new Actions(driver);
builder.click(tableRows.get(1)).keyDown(Keys.CONTROL).click(tableRows.get(3)).keyUp(Keys.CONTROL).build().perform();
//Verify Selected Row table shows two rows selected
List<WebElement> rows = driver.findElements
(By.xpath("//div[@class='icePnlGrp exampleBox']/table[@class='iceDatTbl']/tbody/tr"));
assertEquals(2,rows.size());
}
首先创建一个Actions的实例,再调用相应的事件方法,然后调用build()方法,建立这么一组操作方法链,最后调用perform()来执行。
u 在元素上执行双击操作
package com.example.tests;
import static org.junit.Assert.*;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.interactions.Actions;
public class Selenium2 {
WebDriver driver = new FirefoxDriver();
@Test
public void actionsTest() {
driver.get("D:\\demo\\DoubleClickDemo.html");
WebElement message = driver.findElement(By.id("message"));
// 验证初始字体为14px
assertEquals("14px", message.getCssValue("font-size"));
Actions builder = new Actions(driver);
builder.doubleClick(message).build().perform();
// 验证点击后字体变为20px
assertEquals("20px", message.getCssValue("font-size"));
driver.close();
}
}
当鼠标双击的时候触发了字体变化的事件,我们可以使用doubleClick()来模拟真实的双击。
u 执行拖拽操作
package com.example.tests;
import static org.junit.Assert.*;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.interactions.Actions;
public class Selenium2 {
@Test
public void testDragDrop() {
WebDriver driver = new InternetExplorerDriver();
driver.get("D:\\demo\\DragAndDrop.html");
WebElement source = driver.findElement(By.id("draggable"));
WebElement target = driver.findElement(By.id("droppable"));
Actions builder = new Actions(driver);
builder.dragAndDrop(source, target).perform();
try {
assertEquals("Dropped!", target.getText());
} catch (Error e) {
e.printStackTrace();
}finally{
driver.close();
}
}
}
拖拽一个元素到另一个元素再放下,我们需要先定位返些元素(原元素,目标元素)然后作为参数传给dragAndDrop()。
u 执行JavaScript代码
package com.example.tests;
import static org.junit.Assert.*;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.ie.InternetExplorerDriver;
public class Selenium2 {
@Test
public void testJavaScriptCalls() {
WebDriver driver = new InternetExplorerDriver();
driver.get("http://www.baidu.com");
JavascriptExecutor js = (JavascriptExecutor) driver;
String title = (String) js.executeScript("return document.title");
assertEquals("百度一下,你就知道", title);
long links = (Long) js.executeScript("var links = "
+ "document.getElementsByTagName('A'); "
+ "return links.length");
assertEquals(26, links);
driver.close();
}
}
从javaScript代码中迒回数据,我们需要使用return关键字。基亍迒回值癿类型,我们需要对executeScript()方法迕行转型。对亍带小数点癿值,使用Double类型,非小数值可以使用Long类型,布尔值可以使用Boolean类型,如果迒回癿是HTML节点,可以使用 WebElement类型,文本值,可以使用String类型。如果迒回癿是对象列表,基亍对象类型癿仸何值都可以。
u 使用Selenium WebDriver进行截图
Selenium WebDriver提供了TakesScreenshot接口来捕捉网页的全屏。返可以在测试执行遇到异常错误时候将屏幕戔叏下来,可以知道弼时収生了什么。我们也可以在验证元素状态,显示的值是某个操作完成后的状态迕行截屏。
package com.example.tests;
import java.io.File;
import org.apache.commons.io.FileUtils;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.ie.InternetExplorerDriver;
public class Selenium2 {
@Test
public void testTakesScreenshot() {
WebDriver driver = new InternetExplorerDriver();
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.close();
}
}
TakesScreenshot接口提供了getScreenshotAs()方法来捕捉屏幕。上面的例子中,我们指定了OutputType.FILE作为参数传递给getScreenshoAs()方法,告诉它将截取的屏幕以文件形式返回。
使用org.apache.commons.io.FileUtils类中的copyFile()方法来保存getScreenshot()返回的文件对象。TakesScreenshot接口依赖于浏览器中的API来捕捉屏幕。所以在HtmlUnit Driver中不支持这样使用。
u 将浏览器窗口最大化
package com.example.tests;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.ie.InternetExplorerDriver;
public class Selenium2 {
@Test
public void testTakesScreenshot() {
WebDriver driver = new InternetExplorerDriver();
driver.get("http://www.baidu.com");
driver.manage().window().maximize();
driver.close();
}
}
u 自动选择下拉列表
package com.example.tests;
import static org.junit.Assert.*;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.Select;
public class Selenium2 {
@Test
public void testDropdown() {
WebDriver driver = new FirefoxDriver();
driver.get("D:\\demo\\Droplist.html");
//得到下拉列表框
Select make =
new Select(driver.findElement(By.name("make")));
//验证下拉列表的不支持多选
assertFalse(make.isMultiple());
//验证下拉列表的数量
assertEquals(4,make.getOptions().size());
//命名用可见的本文来选择选项
make.selectByVisibleText("Honda");
//通过value属性来选择选项
make.selectByValue("Audi");
//通过索引来选择选项
make.selectByIndex(2);
driver.close();
}
}
在执行下面的例子时需要导入org.openqa.selenium.support.ui.Select类。首先创建一个Select癿对象,
isMultiple()用来判断是丌是多选下拉框。
Select类提供了3种方法来选择下拉选项:
selectByVisibleText(),selectByValue(),selectByIndex()。
package com.example.tests;
import static org.junit.Assert.*;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.Select;
public class Selenium2 {
@Test
public void testMultipleSelectLis() {
WebDriver driver = new FirefoxDriver();
driver.get("D:\\demo\\Droplist.html");
// 得到下拉列表框
Select color = new Select(driver.findElement(By.name("color")));
// 验证下拉列表支持多选
assertTrue(color.isMultiple());
// 验证下拉列表的数量
assertEquals(4, color.getOptions().size());
// 使用可见的本文来选择选项
color.selectByVisibleText("Black");
color.selectByVisibleText("Red");
color.selectByVisibleText("Silver");
// 通过可见的文本取消已选选项
color.deselectByVisibleText("Silver");
// 通过value属性取消已选选项
color.deselectByValue("red");
// 通过选项索引取消已选选项
color.deselectByIndex(0);
}
}
u 检查下拉列表中的选项
检查单选的下拉框:
package com.example.tests;
import static org.junit.Assert.*;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.Select;
public class Selenium2 {
@Test
public void testDropdown() {
WebDriver driver = new FirefoxDriver();
driver.get("D:\\demo\\Droplist.html");
//得到下拉列表框
Select make =
new Select(driver.findElement(By.name("make")));
//验证下拉列表的不支持多选
assertFalse(make.isMultiple());
//验证下拉列表的数量
assertEquals(4,make.getOptions().size());
//使用可见的本文来选择选项
make.selectByVisibleText("Honda");
assertEquals
("Honda",make.getFirstSelectedOption().getText());
//通过value属性来选择选项
make.selectByValue("Audi");
assertEquals("Audi",
make.getFirstSelectedOption().getText());
//通过索引来选择选项
make.selectByIndex(2);
assertEquals("BMW",
make.getFirstSelectedOption().getText());
}
}
检查多选的下拉框:
import static org.junit.Assert.*;
import java.util.*;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.Select;
public class Selenium2 {
@Test
public void testMultipleSelectLis() {
WebDriver driver = new FirefoxDriver();
driver.get("D:\\demo\\Droplist.html");
//得到下拉列表框
Select color = new Select(driver.findElement(By.name("color")));
//验证下拉列表支持多选
assertTrue(color.isMultiple());
//验证下拉列表的数量
assertEquals(4,color.getOptions().size());
//用可见的本文来选择选项
color.selectByVisibleText("Black");
color.selectByVisibleText("Red");
color.selectByVisibleText("Silver");
//验证所选的选项
List<String> exp_sel_options =
Arrays.asList(new String[] {"Black","Red","Silver"});
List<String> act_sel_options = new ArrayList<String>();
for(WebElement option:color.getAllSelectedOptions()){
act_sel_options.add(option.getText());
}
//验证选择的选项和我们期望的是一样的
assertArrayEquals
(exp_sel_options.toArray(), act_sel_options.toArray());
//验证3个选项已经被选择了
assertEquals(3, color.getAllSelectedOptions().size());
//通过可见的文本取消已选选项
color.deselectByVisibleText("Silver");
assertEquals(2, color.getAllSelectedOptions().size());
//通过value属性取消已选选项
color.deselectByValue("red");
assertEquals(1, color.getAllSelectedOptions().size());
//通过选项索引取消已选选项
color.deselectByIndex(0);
assertEquals(0, color.getAllSelectedOptions().size());
}
}
如果只是单选的下拉列表,通过getFirstSelectedOption()就可以得到所选择的选项,再调用getText()就可以得到本文。如果是多选的下拉列表,使用getAllSelectedOptions()得到所有已选择的选项,此方法会返回元素的集合。使用assertArrayEquals()方法来对比期望和实际所选的选项是否正确。调用getAllSelectedOptions().size()方法来判断已选的下拉列表选项数量。如果想检查某一个选项是否被选择了,可以使用assertTrue(act_sel_options.contains("Red"))方法。
u 自动选择单选按钮
Selenium WebDriver的WebElement类支持单选按钮和按钮组。我们可以通过click()方法来选择单选按钮和取消选择,使用isSelect()方法来判断是否选中了单选按钮。
package com.example.tests;
import static org.junit.Assert.*;
import java.util.*;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
public class Selenium2 {
@Test
public void testRadioButton() {
WebDriver driver = new FirefoxDriver();
driver.get("D:\\demo\\RadioButton.html");
//使用value值来定位单选按钮
WebElement apple =
driver.findElement(By.cssSelector("input[value='Apple']"));
//检查是否已选择,如果没有则点击选择
if(!apple.isSelected()){
apple.click();
}
//验证apple选项已经选中
assertTrue(apple.isSelected());
//也可以得到所有的单选按钮
List<WebElement> fruit =
driver.findElements(By.name("fruit"));
//查询Orange选项是否存在,如果存在则选择
for(WebElement allFruit : fruit){
if(allFruit.getAttribute("value").equals("Orange")){
if(!allFruit.isSelected()){
allFruit.click();
assertTrue(allFruit.isSelected());
break;
}
}
}
}
}
u 自动选择多选项框
Selenium WebDriver的WebElement类也支持多选框。我们可以使用click()方法来选择和取消选择,使用isSelect()方法来判断是否选中。
package com.example.tests;
import static org.junit.Assert.*;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
public class Selenium2 {
@Test
public void testRadioButton() {
WebDriver driver = new FirefoxDriver();
driver.get("D:\\demo\\checkbox.html");
//使用value值来选择单选按钮
WebElement apple = driver.findElement
(By.cssSelector("input[value='Apple']"));
WebElement pear = driver.findElement
(By.cssSelector("input[value='Pear']"));
WebElement orange = driver.findElement
(By.cssSelector("input[value='Orange']"));
//检查是否已选择,如果没有则点击选择
if(!apple.isSelected()){
apple.click();
}
if(!pear.isSelected()){
pear.click();
}
if(!orange.isSelected()){
orange.click();
}
//验证选项已经选中
assertTrue(apple.isSelected());
assertTrue(pear.isSelected());
assertTrue(orange.isSelected());
//再次点击apple多选框,取消选择
if(apple.isSelected()){
apple.click();
}
assertFalse(apple.isSelected());
}
u 处理windows的进程
Selenium WebDriver java提供了windowsUtils类来和Windows操作系统交互。在测试开始时,我们需要关掉已经一些进程。
如下例子,关闭已打开的火狐浏览器:
@Before
public void setUp()
{
WindowsUtils.tryToKillByName("firefox.exe");
driver = new FirefoxDriver();
driver.get("http://www.google.com");
driver.manage().window().maximize();
}
我们可以使用tryToKillByName方法来关闭任何的windows的进程。如果这个进程不存在则会抛出一个异常,但是,测试还是会正常的执行下去。
u 通过WebDriver读取windows注册表中的值
WindowsUtils类提供了多种方法和windows操作系统的注册表进行交互,如果测试是运行在windows操作系统上的IE浏览器,则可能需要修改一些IE注册表里的设置。使用WindowsUtils类就可以很方便的解决。
我们需要导入org.openqa.selenium.os.WindowsUtils类然后使用readStringRegistryValue()方法来读取注册表里的键值。package com.example.tests;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.os.WindowsUtils;
public class Selenium2 {
@Test
public void testRegistry() {
WebDriver driver = new InternetExplorerDriver();
driver.get("D:\\demo\\checkbox.html");
String osname = WindowsUtils.readStringRegistryValue
("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\OS");
System.out.println(osname);
}
}
WindowsUtil也基于返回值的不同提供了多种方法来读取注册表的值,例子中返回的是String所以使用readStringRegistryValue(),还可以据不同的数据类型使用readIntegerRegistryValue(),readBooleanRegistryValue()根。
u 通过WebDriver修改windows注册表的值
package com.example.tests;
import static org.junit.Assert.*;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.os.WindowsUtils;
public class Selenium2 {
@Test
public void testRegistry() {
WebDriver driver = new InternetExplorerDriver();
driver.get("D:\\demo\\checkbox.html");
WindowsUtils.writeStringRegistryValue
("HKEY_CURRENT_USER\\SOFTWARE\\Selenium\\SeleniumVersion",
"2.24");
assertEquals("2.24",
WindowsUtils.readStringRegistryValue
("HKEY_CURRENT_USER\\SOFTWARE\\Selenium\\SeleniumVersion"));
}
}
writeStringRegistryValue()通过注册表的路径找到相应的位置,如果值存在则修改,如果不存在则新建一条新的,同时基于写入数据类型也提供了其他两种方法writeIntegerRegistryValue(),writeBooleanRegistryValue()。
u 使用隐式的等待同步测试
Selenium WebDriver提供了隐式等待来同步测试。当使用了隐式等待执行测试的时候,如果WebDriver没有在DOM中找到元素,将继续等待,超出设定时间后则抛出找不到元素的异常。
换句话说,当查找元素或元素并没有立即出现的时候,隐式等待将等待一段时间再查找DOM。默认的时间是0 。
一旦设置了隐式等待,则它存在在整个WebDriver对象实例的生命周期中,但是,隐式的等待会让一个正常响应的应用的测试变慢,它将会在寻找每个元素的时候都进行等待,这样就增加了整个测试过程的执行时间。
package com.example.tests;
import static org.junit.Assert.*;
import java.util.concurrent.TimeUnit;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.os.WindowsUtils;
public class Selenium2 {
@Test
public void testWithImplicitWait() throws InterruptedException {
WebDriver driver = new InternetExplorerDriver();
driver.get
("http://demo.tutorialzine.com/2009/09/" + "simple-ajax-website-jquery/demo.html");
//等待10秒
driver.manage().timeouts(). implicitlyWait(10, TimeUnit.SECONDS);
WebElement page4button = driver. findElement(By.linkText("Page 4"));
page4button.click();
WebElement message = driver.findElement(By.id("pageContent"));
//等待Ajax的内容出现
Thread.sleep(4000);
assertTrue(message.getText().contains("Nunc nibh tortor"));
}
}
Selenium WebDriver提供了Timeouts接口来设置隐式等待。Timeouts接口下又提供了implicitlyWait()方法,接收一个查询元素所需要等待癿时间参数。
Thread.sleep(4000)意思义等待4秒钟,如果没有返句加上pageContent本身就存在,所以它癿内容就是最初没有点击时候的文本,不是我们所期望的。。
u 使用显式的等待同步测试
Selenium WebDriver也提供了显式的等待,相对亍隐式来说更好的控制方法来同步测试。不像隐式等待,你可以在执行下一次操作时,自定义等待条件。
显式的等待叧需要执行在需要同步的地方而不影响脚本其他癿地方。
Selenium WebDriver提供了WebDriverWait和ExpectedCondition类来执行显式等待。
ExpectedCondition类提供了一系列预定义好的条件来等待。下面的表格中显示了一些我们经常在自动化测试中遇到的常用条件。
预定义条件 |
方法名 |
元素可见可点击 |
elementToBeClickable(By locator) |
元素被选中 |
elementToBeSelected(WebElement element) |
存在一个元素 |
presenceOfElementLocated(By locator) |
元素中出现指定癿文本 |
textToBePresentInElement(By locator, String text) |
元素癿值 |
textToBePresentInElementValue(By locator, String text) |
标题 |
titleContains(String title) |
package com.example.tests;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.support.ui.*;
public class Selenium2 {
@Test
public void testWithImplicitWait() throws InterruptedException {
WebDriver driver = new InternetExplorerDriver();
driver.get("http://demo.tutorialzine.com/2009/09/simple-ajax-website-jquery/demo.html");
WebElement page4button = driver.findElement(By.linkText("Page 4"));
page4button.click();
//设置等待时间10秒
WebDriverWait wait = new WebDriverWait(driver, 10);
//等待直到符合元素文本内容出现。
wait.until(ExpectedConditions.textToBePresentInElement
(By.id("pageContent"),
"Nunc nibh tortor, " +
"congue pulvinar rhoncus quis, " +
"porta sed odio. Quisque ornare, " +
"velit elementum porta consequat, " +
"nibh augue tincidunt magna, " +
"at ullamcorper ligula felis vitae felis."));
WebDriverWait每500毫秒调用一次ExpectedCondition直到正确的返回值。
可见返样的好处就是随时控制所需要等待的地方,更加精确的控制所需要癿条件
u 使用自定义的期望条件同步测试
package com.example.tests;
import static org.junit.Assert.*;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.support.ui.*;
public class Selenium2 {
@Test
public void testWithImplicitWait() throws InterruptedException {
WebDriver driver = new InternetExplorerDriver();
driver.get("http://www.w3school.com.cn/" +
"ajax/ajax_example.asp");
WebElement button = driver.findElement(By.tagName("button"));
//验证点击之前的文本
assertTrue(driver.findElement
(By.cssSelector("#myDiv h3"))
.getText().contains("Let AJAX"));
button.click();
//设置等待时间为5秒
WebDriverWait wait = new WebDriverWait(driver, 5);
//创建一个新的ExpecctedCondition接口,就必须实现apply方法
WebElement message = wait.until
(new ExpectedCondition<WebElement>(){
public WebElement apply(WebDriver d){
return d.findElement(By.cssSelector("#myDiv p"));
}
});
//验证点击后的文本
assertTrue(message.getText().contains("AJAX is"));
driver.close();
}
}
这里通过ExpectedCondition和WebDriverWait类我们自定义了一个期望条件。在这个例子中我们需要在5秒内定位到指定的元素,其实通过自身的presenceOfElementLocated(By locator)方法也能实现.
等待元素的属性值改变:
(new WebDriverWait(driver, 10)).until(
new ExpectedCondition<Boolean>()
{
public Boolean apply(WebDriver d)
{
return d.findElement(By.id("userName")).getAttribute("readonly").contains("true");
}});
如下例子也是等待某属性改变:
driver.get("http://www.jquery.com");
WebElement button =
driver.findElement(By.linkText("RUN CODE"));
button.click();
//设置等待时间为5秒
WebDriverWait wait = new WebDriverWait(driver, 5);
//这里apply的返回值为Boolean
Boolean classname = wait.until
(new ExpectedCondition<Boolean>(){
public Boolean apply(WebDriver d){
return d.findElement(
By.cssSelector(".jq-codeDemo p"))
.getAttribute("class")
.contains("ohmy");
}
});
driver.close();
等待元素变为可见:
package com.example.tests;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.support.ui.*;
public class Selenium2 {
@Test
public void testWithImplicitWait() throws InterruptedException {
WebDriver driver = new InternetExplorerDriver();
driver.get("http://www.jquery.com");
WebElement button =
driver.findElement(By.linkText("RUN CODE"));
button.click();
//设置等待时间为5秒
WebDriverWait wait = new WebDriverWait(driver, 5);
//创建一个新的ExpecctedCondition接口,就必须实现apply方法
Boolean classname = wait.until
(new ExpectedCondition<Boolean>(){
public Boolean apply(WebDriver d){
return d.findElement(
By.cssSelector(".jq-codeDemo p"))
.isDisplayed();
}
});
driver.close();
}
}
等待DOM的事件
Web应用可能使用了AJAX的框架如jQuery来操作网页内容。例如,jQuery经常异步的会去从服务器加载一个很大的JSON文件。当jQuery正在处理文件的时候,测试可以使用active属性。自定义的等待可以通过执行一段JavaScript代码并检查返回值来完成。
(new WebDriverWait(driver, 10)).until(
new ExpectedCondition<Boolean>()
{
public Boolean apply(WebDriver d)
{
JavascriptExecutor js = (JavascriptExecutor) d;
return (Boolean)js.executeScript("return jQuery.active == 0");
}});
u 检查元素是否存在
package com.example.tests;
import static org.junit.Assert.*;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.ie.InternetExplorerDriver;
public class Selenium2 {
WebDriver driver = new InternetExplorerDriver();
@Test
public void testisElementPresent(){
driver.get("http://www.baidu.com");
driver.findElement(By.id("kw")).sendKeys("selenium");
//判断搜索按钮是否存在
if(isElementPresent(By.id("su1"))){
//点击按钮
driver.findElement(By.id("su")).click();
}else{
fail("元素不存在");
}
}
private boolean isElementPresent(By by)
{
try
{
driver.findElement(by);
return true;
}
catch (Exception e)
{
e.printStackTrace();
return false;
}
}
}
u 检查元素的状态
isSelected() |
检查元素是否被选中(单选,多选,下拉框) |
disDisplayed() |
检查元素是否可见 |
package com.example.tests;
import static org.junit.Assert.*;
import java.util.*;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
public class Selenium2 {
@Test
public void testRadioButton() {
WebDriver driver = new FirefoxDriver();
driver.get("D:\\demo\\RadioButton.html");
//使用value值来定位单选按钮
WebElement apple =
driver.findElement(By.cssSelector("input[value='Apple']"));
//检查是否已选择,如果没有则点击选择
if(!apple.isSelected()){
apple.click();
}
//验证apple选项已经选中
assertTrue(apple.isSelected());
//也可以得到所有的单选按钮
List<WebElement> fruit =
driver.findElements(By.name("fruit"));
//查询Orange选项是否存在,如果存在则选择
for(WebElement allFruit : fruit){
if(allFruit.getAttribute("value").equals("Orange")){
if(!allFruit.isSelected()){
allFruit.click();
assertTrue(allFruit.isSelected());
break;
}
u 通过名称识别和处理一个弹出窗口
package com.example.tests;
import static org.junit.Assert.*;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
public class Selenium2 {
WebDriver driver = new FirefoxDriver();
@Test
public void testWindowPopup(){
driver.get("D:\\demo\\window.html");
//保存父窗口
String parentWindowId = driver.getWindowHandle();
//点击按钮弹出窗口
WebElement helpButton = driver.findElement(By.id("helpbutton1"));
helpButton.click();
try
{
//转到HelpWindow
driver.switchTo().window("HelpWindow");
}
catch (NoSuchWindowException e)
{
e.printStackTrace();
}
//验证新窗口里的文本
assertEquals("PopUpWindow", driver.findElement(By.tagName("p")).getText());
//关闭子窗口
driver.close();
//回到父窗口
driver.switchTo().window(parentWindowId);
//验证父窗口的title
assertTrue(driver.getTitle().equals("help"));
driver.close();
}
}
u 通过标题识别处理一个弹出窗口
很多时候开发人员并没有给弹出的窗口分配一个name属性。这种情况下,我们可以使用handle属性。但是,handle的值是不停的变化的,这让识别窗口变的有些困难,尤其是多个窗口的时候。我们使用handle和title来识别一个弹出窗口。
package com.example.tests;
import static org.junit.Assert.*;
import java.util.Set;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
public class Selenium2 {
WebDriver driver = new FirefoxDriver();
@Test
public void testWindowPopup(){
driver.get("D:\\demo\\window.html");
//保存父窗口
String parentWindowId = driver.getWindowHandle();
//点击按钮弹出窗口
WebElement helpButton =
driver.findElement(By.id("helpbutton2"));
helpButton.click();
//得到所有的窗口
Set<String> allWindowsId = driver.getWindowHandles();
//通过title得到新的窗口
for (String windowId : allWindowsId)
{
if (driver.switchTo().window(windowId)
.getTitle().equals("PopUpWindow"))
{
driver.switchTo().window(windowId);
break;
}
}
//验证新窗口的文本
assertEquals("PopUpWindow", driver.findElement(By.tagName("p")).getText());
//关闭弹出窗口
driver.close();
//关闭父窗口
driver.switchTo().window(parentWindowId);
driver.close();
}
}
u 通过网页内容识别处理一个弹出窗口
package com.example.tests;
import static org.junit.Assert.*;
import java.util.Set;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
public class Selenium2 {
WebDriver driver = new FirefoxDriver();
@Test
public void testWindowPopup(){
driver.get("D:\\demo\\window.html");
//保存父窗口
String parentWindowId = driver.getWindowHandle();
//点击按钮弹出窗口
WebElement helpButton =
driver.findElement(By.id("helpbutton2"));
helpButton.click();
//得到所有的窗口
Set<String> allWindowsId = driver.getWindowHandles();
//通过查找页面内容得到新的窗口
for (String windowId : allWindowsId) {
driver.switchTo().window(windowId);
if (driver.getPageSource().contains("Welcome")){
driver.switchTo().window(windowId);
break;
}
}
//验证新窗口的文本
assertEquals("PopUpWindow",
driver.findElement(By.tagName("p")).getText());
//关闭弹出窗口
driver.close();
//关闭父窗口
driver.switchTo().window(parentWindowId);
driver.close();
}
}
通过driver.getPageSource()方法得到页面的html内容,再调用contains()方法来判断是否含有指定的内容。这样做的缺点就是如果页面内容很多,获得的速度会慢,而且contains()里面查找内容必须是唯一,否则可能识别的窗口不是你所期望的。
u 处理一个简单的JavaScript警告窗
//获取alert窗口
Alert alertBox = driver.switchTo().alert();
alertBox.accept();
//验证alert窗口里的文字
assertEquals("Hello World",alertBox.getText());
driver.close();
driver.switchTo().alert()将窗口移劢到警告框上。
alert.getText()得到警告框上癿信息。
如果找不到警告框则会抛出NoAlertPresentException异常。
u 处理一个确认框
package com.example.tests;
import static org.junit.Assert.*;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
public class Selenium2 {
WebDriver driver = new FirefoxDriver();
@Test
public void testWindowPopup(){
driver.get("D:\\demo\\alert.html");
//点击确定按钮
getConfirmBox().accept();
//验证点击后的文字
assertEquals("你点击了确定按钮!",
driver.findElement(By.cssSelector("span")).getText());
//点击取消按钮
getConfirmBox().dismiss();
assertEquals("你点击了取消按钮!",
driver.findElement(By.cssSelector("span")).getText());
driver.close();
}
//封装得到窗口的方法
private Alert getConfirmBox(){
//点击按钮弹出确认提示框
WebElement button = driver.findElement(By.id("confirm"));
button.click();
//获取确认提示框
Alert confirmBox = driver.switchTo().alert();
assertEquals("我是确认提示框!",confirmBox.getText());
return confirmBox;
}
}
点击确认是使用accept()方法,点击取消使用dismiss()方法。
u 处理一个提示框
package com.example.tests;
import static org.junit.Assert.*;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
public class Selenium2 {
WebDriver driver = new FirefoxDriver();
@Test
public void testPromptAlert(){
driver.get("D:\\demo\\alert.html");
WebElement button = driver.findElement(By.id("prompt"));
button.click();
//获得提示框
Alert promptAlert = driver.switchTo().alert();
assertEquals("点都点了,就输入点什么吧",promptAlert.getText());
//输入一些数据
promptAlert.sendKeys("洛阳亲友如相问,就说我在写代码");
//点击确定按钮
promptAlert.accept();
//验证输入的数据
String actualTest = driver.findElement(By.tagName("span"))
.getText();
assertEquals("洛阳亲友如相问,就说我在写代码", actualTest);
driver.close();
}
}
u 识别处理框架
//通过id定位到左边的框架
driver.switchTo().frame("left");
String leftMsg = driver.findElement(By.tagName("p")).getText();
assertEquals("i am left page",leftMsg);
//回到初始的焦点
driver.switchTo().defaultContent();
//通过name定位到右边的框架
driver.switchTo().frame("right");
String rightMsg = driver.findElement(By.tagName("p")).getText();
assertEquals("i am right page",rightMsg);
driver.close();
通过index获取frame框架:
//通过index来定位框架
driver.switchTo().frame(1);
//验证中间框架的文本
String middleMsg = driver.findElement(By.tagName("p"))
.getText();
assertEquals("i am middle page",middleMsg);
u 通过页面内容识别和处理框架
//得到所有的frame元素
List<WebElement> frames = driver.findElements(By.tagName("frame"));
//通过页面的内容得到中间的框架
for (int i = 0; i < frames.size(); i++)
{
driver.switchTo().frame(i);
if (driver.getPageSource().contains("middle"))
{
break;
//没有匹配的时候需要回到最初的页面
}
else
{
driver.switchTo().defaultContent();
}
String actualText = driver.findElement(By.tagName("p")).getText();
assertEquals("i am middle page", actualText);
u 处理IFRAM
//首先获得父窗口
driver.switchTo().frame("left");
//取得iframe元素
WebElement weiboIframe = driver.findElement(By.tagName("iframe"));
//获得iframe窗口
driver.switchTo().frame(weiboIframe);
//验证iframe里面的页面内容
String actualText = driver.findElement(By.linkText("新浪微博")).getText();
assertEquals("新浪微博", actualText);
driver.switchTo().defaultContent();
定位frame中的元素
场景
处理frame需要用到2个方法,分别是switchTo().frame(element|index|id)和switchTo.defaultContent()
switchTo().frame()方法的参数值得一提。其支持
· WebElement, 可以传入一个已经定位的frame元素。如 switchTo().frame(dr.findElement(By.id("myFrame")))
· int index, 可以传入页面上frame的索引,如0表示第1个frame
· String id, 可以传入frame的id
switchTo().frame()方法把当前定位的主体切换了frame里。怎么理解这句话呢?我们可以从frame的实质去理解。frame中实际上是嵌入了另一个页面,而webdriver每次只能在一个页面识别,因此才需要用switch_to.frame方法去获取frame中嵌入的页面,对那个页面里的元素进行定位。
switchTo.defaultContent方法的话则是从frame中嵌入的页面里跳出,跳回到最外面的原始页面中。
如果页面上只有1个frame的话那么这一切都是很好理解的,但如果页面上有多个frame,情况有稍微有点复杂了。
代码
下面的代码中frame.html里有个id为f1的frame,而f1中又嵌入了id为f2的frame,该frame加载了百度的首页。
frame.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>frame</title>
<script type="text/javascript" async="" ></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" />
<script type="text/javascript">
$(document).ready(function(){
});
</script>
</head>
<body>
<div>
<div class="span10 well">
<h3>frame</h3>
<iframe id="f1" width="800", height="600"></iframe>
</div>
</div>
</body>
<script ></script>
</html>
inner.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>inner</title>
</head>
<body>
<div>
<div class="span6 well">
<h3>inner</h3>
<iframe id="f2" width="700" height="500"></iframe>
<a href="javascript:alert('watir-webdriver better than selenium webdriver;')">click</a>
</div>
</div>
</body>
</html>
frame.java
public class Frame {
public static void main(String[] args) throws InterruptedException {
WebDriver dr = new ChromeDriver();
File file = new File("src/frame.html");
String filePath = "file:///" + file.getAbsolutePath();
System.out.printf("now accesss %s \n", filePath);
dr.get(filePath);
Thread.sleep(1000);
// 先到f1再到f2
dr.switchTo().frame("f1");
dr.switchTo().frame("f2");
// 往f2中的百度关键字文本框中输入内容
dr.findElement(By.id("kw")).sendKeys("watir-webdriver");
Thread.sleep(1000);
// 直接跳出所有frame
dr.switchTo().defaultContent();
// 再到f1
dr.switchTo().frame("f1");
dr.findElement(By.linkText("click")).click();
Thread.sleep(1000);
System.out.println("browser will be close");
dr.quit();
}
}
讨论
假设页面上有A、B两个frame,其中B在A内,那么定位B中的内容则需要先到A,然后再到B。如果是定位A中的内容,那么直接switch_to.frame('A')就可以了;
页面中使用frame会影响页面渲染速度,如果你遇到页面中有多个frame的情况,你完全可以提出1个页面前端性能的缺陷;
如果实在搞不定页面上的frame,送你一句歌词:也许放弃才能靠近你。那么及时放弃跟此frame相关的用例才是明智之举;
action
场景
由于webdriver是要模拟真实的用户操作,因此webdriver的Action类中提供了很多与操作有关的方法。
下面列举一下Action类的一些主要方法
· keyDown。模拟按键按下
· keyUp。模拟按键弹起
· click
· sendKeys
· doubleClick。鼠标左键双击
· clickAndHold。鼠标左键点击住不放
· release。鼠标左键弹起,可以与click_and_hold配合使用
· moveToElement。把鼠标移动到元素的中心点
· contextClick。鼠标右键点击
· dragAndDrop。拖拽
代码
Actions action = new Actions(driver)
action.keyDown(Keys.SHIFT).
click(element).
click(second_element).
keyUp(Keys.SHIFT).
dragAndDrop(element, third_element).
build().
perform()
讨论
具体使用方法可以参考api文档。action的api文档算是比较全面了。
上传文件
场景
上传文件的方法是找到上传文件的对象,通常是的对象。然后直接往这个对象sendKeys,传入需要上传文件的正确路径。绝对路径和相对路径都可以,但是上传的文件必须存在,否则会报错。
代码
upload_file.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>upload_file</title>
<script type="text/javascript" async="" ></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" />
<script type="text/javascript">
</script>
</head>
<body>
<div>
<div class="span6 well">
<h3>upload_file</h3>
<input type="file" name="file" />
</div>
</div>
</body>
<script ></script>
</html>
upload_file.java
import java.io.File;
import java.util.List;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
public class Upload {
public static void main(String[] args) throws InterruptedException {
WebDriver dr = new ChromeDriver();
File file = new File("src/upload_file.html");
String filePath = "file:///" + file.getAbsolutePath();
System.out.printf("now accesss %s \n", filePath);
dr.get(filePath);
Thread.sleep(1000);
dr.findElement(By.cssSelector("input[type=file]")).sendKeys("src/navs.html");
Thread.sleep(1000);
System.out.println("browser will be close");
dr.quit();
}
}
执行js
场景
如果你熟悉js的话,那么使用webdriver执行js就是一件很高效的事情了。在webdriver脚本中直接执行js的好处很多,这里就不一一枚举了。
webdriver提供了JavascriptExecutor(dr).executeScript()接口来帮助我们完成这一工作。在实际的测试脚本中,以下两种场景是经常遇到的
· 在页面直接执行一段js
· 在某个已经定位的元素的上执行js
代码
下面的代码演示了如何在页面以及在已经定位的元素上执行js
js.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>js</title>
<script type="text/javascript" async="" ></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" />
<script type="text/javascript">
$(document).ready(function(){
$('#tooltip').tooltip({"placement": "right"});
});
</script>
</head>
<body>
<h3>js</h3>
<div>
<div class="span6 well">
<a id="tooltip" href="#" data-toggle="tooltip" title="watir-webdriver better than selenium-webdriver">hover to see tooltip</a>
<a>Button</a>
</div>
</div>
</body>
<script ></script>
</html>
js.java
public class Js {
public static void main(String[] args) throws InterruptedException {
WebDriver dr = new ChromeDriver();
File file = new File("src/js.html");
String filePath = "file:///" + file.getAbsolutePath();
System.out.printf("now accesss %s \n", filePath);
dr.get(filePath);
Thread.sleep(1000);
// 在页面上直接执行js
((JavascriptExecutor)dr).executeScript("$('#tooltip').fadeOut();");
Thread.sleep(1000);
// 在已经定位的元素上执行js
WebElement button = dr.findElement(By.className("btn"));
((JavascriptExecutor)dr).executeScript("$(arguments[0]).fadeOut();", button);
Thread.sleep(1000);
System.out.println("browser will be close");
dr.quit();
}
}
前进和后退
场景
说实话,这两个功能一般不太常用。所能想到的场景大概也就是在几个页面间来回跳转,省去每次都get url。
代码
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class ForwardAndBack {
public static void main(String[] args) throws InterruptedException {
WebDriver dr = new ChromeDriver();
Thread.sleep(2000);
String firstUrl = "http://www.baidu.com";
System.out.printf("now accesss %s \n", firstUrl);
dr.get(firstUrl);
Thread.sleep(1000);
String secondUrl = "http://www.soso.com";
System.out.printf("now accesss %s \n", secondUrl);
dr.get(secondUrl);
Thread.sleep(1000);
System.out.printf("now back to %s \n", firstUrl);
dr.navigate().back();
Thread.sleep(1000);
System.out.printf("forward to %s \n", secondUrl);
dr.navigate().forward();
Thread.sleep(1000);
System.out.println("browser will be close");
dr.quit();
}
}
定位一组对象
场景
从上一节的例子中可以看出,webdriver可以很方便的使用findElement方法来定位某个特定的对象,不过有时候我们却需要定位一组对象,这时候就需要使用findElements方法。
定位一组对象一般用于以下场景:
· 批量操作对象,比如将页面上所有的checkbox都勾上
· 先获取一组对象,再在这组对象中过滤出需要具体定位的一些对象。比如定位出页面上所有的checkbox,然后选择最后一个
代码
checkbox.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>Checkbox</title>
<script type="text/javascript" async="" ></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" />
<script ></script>
</head>
<body>
<h3>checkbox</h3>
<div>
<form>
<div>
<label for="c1">checkbox1</label>
<div>
<input type="checkbox" id="c1" />
</div>
</div>
<div>
<label for="c2">checkbox2</label>
<div>
<input type="checkbox" id="c2" />
</div>
</div>
<div>
<label for="c3">checkbox3</label>
<div>
<input type="checkbox" id="c3" />
</div>
</div>
<div>
<label for="r">radio</label>
<div>
<input type="radio" id="r" />
</div>
</div>
</form>
</div>
</body>
</html>
find_element.java
public class SimpleLocate {
public static void main(String[] args) throws InterruptedException {
WebDriver dr = new ChromeDriver();
File file = new File("src/checkbox.html");
String filePath = "file:///" + file.getAbsolutePath();
System.out.printf("now accesss %s \n", filePath);
dr.get(filePath);
Thread.sleep(1000);
// 选择所有的checkbox并全部勾上
List<WebElement> checkboxes = dr.findElements(By.cssSelector("input[type=checkbox]"));
for(WebElement checkbox : checkboxes) {
checkbox.click();
}
dr.navigate().refresh();
// 打印当前页面上有多少个checkbox
System.out.printf("%d\n", checkboxes.size());
// 选择页面上所有的input,然后从中过滤出所有的checkbox并勾选之
List<WebElement> inputs = dr.findElements(By.tagName("input"));
for(WebElement input : inputs){
if(input.getAttribute("type").equals("checkbox")){
input.click();
}
}
// 把页面上最后1个checkbox的勾给去掉
List<WebElement> allCheckboxes = dr.findElements(By.cssSelector("input[type=checkbox]"));
allCheckboxes.get(allCheckboxes.size() - 1).click();
Thread.sleep(1000);
System.out.println("browser will be close");
dr.quit();
}
}
讨论
checkbox.html必须与find_elments.rb在同一级目录下
操作测试对象
场景
定位到具体的对象后,我们就可以对这个对象进行具体的操作,比如先前已经看到过的点击操作(click)。一般来说,webdriver中比较常用的操作对象的方法有下面几个
· click 点击对象
· sendKeys 在对象上模拟按键输入
· clear 清除对象的内容,如果可以的话
代码
下面的代码演示了如何点击元素,如何往文本框中输入文字以及如何清空文字。
operate_element.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>Level Locate</title>
<script type="text/javascript" async="" ></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" />
</head>
<body>
<h3>Level locate</h3>
<div>
<div>
<div>
<a data-toggle="dropdown" href="#">Link1</a>
<ul role="menu" aria-labelledby="dLabel" id="dropdown1" >
<li><a tabindex="-1" href="#">Action</a></li>
<li><a tabindex="-1" href="#">Another action</a></li>
<li><a tabindex="-1" href="#">Something else here</a></li>
<li></li>
<li><a tabindex="-1" href="#">Separated link</a></li>
</ul>
</div>
</div>
</div>
<div>
<div>
<div>
<a data-toggle="dropdown" href="#">Link2</a>
<ul role="menu" aria-labelledby="dLabel" >
<li><a tabindex="-1" href="#">Action</a></li>
<li><a tabindex="-1" href="#">Another action</a></li>
<li><a tabindex="-1" href="#">Something else here</a></li>
<li></li>
<li><a tabindex="-1" href="#">Separated link</a></li>
</ul>
</div>
</div>
</div>
</body>
<script ></script>
</html>
operate_element.java
import java.io.File;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
public class OperateElement {
public static void main(String[] args) throws InterruptedException {
WebDriver dr = new ChromeDriver();
File file = new File("src/operate_element.html");
String filePath = "file:///" + file.getAbsolutePath();
System.out.printf("now accesss %s \n", filePath);
dr.get(filePath);
Thread.sleep(1000);
// click
dr.findElement(By.linkText("Link1")).click();
Thread.sleep(1000);
dr.findElement(By.linkText("Link1")).click();
// send_keys
WebElement element = dr.findElement(By.name("q"));
element.sendKeys("something");
Thread.sleep(1000);
// clear
element.clear();
Thread.sleep(1000);
System.out.println("browser will be close");
dr.quit();
}
}
send keys模拟按键输入
场景
sendKeys方法可以模拟一些组合键操作,比如ctrl+a等。另外有时候我们需要在测试时使用tab键将焦点转移到下一个元素,这时候也需要sendKeys。在某些更复杂的情况下,还会出现使用sendKeys来模拟上下键来操作下拉列表的情况。
代码
下面的代码演示了如何将A多行文本框中的内容清空并复制到B文本框中。
send_keys.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>send keys</title>
<script type="text/javascript" async="" ></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" />
</head>
<body>
<h3>send keys</h3>
<div>
<div>
<div>
<label>A</label>
<textarea rows="10", cols="10" id="A">I think watir-webdriver is better than selenium-webdriver</textarea>
</div>
</div>
<div>
<div>
<label>B</label>
<textarea rows="10", cols="10" id="B"></textarea>
</div>
</div>
</div>
</body>
<script ></script>
</html>
send_keys.java
import java.io.File;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class SendKeys {
public static void main(String[] args) throws InterruptedException {
WebDriver dr = new ChromeDriver();
File file = new File("src/send_keys.html");
String filePath = "file:///" + file.getAbsolutePath();
System.out.printf("now accesss %s \n", filePath);
dr.get(filePath);
Thread.sleep(1000);
// copy content of A
dr.findElement(By.id("A")).sendKeys(Keys.chord(Keys.CONTROL + "a"));
Thread.sleep(1000);
dr.findElement(By.id("A")).sendKeys(Keys.chord(Keys.CONTROL + "x"));
// paste to B
dr.findElement(By.id("B")).sendKeys(Keys.chord(Keys.CONTROL + "v"));
// SendKeys to A
dr.findElement(By.id("A")).sendKeys(Keys.chord("watir webdriver is better than selenium webdriver"));
Thread.sleep(1000);
System.out.println("browser will be close");
dr.quit();
}
}
处理button group
场景
button group就是按钮组,将一组按钮排列在一起。处理这种对象的思路一般是先找到button group的包裹(wrapper)div,然后通过层级定位,用index或属性去定位更具体的按钮。
代码
下面的代码演示了如何找到second这个按钮。其处理方法是先找到button group的父div,class为btn-group的div,然后再找到下面所有的div(也就是button),返回text是second的div。
button_group.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>button group</title>
<script type="text/javascript" async="" ></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" />
<script type="text/javascript">
$(document).ready(function(){
$('.btn').click(function(){
alert($(this).text());
});
});
</script>
</head>
<body>
<h3>button group</h3>
<div>
<div>
<div>
<div>
<div>
<div>first</div>
<div>second</div>
<div>third</div>
</div>
</div>
</div>
</div>
</div>
</body>
<script ></script>
</html>
button_group.java
import java.io.File;
import java.util.List;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
public class ButtonGroup {
public static void main(String[] args) throws InterruptedException {
WebDriver dr = new ChromeDriver();
File file = new File("src/button_group.html");
String filePath = "file:///" + file.getAbsolutePath();
System.out.printf("now accesss %s \n", filePath);
dr.get(filePath);
Thread.sleep(1000);
// 定位text是second的按钮
List<WebElement> btns = dr.findElement(By.className("btn-group")).findElements(By.className("btn"));
for(WebElement btn : btns){
if(btn.getText().equals("second")){
btn.click();
break;
}
}
Thread.sleep(1000);
System.out.println("browser will be close");
dr.quit();
}
}
讨论
自己查资料搞清楚detect方法的作用。
处理button dropdown
场景
button dropdown就是把按钮和下拉菜单弄到了一起。处理这种对象的思路一般是先点击这个按钮,等待下拉菜单显示出来,然后使用层级定位方法来获取下拉菜单中的具体项。
代码
下面的代码演示了如何找到watir-webdriver这个菜单项。其处理方法是先点击info按钮,然后等到下拉菜单出现后定位下拉菜单的ul元素,再定位ul元素中link text为watir-webdriver的link,并点击之。
button_dropdown.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>button group</title>
<script type="text/javascript" async="" ></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" />
<script type="text/javascript">
$(document).ready(function(){
$('.btn').click(function(){
alert($(this).text());
});
});
</script>
</head>
<body>
<h3>button group</h3>
<div>
<div>
<div>
<div>
<div>
<div>first</div>
<div>second</div>
<div>third</div>
</div>
</div>
</div>
</div>
</div>
</body>
<script ></script>
</html>
button_dropdown.java
import java.io.File;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
public class ButtonDropdown {
public static void main(String[] args) throws InterruptedException {
WebDriver dr = new ChromeDriver();
File file = new File("src/button_dropdown.html");
String filePath = "file:///" + file.getAbsolutePath();
System.out.printf("now accesss %s \n", filePath);
dr.get(filePath);
Thread.sleep(1000);
// 定位text是watir-webdriver的下拉菜单
// 首先显示下拉菜单
dr.findElement(By.linkText("Info")).click();
(new WebDriverWait(dr, 10)).until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver d){
return d.findElement(By.className("dropdown-menu")).isDisplayed();
}
});
// 通过ul再层级定位
dr.findElement(By.className("dropdown-menu")).findElement(By.linkText("watir-webdriver")).click();
Thread.sleep(1000);
System.out.println("browser will be close");
dr.quit();
}
}
处理navs
场景
navs可以看作是简单的类似于tab的导航栏。一般来说导航栏都是ul+li。先定位ul再去层级定位li中的link基本就能解决问题。
代码
navs.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>Navs</title>
<script type="text/javascript" async="" ></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" />
<script type="text/javascript">
$(document).ready(
function(){
$('.nav').find('li').click(function() {
$(this).parent().find('li').removeClass('active');
$(this).addClass('active');
});
}
);
</script>
</head>
<body>
<h3>Navs</h3>
<div>
<div>
<ul class="nav nav-pills">
<li>
<a href="#">Home</a>
</li>
<li><a href="#">Content</a></li>
<li><a href="#">About</a></li>
</ul>
</div>
</div>
</body>
<script ></script>
</html>
navs.java
import java.io.File;
import java.util.List;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
public class Navs {
public static void main(String[] args) throws InterruptedException {
WebDriver dr = new ChromeDriver();
File file = new File("src/navs.html");
String filePath = "file:///" + file.getAbsolutePath();
System.out.printf("now accesss %s \n", filePath);
dr.get(filePath);
Thread.sleep(1000);
// 方法1:层级定位,先定位ul再定位li
dr.findElement(By.className("nav")).findElement(By.linkText("About")).click();
Thread.sleep(1000);
// 方法2: 直接定位link
dr.findElement(By.linkText("Home")).click();
Thread.sleep(1000);
System.out.println("browser will be close");
dr.quit();
}
}
处理面包屑
场景
在实际的测试脚本中,有可能需要处理面包屑。处理面包屑主要是获取其层级关系,以及获得当前的层级。一般来说当前层级都不会是链接,而父层级则基本是以链接,所以处理面包屑的思路就很明显了。找到面包屑所在的div或ul,然后再通过该div或ul找到下面的所有链接,这些链接就是父层级。最后不是链接的部分就应该是当前层级了。
代码
breadcrumb.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>breadcrumb</title>
<script type="text/javascript" async="" ></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" />
<script type="text/javascript">
$(document).ready(
function(){
}
);
</script>
</head>
<body>
<h3>breadcrumb</h3>
<div>
<div>
<ul>
<li><a href="#">Home</a> <span>/</span></li>
<li><a href="#">Library</a> <span>/</span></li>
<li>Data</li>
</ul>
</div>
</div>
</body>
<script ></script>
</html>
breadcrumb.java
import java.io.File;
import java.util.List;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
public class Breadcrumb {
public static void main(String[] args) throws InterruptedException {
WebDriver dr = new ChromeDriver();
File file = new File("src/breadcrumb.html");
String filePath = "file:///" + file.getAbsolutePath();
System.out.printf("now accesss %s \n", filePath);
dr.get(filePath);
Thread.sleep(1000);
// 获得其父层级
List<WebElement> ancestors = dr.findElement(By.className("breadcrumb")).findElements(By.tagName("a"));
for(WebElement link : ancestors){
System.out.println(link.getText());
}
// 获取当前层级
// 由于页面上可能有很多class为active的元素
// 所以使用层级定位最为保险
WebElement current = dr.findElement(By.className("breadcrumb")).findElement(By.className("active"));
System.out.println(current.getText());
Thread.sleep(1000);
System.out.println("browser will be close");
dr.quit();
}
}
处理对话框
场景
页面上弹出的对话框是自动化测试经常会遇到的一个问题。很多情况下这个弹出的对话框是一个iframe,处理起来有点麻烦,需要进行switch_to操作。但现在很多前端框架的对话框都是div形式的,这就让我们的处理变得十分简单了。
处理对话框一般会做下面的一些事情
· 打开对话框
· 关闭对话框
· 操作对话框中的元素
代码
下面的代码演示了如何打开、关闭以及点击对话框中的链接
modal.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>modal</title>
<script type="text/javascript" async="" ></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" />
<script type="text/javascript">
$(document).ready(function(){
$('#click').click(function(){
$(this).parent().find('p').text('try watir-webdriver right now!');
});
});
</script>
</head>
<body>
<h3>modal</h3>
<div>
<div>
<!-- Button to trigger modal -->
<a href="#myModal" role="button" class="btn btn-primary" data-toggle="modal" id="show_modal">Click</a>
<!-- Modal -->
<div id="myModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div>
<button type="button" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="myModalLabel">Modal header</h3>
</div>
<div>
<p>watir-webdriver is better than slenium-webdriver</p>
<a href="#" id="click">click me</a>
</div>
<div>
<button data-dismiss="modal" aria-hidden="true">Close</button>
<button class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
</body>
<script ></script>
</html>
modal.java
public class Modal {
public static void main(String[] args) throws InterruptedException {
WebDriver dr = new ChromeDriver();
File file = new File("src/modal.html");
String filePath = "file:///" + file.getAbsolutePath();
System.out.printf("now accesss %s \n", filePath);
dr.get(filePath);
Thread.sleep(1000);
// 打开对话框
dr.findElement(By.id("show_modal")).click();
(new WebDriverWait(dr, 10)).until(
new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver d) {
return d.findElement(By.id("myModal")).isDisplayed();
}
}
);
// 点击对话框中的链接
// 由于对话框中的元素被蒙板所遮挡,直接点击会报 Element is not clickable的错误
// 所以使用js来模拟click
// 在watir-webdriver中只需要fire_event(:click)就可以了
WebElement link = dr.findElement(By.id("myModal")).findElement(By.id("click"));
((JavascriptExecutor)dr).executeScript("$(arguments[0]).click()", link);
Thread.sleep(1000);
System.out.println("browser will be close");
dr.quit();
}
}
获取测试对象的属性及内容
场景
获取测试对象的内容是前端自动化测试里一定会使用到的技术。比如我们要判断页面上是否显示了一个提示,那么我们就需要找到这个提示对象,然后获取其中的文字,再跟我们的预期进行比较。在webdriver中使用element.getAttribute()方法可以获取dom元素(测试对象)的属性。
获取测试对象的属性能够帮我们更好的进行对象的定位。比如页面上有很多class都是'btn'的div,而我们需要定位其中1个有具有title属性的div。由于selenium-webdriver是不支持直接使用title来定位对象的,所以我们只能先把所有class是btn的div都找到,然后遍历这些div,获取这些div的title属性,一旦发现具体title属性的div,那么返回这个div既可。在webdriver中,使用element.getText()方法可以返回dom节点的内容(text)。
代码
下面的代码演示了如何获取测试对象的title属性和该对象的文字内容
attribute.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>attribute</title>
<script type="text/javascript" async="" ></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" />
<script type="text/javascript">
$(document).ready(function(){
$('#tooltip').tooltip({"placement": "right"});
});
</script>
</head>
<body>
<h3>attribute</h3>
<div>
<div>
<a id="tooltip" href="#" data-toggle="tooltip" title="watir-webdriver better than selenium-webdriver">hover to see tooltip</a>
</div>
</div>
</body>
<script ></script>
</html>
attribute.java
public class Attribute {
public static void main(String[] args) throws InterruptedException {
WebDriver dr = new ChromeDriver();
File file = new File("src/attribute.html");
String filePath = "file:///" + file.getAbsolutePath();
System.out.printf("now accesss %s \n", filePath);
dr.get(filePath);
Thread.sleep(1000);
WebElement link = dr.findElement(By.id("tooltip"));
// 获得tooltip的内容
System.out.println(link.getAttribute("data-original-title"));
// 获取该链接的text
System.out.println(link.getText());
Thread.sleep(1000);
System.out.println("browser will be close");
dr.quit();
}
}
获取测试对象的css属性
场景
当你的测试用例纠结细枝末节的时候,你就需要通过判断元素的css属性来验证你的操作是否达到了预期的效果。比如你可以通过判断页面上的标题字号以字体来验证页面的显示是否符合预期。当然,这个是强烈不推荐的。因为页面上最不稳定的就是css了,css变动频繁,而且通过属性也不能直观的判断页面的显示效果,还不如让人为的去看一眼,大问题一望即知。
代码
下面的代码演示了如何获取测试对象的css属性。
css.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>attribute</title>
<script type="text/javascript" async="" ></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" />
<script type="text/javascript">
$(document).ready(function(){
$('#tooltip').tooltip({"placement": "right"});
});
</script>
</head>
<body>
<h3>attribute</h3>
<div>
<div>
<a id="tooltip" href="#" data-toggle="tooltip" title="watir-webdriver better than selenium-webdriver">hover to see tooltip</a>
</div>
</div>
</body>
<script ></script>
</html>
css.java
public class Css {
public static void main(String[] args) throws InterruptedException {
WebDriver dr = new ChromeDriver();
File file = new File("src/css.html");
String filePath = "file:///" + file.getAbsolutePath();
System.out.printf("now accesss %s \n", filePath);
dr.get(filePath);
Thread.sleep(1000);
WebElement link = dr.findElement(By.id("tooltip"));
System.out.println(link.getCssValue("color"));
System.out.println(dr.findElement(By.tagName("h3")).getCssValue("font"));
Thread.sleep(1000);
System.out.println("browser will be close");
dr.quit();
}
}
获取测试对象的状态
场景
在web自动化测试中,我们需要获取测试对象的四种状态
· 是否显示。使用element.isDisplayed()方法;
· 是否存在。使用findElement方法,捕获其抛出的异常,如果是NoSuchElementException的话则可以确定该元素不存在;
· 是否被选中。一般是判断表单元素,比如radio或checkbox是否被选中。使用element.isSelected()方法;
· 是否enable,也就是是否是灰化状态。使用element.isEnabled()方法;
代码
status.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>status</title>
<script type="text/javascript" async="" ></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" />
<script type="text/javascript">
$(document).ready(function(){
$('#tooltip').tooltip({"placement": "right"});
});
</script>
</head>
<body>
<h3>status</h3>
<div>
<div>
<input name="user" placeholder="Disabled TextField" disabled />
</div>
<div>
<a class="btn disabled">Disabled Button</a>
</div>
<div>
<input name="radio" type="radio" />
</div>
</div>
</body>
<script ></script>
</html>
status.java
public class Status {
public static void main(String[] args) throws InterruptedException {
WebDriver dr = new ChromeDriver();
File file = new File("src/status.html");
String filePath = "file:///" + file.getAbsolutePath();
System.out.printf("now accesss %s \n", filePath);
dr.get(filePath);
Thread.sleep(1000);
WebElement textField = dr.findElement(By.name("user"));
System.out.println(textField.isEnabled());
// 直接用isEnabled方法去判断该button的话返回的会是true
// 这是因为button是使用css方法去disabled的,并不是真正的disable
// 这时候需要判断其class里是否有disabled这值来判断其是否处于disable状态
System.out.println(dr.findElement(By.className("btn")).isEnabled());
// 隐藏掉textField
// 判断其是否显示
((JavascriptExecutor)dr).executeScript("$(arguments[0]).hide()", textField);
System.out.println(textField.isDisplayed());
// 使用click方法选择raido
WebElement radio = dr.findElement(By.name("radio"));
radio.click();
System.out.println(radio.isSelected());
try{
dr.findElement(By.id("none"));
} catch(NoSuchElementException e){
System.out.println("element does not exist");
}
Thread.sleep(1000);
System.out.println("browser will be close");
dr.quit();
}
}
讨论
在这里我们遇到了一种情况,那就是测试对象看上去是disabled,但是使用enabled方法却返回true。这时候一般思路是判断该对象的css属性或class,通过这些值去进一步判断对象是否disable。
}