使用Selenium或WebDriver測試GWT應用

對于Web應用程序開發人員及其團隊而言,良好的功能測試是最困難的任務之一。 開發價格低廉且維護良好的測試是一項挑戰,這有助于降低質量檢查成本并提高質量。

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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/374022.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/374022.shtml
英文地址,請注明出處:http://en.pswp.cn/news/374022.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

MySQL中有關TIMESTAMP和DATETIME的總結

一、MySQL中如何表示當前時間&#xff1f; 其實&#xff0c;表達方式還是蠻多的&#xff0c;匯總如下&#xff1a; CURRENT_TIMESTAMP CURRENT_TIMESTAMP() NOW() LOCALTIME LOCALTIME() LOCALTIMESTAMP LOCALTIMESTAMP() 二、關于TIMESTAMP和DATETIME的比較 一個完整的日期格式…

NYOJ 202 紅黑樹

紅黑樹 時間限制&#xff1a;3000 ms | 內存限制&#xff1a;65535 KB難度&#xff1a;3描述 什么是紅黑樹呢&#xff1f;顧名思義&#xff0c;跟棗樹類似&#xff0c;紅黑樹是一種葉子是黑色果子是紅色的樹。。。 當然&#xff0c;這個是我說的。。。 《算法導論》上可不是這么…

為對象添加方法mothod

Function.prototype.mothod function( name, fn ) { this.prototype[name] fn ; return this ; };轉載于:https://www.cnblogs.com/40dadao/p/5816521.html

python爬蟲cookie池 與ip綁定_Python爬蟲:設置Cookie解決網站攔截并爬取螞蟻短租

前言文的文字及圖片來源于網絡,僅供學習、交流使用,不具有任何商業用途,版權歸原作者所有,如有問題請及時聯系我們以作處理。作者&#xff1a; EastmountPS&#xff1a;如有需要Python學習資料的小伙伴可以加點擊下方鏈接自行獲取我們在編寫Python爬蟲時&#xff0c;有時會遇到…

Java Secret:加載和卸載靜態字段

總覽 首先&#xff0c;很自然地假設靜態字段具有特殊的生命周期&#xff0c;并且在應用程序的生命周期中一直存在。 您可以假設它們存在于內存中的特殊位置&#xff0c;例如C或類元信息的perm gen中的內存開始。 但是&#xff0c;得知靜態字段駐留在堆上&#xff0c;可以具有任…

HTTP協議詳解(真的很經典)

轉自&#xff1a;http://blog.csdn.net/gueter/archive/2007/03/08/1524447.aspx Author :Jeffrey 引言 HTTP是一個屬于應用層的面向對象的協議&#xff0c;由于其簡捷、快速的方式&#xff0c;適用于分布式超媒體信息系統。它于1990年…

NYOJ 63 小猴子下落

小猴子下落 時間限制&#xff1a;3000 ms | 內存限制&#xff1a;65535 KB難度&#xff1a;3描述 有一顆二叉樹&#xff0c;最大深度為D,且所有葉子的深度都相同。所有結點從左到右從上到下的編號為1,2,3&#xff0c;&#xff0c;2的D次方減1。在結點1處放一個小猴子&#xff0…

python科學計算與圖形渲染_寧哥Python科學計算與圖形渲染庫課程

50dccd474759c0ffd343efcac14f8ab2.png (259.41 KB, 下載次數: 0)2019-4-9 12:23 上傳課程目錄章節1: NumPy基礎知識課時1NumPy簡介14:05課時2搭建NumPy開發環境&#xff0c;驗證NumPy開發環境17:08課時3源代碼和數據下載章節2: NumPy數組課時4創建多維數組09:20課時5獲取單個數…

http協議說明

今天公司有同事讓我給他講一講http..然后自己寫了一個示例代碼,這如果都看不懂.那我也沒辦法了.... 1 <?php2 3 //這里服務器以apache舉例.nginx.iis.他們實際上處理方式的都是同理4 //申明http鏈接的數據包 注意最后面有兩個換號.這是告訴apache.數據包的結束,如果后面沒…

JBoss模塊示例–模塊化Web應用程序

