1 簡介
資源
jar包:http://code.google.com/p/selenium/downloads/list or http://selenium-release.storage.googleapis.com/index.html
官方 UserGuide:http://seleniumhq.org/docs/
2 基本配置
2.1 Firefox
對於不同的瀏覽器,需要創建不同類型的WebDriver進行測試,默認情況下我們通常可以直接 new XXXDriver() 來創建對應類型的 WebDriver。
如果使用Firefox測試,而Firefox又沒有安裝在默認目錄下,那麼直接 new FirefoxDriver()將會出現異常提示找不到瀏覽器。這時,我們需要在程序開始調用以下代碼,用以指定Firefox的位置:
System.setProperty(“webdriver.firefox.bin”, “***\\firefox.exe”) |
或者我們使用 FirefoxBinary 實例來指定瀏覽器的位置:
File firefox = new File(“…\\firefox.exe”); FirefoxBinary firefoxbin = new FirefoxBinary(firefox); WebDriver driver = new FirefoxDriver(firefoxbin, null); |
值得注意的是,使用以上兩種配置啓動的Firefox瀏覽器是“全新”的,也就是說瀏覽器的設置都是初始的,包括插件集。這會使依賴 Firebug 等插件的開發調試工作無法進行,於是我們需要保留瀏覽器的配置信息。
這需要使用FirefoxProfile 實例來指定配置文件的位置:
String path = System.getProperty( "user.home" ) + "\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles\\"; File prodir = new File( path ); File[] files = prodir.listFiles( new FilenameFilter() { @Override public boolean accept( File dir, String name ) { return name.endsWith( ".default" ); } } ); FirefoxProfile profile = new FirefoxProfile( files[0] ); |
綜上而言,我們通常會使用 FirefoxDriver(FirefoxBinarybinary, FirefoxProfile profile) 形式的構造器。
2.2 Chrome
與Firefox類似,如果測試程序找不到Chrome的安裝位置(非默認位置),那麼可以這樣指定:
System.setProperty(“webdriver.chrome.driver”, “***\\chrome.exe”) |
但是,使用Chrome測試,比較特別的是,需要驅動程序:
通常,我們使用 ChromeDriver(ChromeDriverServiceservice, ChromeOptions options) 形式的構造器,前一參數可指定驅動程序的位置,後一參數可指定瀏覽器的位置。
ChromeDriverService 實例的創建如下:
String chromeDriver = "…\\chromedriver.exe"; ChromeDriverService service = new ChromeDriverService.Builder(). usingDriverExecutable( new File(chromeDriver) ).build(); |
ChromeOptions 實例的創建如下:
String chrome = "…\\chrome.exe"; ChromeOptions options = new ChromeOptions(); options.setBinary( chrome ); |
3 基本使用
3.1 打開瀏覽器
開始測試前,總是應該創建一個WebDriver接口實現類實例,以打開某種瀏覽器。
// 創建Firefox driver實例,打開Firefox WebDriver driver = new FirefoxDriver(); // 創建IE driver實例,打開IE WebDriver driver = new InternetExplorerDriver(); |
3.2 打開測試頁面
打開瀏覽器後,應該導航到測試頁面進行測試。
driver.get( "http://www.baidu.com" ) |
另一種可選方式是:
driver.navigate().to( "http://www.baidu.com" ); |
3.3 查找元素
導航到測試頁面後,就應該要查找頁面元素進行操作了。
由於Selenium2推崇面向接口編程,所以所有元素都使用WebElement接口代表。
定位元素位置可以在WebDriver實例上進行,也可以在某個WebElement上進行。它們都暴露了findElement()和findElements()方法,前者查找返回一個WebElement對象否則拋出異常;後者查找返回一個WebElement列表,如果沒有匹配項列表可能爲空。
兩種find方法都使用By類實例進行定位。By是一個抽象類,所以實際使用的應是它的派生子類,每種派生子類都代表一種查找策略。通常我們不直接調用其派生子類的構造器創建對象,而是使用By類的靜態工廠方法來創建。
下面逐一說明各種定位方式。
3.3.1 By ID
通過ID查找。這是最高效也最常用的定位方式。但是,可能存在的陷阱是:網頁中ID並非唯一或者ID是自動生成的。使用中應該避免這些情況。
WebElement element = driver.findElement(By.id("coolestWidgetEvah")); |
3.3.2 By Name
通過name查找。
WebElement cheese = driver.findElement(By.name("cheese")); |
3.3.3 By XPath
通過XPath查找。WebDriver試圖在任何地方使用瀏覽器原生XPath能力,但是對於原生不支持XPath的瀏覽器,將提供實現。這可能導致一些非預期的行爲,除非你清楚不同XPath引擎間的差異。
Driver |
Tag and Attribute Name |
Attribute Values |
Native XPath Support |
Lower-cased |
As they appear in the HTML |
Yes |
|
Lower-cased |
As they appear in the HTML |
No |
|
Case insensitive |
As they appear in the HTML |
Yes |
比如如下頁面:
<input type="text" name="example" /> <INPUT type="text" name="other" /> |
查找語句爲:
List<WebElement> inputs = driver.findElements(By.xpath("//input")); |
匹配結果爲:
XPath expression |
|||
//input |
1 (“example”) |
2 |
2 |
//INPUT |
0 |
2 |
0 |
有時元素不必聲明某些有默認值的屬性,比如input元素的type屬性可以缺省,缺省值爲text。但是在WebDriver中使用XPath時,你不能期望能夠匹配未聲明的默認屬性。
3.3.4 By Class Name
通過class屬性查找。實際使用中相同的class屬性一般對應多個元素,所以一般會查找到多個元素,然後取用第一個元素。
List<WebElement> cheeses = driver.findElements(By.className("cheese")); |
3.3.5 By Link Text
通過超鏈接文本查找超鏈接。
WebElement cheese = driver.findElement(By.linkText("cheese")); |
3.3.6 By Partial Link Text
通過部分超鏈接文本查找超鏈接。
WebElement cheese = driver.findElement(By.partialLinkText("cheese")); |
3.3.7 By Css Selector
通過Css Selector查找。如果瀏覽器默認原生支持css查詢,可參閱w3c css selectors;否則Sizzle被使用。IE6,7和FF3.0都使用Sizzle作爲css查詢引擎。
注意並非所有的瀏覽器都是等效的,有的css在一箇中起作用也許在另一箇中不會。
WebElement cheese = driver.findElement(By.cssSelector("#food span.dairy.aged")); |
3.3.8 By TagName
通過元素標籤名查找。
WebElement frame = driver.findElement(By.tagName("iframe")); |
3.4 界面操作
找到頁面元素後,需要操作元素,通常WebElement接口方法就足以操作大多數元素了。
3.4.1 通用操作
// 點擊 element.click(); // 文本框輸入 element.sendKeys(“*****”); // 文本框清空 element.clear(); // 是否選中,單/多選等 element.isSelected(); // 是否可用 element.isEnabled(); |
3.4.2 文件域
file.sendKeys(filePath); |
3.4.3 下拉列表
對於下拉列表這種較複雜的元素,使用通用的方法來操作將不是那麼高效的。我們可以將其封裝爲Select對象,這將提供更多有用的方法便於操作。
Select select = new Select(driver.findElement(By.tagName("select"))); select.selectByVisibleText(“***”); select.deselectByVisibleText(“***”); select.selectByValue(“***”); select.deselectByValue(“***”); select.deselectAll(); select.getAllSelectedOptions(); select.getFirstSelectedOption(); |
3.4.4 表單
一旦填寫完表單,我們就期望提交它。一個提交的方法是找到“提交”按鈕並點擊它。
driver.findElement(By.id("submit")).click(); |
另外,WebDriver爲每個元素都提供了一個方便的submit()方法。如果你調用一個處於表單中的元素的submit()方法,WebDriver將沿DOM向上查找直到找到表單然後提交。如果元素不在表單中,則會拋出NoSuchElementException異常。
// 表單提交 element.submit(); |
3.4.5 Actions
// 拖拽元素到目標元素中 new Actions( driver ).dragAndDrop( element, target ).perform(); // hover new Actions(driver).moveToElement( text ).perform(); |
3.4.6 對話框
我們可以獲取到各種彈出對話框的對象,並可以執行accept、dismiss、讀取內容或者向prompt中輸入內容等操作。
Alert alert = driver.switchTo().alert(); alert.accept(); alert.dismiss(); alert.getText(); alert. sendKeys(); |
3.4.7 Windows和Frames切換
有的Web應用是多框架或多窗口的。
WebDriver支持在命名窗口間切換:
driver.switchTo().window("windowName"); |
怎樣知道窗口的名字呢?查看一下打開它的JS或超鏈接:
<a href="somewhere.html" target="windowName">Click here to open a new window</a> |
另外,也可以使用窗口句柄,這可能需要迭代所有窗口句柄來獲取某個窗口的句柄了:
for (String handle : driver.getWindowHandles()) { driver.switchTo().window(handle); } |
在框架間切換也是類似的:
driver.switchTo().frame("frameName"); |
3.4.8 導航
driver.navigate().forward(); driver.navigate().back(); |
4 非界面操作
4.1 Cookie
driver.manage().addCookie(cookie); driver.manage().getCookies(); driver.manage().getCookieNamed(“cookieName”); driver.manage().deleteCookieNamed(“cookieName”); driver.manage().deleteCookie(cookie); driver.manage().deleteAllCookies(); |
4.2 執行JS
可以執行任意JS腳本來查找一個元素,並且只要返回一個DOM元素,它將被自動轉換爲WebElement對象。
WebElement element = (WebElement) ((JavascriptExecutor)driver).executeScript("return $('.cheese')[0]"); |
4.3 截圖
測試過程中,可以把頁面截圖,保存成爲圖片。
需要注意,截取的圖片存在臨時目錄,所以需要將其拷貝到指定的目錄,否則測試完成可就找不到截圖了。
File screenshotFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE); FileUtils.copyFile( screenshotFile, new File("E:\\1.png") ); |
或遠程截圖
WebDriver augmentedDriver = new Augmenter().augment(getDriver()); File screenshotFile = ((TakesScreenshot)augmentedDriver).getScreenshotAs(OutputType.FILE); |
4.4 等待
當頁面需要一段時間才能加載完成,那麼就需要等待完成後才進行查找和操作。
等待有2種:顯性等待和隱性等待。
顯性等待使用WebDriverWait類和ExpectedCondition接口完成,編碼實現ExpectedCondition接口用以判斷某種條件,然後等待這種條件達成或超時。
WebElement myDynamicElement = (new WebDriverWait(driver, 10)) .until(ExpectedConditions.presenceOfElementLocated(By.id("myDynamicElement"))); |
ExpectedConditions類提供了許多靜態工廠方法,返回常用的ExpectedCondition對象。
隱性等待更爲簡潔:
driver.manage().timeouts().implicitlyWait( 10, TimeUnit.SECONDS ); |
但是隱性等待的設置將影響後續全局的查找操作。
4.5 改變User Agent
FirefoxProfile profile = new FirefoxProfile(); profile.addAdditionalPreference("general.useragent.override", "some UA string"); WebDriver driver = new FirefoxDriver(profile); |
5 附錄
5.1 注意
5.1.1 關於click()
當調用WebElement.click()時,如果被操作元素是不可用的(disabled),click()方法調用仍會是正常的,不會有異常。
所以,如果會出現被點擊的元素是不可用的情況,而點擊不可用元素又被認爲是非法的,那麼應該在click()調用前使用isEnable()方法檢查元素可用性。
5.1.2 driver.close() vs.driver.quit()
在測試結束後通常需要關閉瀏覽器,這個操作通常使用close()或quit()方法完成。但是兩者是有區別的,其方法說明也體現了這一點。
close() |
Close the current window, quitting the browser if it's the last window currently open. |
quit() |
Quits this driver, closing every associated window. |
對於close()而言,如果當前窗口是最後一個打開窗口,那麼關閉當前窗口退出瀏覽器;quit()則關閉每個關聯的窗口退出瀏覽器。
但是,實際使用中close()方法的行爲同說明有一些出入。以firefox爲例,噹噹前窗口爲最後一個打開窗口時,close()方法不會將最後一個窗口關閉,當然也不會使firefox退出。
5.2 常用API
5.2.1 Sleeper
原生休眠類
org.openqa.selenium.browserlaunchers.Sleeper
public static void sleepTightInSeconds(longtimeoutInSeconds)
public static void sleepTight(long timeout)