Selenium和WebDriver(本質上現在是Selenium的繼承者)都提供了一種無需人工就可以在多個目標環境中對Web應用程序進行功能測試的好方法。 過去,Web UI是使用頁面導航構建的,以允許用戶提交表單等。如今,越來越多的Web應用程序使用Ajax,因此其行為和外觀與桌面應用程序非常相似。 但是,這給測試帶來了問題– Selenium和WebDriver旨在與用戶交互配合使用,從而導致頁面導航,并且不能與現成的AJAX應用很好地配合使用。
基于GWT的應用程序尤其存在此問題,但是我發現有一些方法可以開發有用且有效的測試。 在模擬用戶輸入和查找DOM元素方面,GWT還提出了其他問題,我將在下面進行討論。 請注意,我的代碼示例使用Groovy使其簡潔,但是可以很容易地將它們轉換為Java代碼。
問題1:處理異步更改
在測試基于GWT的應用程序時,開發人員很快就會面臨的一個問題是檢測并等待對用戶交互的響應。 例如,用戶可以單擊導致AJAX調用的按鈕,該調用將成功并關閉窗口,或者顯示錯誤消息。 我們需要的是一種阻止方法,直到我們看到預期的變化,并且超時,這樣,如果我們看不到預期的變化,我們可能會失敗。
解決方案:使用WebDriverWait
最簡單的方法是利用WebDriverWait(或Selenium的Wait)。 這使您可以等待條件,并在條件評估為true時繼續進行。 下面,為了簡潔地使用閉包,我使用了Groovy代碼,但是在Java中也可以做到這一點,盡管由于需要匿名類,所以使用了更多代碼。
def waitForCondition(Closure closure) {int timeout = 20WebDriverWait w = new WebDriverWait(driver, timeout)w.until({closure() // wait until this closure evaluates to true} as ExpectedCondition)
}def waitForElement(By finder) {waitForCondition {driver.findElements(finder).size() > 0;}
}def waitForElementRemoval(By finder) {waitForCondition {driver.findElements(finder).size() == 0;}
}// now some sample test code submitButton.click() // submit a form// wait for the expected error summary to show up
waitForElement(By.xpath("//div[@class='error-summary']"))
// maybe some more verification here to check the expected errors// ... correct error and resubmitsubmitButton.click()
waitForElementRemoval(By.xpath("//div[@class='error-summary']"))
waitForElementRemoval(By.id("windowId"))
從示例中可以看到,您的代碼可以專注于實際的測試邏輯,同時無縫地處理GWT應用程序的異步特性。
問題2:在您對DOM幾乎沒有控制的情況下定位元素
在使用模板的Web應用程序(JSP,Velocity,JSF等)中,您可以很好地控制并輕松查看頁面將具有的DOM結構。 對于GWT,情況并非總是如此。 通常,您正在處理無法精確控制的嵌套元素。
使用WebDriver和Selenium,可以使用幾種方法來定位元素,但最有用的是DOM元素ID和XPath。 我們如何利用它們來獲得可維護的測試,而這些測試不會因布局的微小變化而中斷?
解決方案:結合使用XPath和ID來限制范圍
以我的經驗,要在WebDriver中開發功能性GWT測試,您應該使用稍微松散的XPath作為查找元素的主要方法,并在適用時通過DOM ID對這些調用進行作用域來對其進行補充。
特別是,請在應用程序中唯一的窗口或選項卡等頂級元素上使用ID,這些ID在頁面中不會出現多次。 這些可以幫助確定您的XPath表達式的范圍,該表達式可以查找窗口或表單標題,字段標簽等。
以下是一些示例,可助您一臂之力。 請注意,我們在XPath中使用//和*來保持表達式的靈活性,以便除非主要更改布局更改,否則不會破壞我們的測試。
By byUserName = By.xpath("//*[@id='userTab']//*[text()='User Name']/..//input")
WebElement userNameField = webDriver.findElement(byUserName)
userNameField.sendKeys("my new user")// maybe a user click and then wait for the window to disappear
By submitLocator = By.xpath("//*[@id='userTab']//input[@type='submit']")
WebElement submit = webDriver.findElement(submitLocator)
submit.click()// use our helper method from Problem 1
waitForElementRemoval By.id("userTab")
問題3:法線元素交互方法不起作用!
就管理DOM的狀態而言,GWT及其派生工具(Vaadin,GXT等)通常在幕后發揮作用。 對開發人員來說,這意味著您不必總是處理普通的<input>或<select>等元素。 僅通過常規方法簡單地設置字段的值可能不起作用,并且使用WebDriver或Selenium的click方法可能不起作用。
WebDriver在這方面有所改進,但是問題仍然存在。
解決方案:不幸的是,只有一些解決方法
您可能會遇到的主要問題與在字段中鍵入和單擊元素有關。
以下是一些我過去發現有必要的變體,可以避免點擊無法正常運行。 如果遇到問題,請嘗試一下。 這些示例在Selenium中,但是如果需要,可以將它們改編為適用于WebDriver中的相應調用。 如果您想直接使用示例,也可以將Selenium適配器用于WebDriver(WebDriverBackedSelenium)。
點擊問題
有時,元素不會響應Selenium或WebDriver中的click()調用。 在這些情況下,通常必須在瀏覽器中模擬事件。 Selenium在2.0之前比WebDriver更是如此。
// Selenium's click sometimes has to be simulated with events.
def fullMouseClick(String locator) {selenium.mouseOver locatorselenium.mouseDown locatorselenium.mouseUp locator
}// In some cases you need only mouseDown, as mouseUp may be
// handled the same as mouseDown.
// For example, this could result in a table row being selected, then deselected.
def mouseOverAndDown(String locator) {selenium.mouseOver locatorselenium.mouseDown locator
}
打字問題
這些是過去在GWT無法識別鍵入的輸入時能夠成功使用的回旋輸入法。
// fires only key events (works for most GWT inputs)
// Useful if WebDriver sendKeys() or Selenium type() aren't cooperating.
def typeWithEvents(String locator, String text) {def keyEvents = ["keydown", "keypress", "keyup"]typeWithEvents(locator, text, keyEvents)
}// fires key events, plus blur and focus for really picky cases
def typeWithFullEvents(String locator, String text) {def fullEvents = ["keydown", "keypress", "keyup", "blur", "focus"]typeWithEvents(locator, text, fullEvents)
}// use this directly to customize which events are fired
def typeWithEvents(String locator, String text, def events) {text.eachWithIndex { ch, i ->selenium.type locator, text.substring(0, i+1)events.each{ event ->selenium.fireEvent locator, event}}
}
請注意,必須通過反復試驗找出有效的方法,在某些情況下,您在不同的瀏覽器中可能會得到不同的行為,因此,如果針對不同的環境運行功能測試,則必須確保您的方法適用于所有這些方法。
結論
希望你們中的一些人發現這些技巧有用。 那里也有類似的技巧,但我想匯編一套很好的示例和變通方法,以使處于類似情況的其他人不會陷入僵局,也不會在需要大量猜測和時間的問題上浪費時間。
參考: Carfey Software博客上的JCG合作伙伴提供的使用Selenium或WebDriver測試GWT應用程序 。
- 任何軟件開發公司應存在的服務,實踐和工具,第2部分
- 為什么自動化測試可以提高您的開發速度
- 不執行代碼審查? 你的借口是什么
- 軟件可靠性的教訓
- 這是在您的業務邏輯之前!
- 單元和集成測試的代碼覆蓋率
翻譯自: https://www.javacodegeeks.com/2011/10/testing-gwt-apps-with-selenium-or.html