对Web进行自动化测试,我们首先想象一个简单的场景,来看看需要测试哪些东西:
a. 元素定位:无论使用XPath, Dom还是CSS,需要简单方便的API定位元素,可以延时等待元素出现;
b. 交互操作:包括文本框、单选框、多选框、按钮、表格单元的输入或者点击;
c. 页面操作:页面切换和关闭、对话框切换和关闭;
d. 其他要求:对主流浏览器测试的支持、对JavaScript的支持等。
说起Web自动化测试,首先想到的就是Selenium。其实WebDriver就是基于Selenium的一个自动化测试类库,但它不再是运行在浏览器内的JS程序,而是自己可以控制浏览器。旨在改进Selenium1.0中出现的诸多问题,并且提供了非常易用、可读性很强的API。
1. 简单例子
我们通过一个例子来初步认识一下WebDriver。简单起见,我们通过WebDriver连接到google网站上,通过关键词进行搜索,并且验证搜索结果。
代码如下:
- package selenium;
- import org.junit.Before;
- import org.junit.Test;
- import org.openqa.selenium.By;
- import org.openqa.selenium.WebDriver;
- import org.openqa.selenium.WebElement;
- import org.openqa.selenium.htmlunit.HtmlUnitDriver;
- import static junit.framework.Assert.assertNotNull;
- public class WebDriverTest {
- private WebDriver page;
- @Before
- public void before() {
- page = new HtmlUnitDriver();
- }
- @Test
- public void testHasAnImageSearchPage() throws Exception {
- page.get("http://www.google.cn");
- WebElement searchBox = page.findElement(By.name("q"));
- searchBox.sendKeys("JavaEye");
- WebElement subBtn = page.findElement(By.name("btnG"));
- subBtn.submit();
- WebElement result = page.findElement(By.linkText("http://www.iteye.com"));
- assertNotNull(result);
- }
- }
package selenium;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
import static junit.framework.Assert.assertNotNull;
public class WebDriverTest {
private WebDriver page;
@Before
public void before() {
page = new HtmlUnitDriver();
}
@Test
public void testHasAnImageSearchPage() throws Exception {
page.get("http://www.google.cn");
WebElement searchBox = page.findElement(By.name("q"));
searchBox.sendKeys("JavaEye");
WebElement subBtn = page.findElement(By.name("btnG"));
subBtn.submit();
WebElement result = page.findElement(By.linkText("http://www.iteye.com"));
assertNotNull(result);
}
}
2. HamcrestWebDriverTestCase
除了上面的写法,WebDriver还根据Hamcrest类库,利用它优秀的Matcher API,另外提供了的基类:HamcrestWebDriverTestCase,从该基类集成的测试用例,更易读。
代码如下:
- package selenium;
- import org.junit.Test;
- import org.openqa.selenium.WebDriver;
- import org.openqa.selenium.htmlunit.HtmlUnitDriver;
- import org.openqa.selenium.lift.HamcrestWebDriverTestCase;
- import static org.hamcrest.Matchers.equalTo;
- import static org.openqa.selenium.lift.Finders.div;
- import static org.openqa.selenium.lift.Finders.textbox;
- import static org.openqa.selenium.lift.find.InputFinder.submitButton;
- import static org.openqa.selenium.lift.find.LinkFinder.link;
- import static org.openqa.selenium.lift.match.AttributeMatcher.attribute;
- public class HamcrestTest extends HamcrestWebDriverTestCase {
- @Override
- protected WebDriver createDriver() {
- return new HtmlUnitDriver();
- }
- @Test
- public void testHasAnImageSearchPage() throws Exception {
- goTo("http://www.google.cn");
- type("JavaEye", into(textbox().with(attribute("name", equalTo("q")))));
- clickOn(submitButton().with(attribute("name", equalTo("btnG"))));
- assertPresenceOf(link("http://www.iteye.com"));
- }
- }
package selenium;
import org.junit.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
import org.openqa.selenium.lift.HamcrestWebDriverTestCase;
import static org.hamcrest.Matchers.equalTo;
import static org.openqa.selenium.lift.Finders.div;
import static org.openqa.selenium.lift.Finders.textbox;
import static org.openqa.selenium.lift.find.InputFinder.submitButton;
import static org.openqa.selenium.lift.find.LinkFinder.link;
import static org.openqa.selenium.lift.match.AttributeMatcher.attribute;
public class HamcrestTest extends HamcrestWebDriverTestCase {
@Override
protected WebDriver createDriver() {
return new HtmlUnitDriver();
}
@Test
public void testHasAnImageSearchPage() throws Exception {
goTo("http://www.google.cn");
type("JavaEye", into(textbox().with(attribute("name", equalTo("q")))));
clickOn(submitButton().with(attribute("name", equalTo("btnG"))));
assertPresenceOf(link("http://www.iteye.com"));
}
}
3. WebDriver, Web Driver
WebDriver有以下几种浏览器驱动器:
HtmlUnit Driver:
速度最快;平台独立;支持JavaS次日平台;
不是图形化的,即你无法在浏览器中看到页面元素被点击的过程;
其JavaScript引擎是Rhino,与主流浏览器的均不同(Chrome V8, Safari Nitro, FF TraceMonkey...),因此JavaScript执行结果可能稍微不同;
而另外三种FireFox Driver、Internet Explorer Driver和Chrome Driver都可在真正的浏览器中运行,因此是可视化的;并且支持JavaScript;只是运行速度较慢;
4. 更多的API
继续尝试下去,会遇到一些常用的API,主要包括:
Finder:在某些时候可以作为XPath查找方式的替代,使用比较方便;
Matcher:就是Hamcrest类库提供的Matcher API;
页面、frame等的切换、Cookie等等。
5. 局限?
a. WebDriver支持XPath的方式进行元素定位,可惜现在还不支持常用的CSS Selector定位。
b. WebDriver对javascript弹出的对话框暂时还不支持,不过应该很快了吧。
6. 总结:
由于提供了良好的API,解决了很多Selenium1.0的问题,它被即将发布的Selenium 2.0集成了进去,因此还是很值得一试。
参考资料:
2. Issue24:Allow use of CSS selectors
3. Selenium FAQ
webdriver入门-Java
如何用webdriver打开一个浏览器,我们常用的浏览器有firefox和IE两种,firefox是selenium支持得比较成熟的浏览器,很多新的特性都会在firefox中体现。但是做页面的测试,启动速度比较慢,启动以后运行速度还是可以接受的。
启动firefox浏览器
新建一个firefoxDriver
如果火狐浏览器没有默认安装在C盘,需要制定其路径
System.setProperty("webdriver.firefox.bin", "D:/Program Files/Mozilla firefox/firefox.exe");
WebDriver driver = newFirefoxDriver();
启动IE浏览器
//Create a newinstance of the Internet Explorer driver
WebDriver driver = newInternetExplorerDriver ();
启动HtmlUnit浏览器
//Createa new instance of the HtmlUnit driver
WebDriverdriver = new HtmlUnitDriver();
启动Chrome浏览器
//Createa new instance of the Chromedriver
System.setProperty(“webdriver.chrome.driver”, bsPath);
WebDriverdriver = new ChromeDriver();
对web页面进行测试,首先要打开被测试页面的地址(如:http://www.baidu.com),web driver 提供的get方法可以打开一个页面:
// And now use thedriver to visit Google
driver.get(“http://www.baidu.com“);
//也可以调用以下方法
driver.navigate().to(“http://www.baidu.com“);
测试脚本如下
package com.test.ui.demo;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class TestWebDriver {
private WebDriver driver = null;
private String url = “http://www.baidu.com“;
//每个用例执行前会执行该方法
@BeforeMethod
public void startUp(){
//如果firefox没有安装在c盘需要执行下面这句,否则请注释掉
System.setProperty(“webdriver.firefox.bin”, “D:/Program Files/Mozilla firefox/firefox.exe”);
driver = new FirefoxDriver();
}
//每个用例执行后会执行该方法
@AfterMethod
public void tearDown(){
//退出操作
driver.quit();
driver = null;
}
@Test
public void startTest(){
//打开新窗口
driver.get(url);
}
}
各种浏览器比较↓
Webdirver对浏览器的支持HtmlUnit Driver优点:HtmlUnit Driver不会实际打开浏览器,运行速度很快。对于用FireFox等浏览器来做测试的自动化测试用例,运行速度通常很慢,HtmlUnit Driver无疑是可以很好地解决这个问题。
缺点:它对JavaScript的支持不够好,当页面上有复杂JavaScript时,经常会捕获不到页面元素。
使用:
WebDriver driver = new HtmlUnitDriver();
FireFox Driver优点:FireFox Dirver对页面的自动化测试支持得比较好,很直观地模拟页面的操作,对JavaScript的支持也非常完善,基本上页面上做的所有操作FireFox Driver都可以模拟。
缺点:启动很慢,运行也比较慢,不过,启动之后Webdriver的操作速度虽然不快但还是可以接受的,建议不要频繁启停FireFox Driver。
使用:
WebDriver driver = new FirefoxDriver();
Firefox profile的属性值是可以改变的,比如我们平时可能需要通过代理上网,可以这样修改:
FirefoxProfile profile = new FirefoxProfile();
//使用profile
ProfilesIni allProfiles = new ProfilesIni();
FirefoxProfile profile = allProfiles.getProfile("default");
driver = new FirefoxDriver(profile);
// 使用代理
profile.setPreference(“network.proxy.type”, 1);
// http协议代理配置
profile.setPreference(“network.proxy.http”, proxyIp);
profile.setPreference(“network.proxy.http_port”, proxyPort);
// 所有协议公用一种代理配置,如果单独配置,这项设置为false,再类似于http的配置
profile.setPreference(“network.proxy.share_proxy_settings”, true);
// 对于localhost的不用代理,这里必须要配置,否则无法和webdriver通讯
profile.setPreference(“network.proxy.no_proxies_on”, “localhost”);
// 以代理方式启动firefox
FirefoxDriver ff = new FirefoxDriver(profile);
InternetExplorer Driver优点:直观地模拟用户的实际操作,对JavaScript提供完善的支持。
缺点:是所有浏览器中运行速度最慢的,并且只能在Windows下运行,对CSS以及XPATH的支持也不够好。
使用:
WebDriver driver = new InternetExplorerDriver();
元素操作↓
查找元素
使用操作如何找到页面元素Webdriver的findElement方法可以用来找到页面的某个元素,最常用的方法是用id和name查找。下面介绍几种比较常用的方法。
By ID假设页面写成这样:
<input type=”text” name=”userName” id=”user” />
那么可以这样找到页面的元素:
通过id查找:
WebElement element = driver.findElement(By.id(“user”));
By Name或通过name查找:
WebElement element = driver.findElement(By.name(“userName”));
By XPATH或通过xpath查找:
WebElement element =driver.findElement(By.xpath(“//input[@id='user']“));
By Class Name假设页面写成这样:
<div class=”top”><span>Head</span></div><divclass=”top”><span>HeadName</span></div>
可以通过这样查找页面元素:
List<WebElement>top= driver.findElements(By.className(“top”));
By Link Text假设页面元素写成这样:
<a href=”http://www.baidu.com”>baidu</a>>
那么可以通过这样查找:
WebElement baidu=driver.findElement(By.linkText(“baidu”));
输入框传值
输入框(text field or textarea) 找到输入框元素:
WebElement element = driver.findElement(By.id(“passwd-id”));
在输入框中输入内容:
element.sendKeys(“test”);
将输入框清空:
element.clear();
获取输入框的文本内容:
element.getText();
下拉菜单
下拉选择框(Select)找到下拉选择框的元素:
Select select = new Select(driver.findElement(By.id(“select”)));
选择对应的选择项:select.selectByVisibleText(“testName”);
或
select.selectByValue(“name”);
不选择对应的选择项:
select.deselectAll();
select.deselectByValue(“name”);
select.deselectByVisibleText(“姓名”);
或者获取选择项的值:
select.getAllSelectedOptions();
select.getFirstSelectedOption();
单选框
单选项(Radio Button)找到单选框元素:
WebElement sex=driver.findElement(By.id(“sex”));
选择某个单选项:
sex.click();
清空某个单选项:
sex.clear();
判断某个单选项是否已经被选择:
sex.isSelected();
复选框
多选项(checkbox)多选项的操作和单选的差不多:
WebElement area =driver.findElement(By.id(“area .”));
area .click();
area .clear();
area .isSelected();
area .isEnabled();
按钮
按钮(button)找到按钮元素:
WebElement saveButton = driver.findElement(By.id(“save”));
点击按钮:
saveButton.click();
判断按钮是否enable:
saveButton.isEnabled ();
左右选择框也就是左边是可供选择项,选择后移动到右边的框中,反之亦然。例如:
Select name= new Select(driver.findElement(By.id(“name”)));
name.selectByVisibleText(“hellen”);
WebElement addName=driver.findElement(By.id(“addButton”));
addName.click();
弹出框
弹出对话框(Popup dialogs)Alert alert = driver.switchTo().alert();
alert.accept();
alert.dismiss();
alert.getText();
表单提交
表单(Form)Form中的元素的操作和其它的元素操作一样,对元素操作完成后对表单的提交可以:
WebElement sub= driver.findElement(By.id(“sub”));
sub.click();
或
sub.submit();//只适合于表单的提交
上传附件
上传文件 (Upload File)上传文件的元素操作:
WebElement picFile = driver.findElement(By.id(“picFile ”));
String filePath = “d:\\report\\600x600x0.jpg”;
picFile .sendKeys(filePath);
多窗口切换
Windows 或 Frames之间的切换
首先切换到默认的frame
driver.switchTo().defaultContent();
切换到某个frame:
driver.switchTo().frame(“leftFrame”);
从一个frame切换到另一个frame:
driver.switchTo().frame(“mainFrame”);
切换到某个window:
driver.switchTo().window(“windowName”);
导航
导航 (Navigationand History)打开一个新的页面:
driver.navigate().to(“http://www.baidu.com”);
通过历史导航返回原页面:
driver.navigate().forward();
driver.navigate().back();
以上为简单介绍了一下webDriver中常遇到的操作,有问题可以查阅官方的API文档