Selenium Webdriver重新使用已開啟的瀏覽器例項
我弄這個的本意是為了在SoapUI中更好地編寫自動化用例,因為我的業務流程有的很長,有7-8個頁面。
我想把程式碼不集中在一個Groovy 腳本里,想在第二個指令碼中繼續使用第一個指令碼中開啟的瀏覽器。這樣便於
維護和定位問題。
也還有一種情況是我打開了瀏覽器,,操作了系統到某一個介面後,我寫了這個頁面的測試指令碼,使用已
開啟的瀏覽器我立刻就可以單獨對這個頁面進行測試,測試我寫的程式碼是否OK 。不通過就人工操作復位頁面,
修改程式碼後再次測試,不用每次測試程式碼是否可行都從頭打卡瀏覽器,登入系統,重新操作了。可以實現分步
單頁面除錯自動化指令碼。
首先,來簡單看一下Selenium Webdriver如何工作的。
(1)Selenium程式碼呼叫API實際上根據 The WebDriver Wire Protocol 傳送不同的Http Request 到 WebdriverServer。
IE 是 IEDriverServer.exe
Chrome是ChromerDriver,下載地址:
Firefox是以外掛的形式,直接在selenium-server-standalone-XXX.jar裡了:
webdriver.xpi (selenium-server-standalone-2.48.2.jar中/org/openqa/selenium/firefox/目錄下)
new FirefoxDriver()時,啟動Firefox瀏覽器時,帶此外掛一起啟動,然後外掛會預設監聽7055埠,7055被佔用就使用下一個埠。如下圖所示。
同一臺機器上可以同時啟動多個FirefoxDriver例項,每個例項佔用不同的埠號。
The WebDriver Wire Protocol 協議的具體內容請看:https://code.google.com/p/selenium/wiki/JsonWireProtocol#Introduction。 這個協議現在正在被W3C標準化,W3C Webdriver,兩者基本一樣。
W3C Webdriver標準協議內容:http://www.w3.org/TR/webdriver/
(2)WebdriverServer接收到Http Request之後,根據不同的命令在作業系統層面去觸發瀏覽器的”native事件“,
模擬操作瀏覽器。WebdriverServer將操作結果Http Response返回給程式碼呼叫的客戶端。
為了更清晰直觀地看到這個是如何運轉的,我們來在使用OWASP ZAP做代理,截獲Http Request和Response來看一下。
首先安裝OWASP ZAP或其他有代理功能的工具,設定SoapUI Proxy,如ZAP預設使用8080埠,則SoapUI配置如下:
配置完SoapUI埠後,好像需要重啟SoapUI,然後在SoapUI 的自動化測試程式碼中,代理才能正常工作。
重新跑前一節FirefoxDriver的程式碼,檢視截獲的請求和響應。如下圖所示:
可以清楚地看到程式碼與DriverServer之間是如何根據WebDriver協議連通的。
WebDriver協議是RESTful風格的。
回到我們的主題:Webdriver重新使用已開啟的瀏覽器例項。
Webdriver例項都將重新開啟一個瀏覽器,新建一個Session。Selenium並沒有介面或方法可以使用已有Session。
如果在一個測試用例中不將瀏覽器退出關閉,想要在另一個新的測試用例中使用已開啟的瀏覽器的話,怎麼辦?
Selenium Webdriver本省並沒有這種介面。本人自己實現了一個基於FirefoxDriver的,因為我基本只用Firefox,
IE 什麼的,沒需求,沒動力啊,但是大概原理應該類似,差不多。
FirefoxDriver是主要是由startClient()和startSession()完成初始化。startClient()中開啟瀏覽器,設定執行器HttpCommandExecutor。
StartSession執行New Session指令,獲取SessionID,並根據響應,設定capabilities。
具體有興趣的可以自己下載原始碼,自己看。
根據上文,Webdriver 想要執行命令,需要1:WebdriverServer的地址 2:一個可用的SessionID 。
寫一個自己的WebDriver類來new一個Webdriver。
因此需要在一個用例中儲存WebdriverServer的地址和SessionID ,最後不退出關閉瀏覽器。
另一個用例中使用儲存的引數,完成Webdriver的例項化。
程式碼就不貼在文章裡了:原始碼及jar包下載地址:
http://download.csdn.net/detail/wwwqjpcom/9500777
其中的初始化程式碼如下(需要兩個引數 Webdriver 的地址和SessionID):
public myFirefoxDriver(String localserver,String sessionID){
mystartClient(localserver);
mystartSession(sessionID);
}
程式碼例子:
測試用例1中開啟瀏覽器,但是不退出關閉瀏覽器:
import org.openqa.selenium.By
import org.openqa.selenium.WebDriver
import org.openqa.selenium.WebElement
import org.openqa.selenium.firefox.FirefoxDriver
import org.openqa.selenium.support.ui.ExpectedCondition
import org.openqa.selenium.support.ui.WebDriverWait
import org.openqa.selenium.OutputType
import org.apache.commons.io.FileUtils
import org.openqa.selenium.Keys
WebDriver driver = new FirefoxDriver()
try
{
driver.get("https://learnsoapui.wordpress.com") // Url to be opened
//下面兩行將所需的地址和SessionID 儲存起來。樣例因為是在SoapUI中的兩個Step,所以儲存為了SoapUI中
//用例級別的屬性,具體請根據自己的使用環境儲存為系統引數或其他地方
testRunner.testCase.setPropertyValue( "DriverServer", driver.getCommandExecutor().getAddressOfRemoteServer().toString() )
testRunner.testCase.setPropertyValue( "CaseSession", driver.getSessionId().toString() )
log.info driver.getSessionId().toString()
WebElement element = driver.findElement(By.id("s"))
element.sendKeys("Assertion")
File f1 = driver.getScreenshotAs(OutputType.FILE)
FileUtils.copyFile(f1, new File("c:\\screenshot1.png")); // Location to save screenshot
element.submit()
driver.getKeyboard ().pressKey (Keys.DOWN)
driver.getKeyboard ().pressKey (Keys.DOWN)
driver.getKeyboard ().pressKey (Keys.DOWN)
driver.getKeyboard ().pressKey (Keys.UP)
driver.getKeyboard ().pressKey (Keys.UP)
driver.getKeyboard ().pressKey (Keys.UP)
}
catch(Exception e)
{
log.info "Exception encountered : " + e.message
}
測試用例2中繼續使用1中已開啟的瀏覽器:
import webtest.myFirefoxDriver;
import org.openqa.selenium.By
import org.openqa.selenium.WebDriver
import org.openqa.selenium.WebElement
import org.openqa.selenium.firefox.FirefoxDriver
import org.openqa.selenium.JavascriptExecutor
//下面三行,取出儲存的可用的瀏覽器的Webdriver Server的地址和SessionID,new一個Webdriver。
def driverserver = testRunner.testCase.getPropertyValue( "DriverServer" )
def caseSession = testRunner.testCase.getPropertyValue( "CaseSession" )
WebDriver driver = new myFirefoxDriver(driverserver,caseSession)
log.info (driver.getCommandExecutor().getAddressOfRemoteServer())
try
{
driver.findElement(By.linkText("Home")).click()// Url to be opened
driver.findElement(By.linkText("About Author")).click()// Url to be opened
log.info driver.getSessionId().toString()
log.info driver.getCapabilities()
((JavascriptExecutor)driver).executeScript("alert(\"hello,this is a alert!\")");
//driver.quit()
}
catch(Exception e)
{
log.info "Exception encountered : " + e.message
}
注意程式碼中的文字註釋下方部分,1中要將WebdriverServer的地址和SessionID 儲存起來,
2中使用1中儲存的引數,用實現的自己的myFirefoxDriver來初始化driver。
(此處感謝https://learnsoapui.wordpress.com/ , 我最初研究在SoapUI中使用Selenium
Webdriver看了這個,雖然感覺他講的也是不明不白的 ,但是給了我啟發)。
注:(1)webtest01.jar是我在Selenium 2.48.2版本的程式碼下編譯的,本人只配合用過Selenium 2.48.2
和Selenium 2.53.0這兩個版本可用,其他的Selenium版本我是沒試過的,說不定老版本不支援的。)
(2)實際中myFirefoxDriver不僅可以在本地用,用來RemoteWebdriver遠端呼叫也是可以用的,即開啟
RemoteWebdriver,然後用myFirefoxDriver來繼續使用遠端的那個已開啟的瀏覽器例項,反正是隻需要那兩
個引數就可以,反正我自己用的時候這種情況也是是可以用的。僅供參考,不提供技術支援,呃,後果自負哦。