最近&#xff0c;我讀了為什么沒有標準來開發真正的模塊化Web應用程序&#xff1f; 由Patroklos Papapetrou撰寫&#xff08; 在Java Code Geeks中也有介紹 &#xff09;。 受本文的啟發&#xff0c;我決定檢查實際使用的JBoss模塊 。 這篇文章逐步描述了我的實驗。 我首先想到…

由MySql漏洞導致電腦被入侵(特征為新增加名為piress的帳戶)

今天開機&#xff0c;突然發現新增了一個名為piress的賬戶&#xff0c;突然間就意識到我的電腦可能被入侵了。后來發現網上很多人都遇到這樣的問題。經過一步步的查證&#xff0c;原來最近MySQL爆出一個安全漏洞&#xff0c;遠程登錄mysql&#xff0c;嘗試225次后就可以繞過身份…

multiprocessing.manager管理的對象需要加鎖嗎_Go: 內存管理和分配

本文基于Go1.13當不再使用內存時&#xff0c;標準庫會自動執行Go的內存管理即從分配到回收。盡管開發者不需要處理它&#xff0c;但是Go的底層管理進行了很好的優化并且充滿了有趣的概念。堆上的分配內存管理被設計可以在并發環境快速執行并且集成了gc。讓我們從一個例子開始&a…

NYOJ 35表達式求值

表達式求值 時間限制&#xff1a;3000 ms | 內存限制&#xff1a;65535 KB難度&#xff1a;4描述 ACM隊的mdd想做一個計算器&#xff0c;但是&#xff0c;他要做的不僅僅是一計算一個AB的計算器&#xff0c;他想實現隨便輸入一個表達式都能求出它的值的計算器&#xff0c;現在請…

Java EE6 CDI,命名組件和限定符

Java EE6的最大承諾之一就是簡化了依賴注入的使用。 他們做到了&#xff0c;使用CDI 。 CDI代表Java EE的上下文和依賴注入&#xff0c;它提供了一個基礎集&#xff0c;用于在企業應用程序中應用依賴注入。 在CDI之前&#xff0c;EJB 3還引入了依賴注入&#xff0c;但這有點基礎…

c#獲取當前目錄的一些方法

【內容來源地址】&#xff1a;http://www.cnblogs.com/marcozh/archive/2008/10/19/1314667.html Assembly myAssembly Assembly.GetEntryAssembly(); string path myAssembly.Location; DirectoryInfo dr new DirectoryInfo(path); pathd…

linux里的進程簡介

/sbin/init 內核啟動的第一個用戶級進程,引導用戶空間服務 [kthreadd] 內核線程管理[migration/0] 用于進程在不同的CPU間遷移[ksoftirqd/0] 內核調度/管理第0個CPU軟中斷的守護進程[migration/1] 管理多核心[ksoftirqd/1] 內核調度/管…

python畫畫bup_Python中的高效Vector / Point類

實現高效的Vector / Point類的最佳方法是什么(甚至更好&#xff1a;是否有一個),可以在Python 2.7和3.x中使用&#xff1f;我找到了the blender-mathutils,但它們似乎只支持Python 3.x.然后是this Vector class,使用numpy,但它只是一個3D矢量.使用具有靜態屬性(x和y)的像kivy’…

CSDN 編程挑戰——《coder的計算器》

coder的計算器 題目詳情: coder現在已經上初中&#xff0c;也會用計算器實現 ,-,*,/和冪運算^了&#xff0c;但他覺得市場那些計算器太繁瑣了&#xff0c;有很多他不認識的符號&#xff0c;所以他現在很想要能計算帶括號的 ,-,*,/和冪運算^的混合表達式就可以了&#xff0c;你…

OpenShift Express:部署Java EE應用程序(支持AS7)

在過去的幾年中&#xff0c;我越來越聽到有關“云”服務的信息。 最初&#xff0c;我并不是很想嘗試一下。 但是幾個月后&#xff08;一年&#xff1f;&#xff09;&#xff0c;我決定看看這是怎么回事。 我從事Java EE開發已經超過7年了&#xff0c;所以我決定看看將Java EE應…

07 總結ProgressDialog 異步任務

1,ProgressDialog> //使用對象 設置標題 progressDialog.setTitle("標題"); //設置圖標 progressDialog.setIcon(R.drawable.ic_launcher); //設置展示的內容 progressDialog.setMessage(&q…