Selenium自動化測試用例設計注意事項(一)
自動化測試設計簡介
我們在本章提供的信息,對自動化測試領域的新人和經驗豐富的老手都是有用的。本篇中描述最常見的自動化測試類型, 還描述了可以增強您的自動化測試套件可維護性和擴展性的“設計模式”。還沒有使用這些技術的、有經驗的自動化測試工程師會對這些技術更加感興趣。
測試類型
您應該測試應用程序中的哪些部分?這取決于您的項目的各種影響因素:用戶的期望,時間期限,項目經理設置的優先事項等等。但是,一旦項目邊界定義完成,作為測試工程師,你必須做出要測試什么的決定。
為了對Web應用的測試類型進行分類,我們在這里創建了一些術語。這些術語并不意味著標準,但是這些概念對web應用測試來說非常典型。
● 測試靜態內容
靜態內容測試是最簡單的測試,用于驗證靜態的、不變化的UI元素的存在性。例如:
→ 每個頁面都有其預期的頁面標題?這可以用來驗證鏈接指向一個預期的頁面。
→ 應用程序的主頁包含一個應該在頁面頂部的圖片嗎?
→ 網站的每一個頁面是否都包含一個頁腳區域來顯示公司的聯系方式,隱私政策,以及商標信息?
→ 每一頁的標題文本都使用的<h1>標簽嗎?每個頁面有正確的頭部文本內嗎?
您可能需要或也可能不需要對頁面內容進行自動化測試。如果您的網頁內容是不易受到影響手工對內容進行測試就足夠了。如果,例如您的應用文件的位置被移動,內容測試就非常有價值。
● 測試鏈接
Web站點的一個常見錯誤為的失效的鏈接或鏈接指向無效頁。鏈接測試涉及點各個鏈接和驗證預期的頁面是否存在。如果靜態鏈接不經常更改,手動測試就足夠。但是,如果你的網頁設計師經常改變鏈接,或者文件不時被重定向,鏈接測試應該實現自動化。
● 功能測試
在您的應用程序中,需要測試應用的特定功能,需要一些類型的用戶輸入,并返回某種類型的結果。通常一個功能測試將涉及多個頁面,一個基于表單的輸入頁面,其中包含若干輸入字段、提交“和”取消“操作,以及一個或多個響應頁面。用戶輸入可以通過文本輸入域,復選框,下拉列表,或任何其他的瀏覽器所支持的輸入。
功能測試通常是需要自動化測試的最復雜的測試類型,但也通常是最重要的。典型的測試是登錄,注冊網站賬戶,用戶帳戶操作,帳戶設置變化,復雜的數據檢索操作等等。功能測試通常對應著您的應用程序的描述應用特性或設計的使用場景。
● 測試動態元素
通常一個網頁元素都有一個唯一的標識符,用于唯一地定位該網頁中的元素。通常情況下,唯一標識符用HTML標記的’id’屬性或’name’屬性來實現。這些標識符可以是一個靜態的,即不變的、字符串常量。它們也可以是動態生產值,在每個頁面實例上都是變化的。例如,有些Web服務器可能在一個頁面實例上命名所顯示的文件為doc3861,并在其他頁面實力上顯示為doc6148,這取決于用戶在檢索的‘文檔’。驗證文件是否存在的測試腳本,可能無法找到不變的識別碼來定位該文件。通常情況下,具有變化的標識符的動態元素存在于基于用戶操作的結果頁面上,然而,顯然這取決于Web應用程序。
下面是一個例子。
<input id="addForm:_ID74:_ID75:0:_ID79:0: checkBox" type="checkbox" value="true" /> |
這是一個HTML標記的復選框,
其ID (addForm:_ID74:_ID75:0:_ID79:0:checkBox) 是一個動態生成的值。這個頁面下次被打開時,復選框的ID將可能是一個不同的值。
● Ajax的測試
Ajax是一種支持動態改變用戶界面元素的技術。頁面元素可以動態更改,但不需要瀏覽器重新載入頁面,如動畫,RSS源,其他實時數據更新等等。Ajax有不計其數的更新網頁上的元素的方法。但是了解AJAX的最簡單的方式,可以這樣想,在Ajax驅動的應用程序中,數據可以從應用服務器檢索,然后顯示在頁面上,而不需重新加載整個頁面。只有一小部分的頁面,或者只有元素本身被重新加載。
驗證結果
● 斷言assert與驗證verify
什么時候使用斷言命令,什么時候使用驗證命令?這取決于你。差別在于在檢查失敗時,你想讓測試程序做什么。你想讓測試終止,還是想繼續而只簡單地記錄檢查失敗?
這需要權衡。如果您使用的斷言,測試將在檢查失敗時停止,并不運行任何后續的檢查。有時候,也許是經常的,這是你想要的。如果測試失敗,你會立刻知道測試沒有通過。TestNG和JUnit等測試引擎提供在開發測試腳本時常用的插件,可以方便地標記那些測試為失敗的測試。優點:你可以直截了當地看到檢查是否通過。缺點:當檢查失敗,后續的檢查不會被執行,無法收集那些檢查的結果狀態。
相比之下,驗證命令將不會終止測試。如果您的測試只使用驗證,可以得到保證是—假設沒有意外的異常—測試會被執行完畢,而不管是否發現缺陷。缺點:你必須做更多的工作,以檢查您的測試結果。也就是說,你不會從TestNG和JUnit得到反饋。您將需要在打印輸出控制臺或日志文件中查看結果。每次運行測試,你都需要花時間去查看結果輸出。如果您運行的是數以百計的測試,每個都有它自己的日志,這將耗費時間。及時得到反饋會更合適,因此斷言通常比驗證更常使用。
● 權衡:assertTextPresent,assertElementPresent和assertText
您現在應該熟悉這些命令及使用它們的機制。如果沒有,請參閱相關章節。在構建你的測試時,你需要決定
→ 只檢查在頁面上的文本嗎?(verify/ assertTextPresent)
→ 只檢查是否在頁面上存在HTML元素嗎?即文本,圖像,或其他沒被檢查的內容,只要和HTML標記相關。(verify/ assertElementPresent)
→ 需要同時檢查元素和它的文本內容?(verify/ assertText)
沒有正確的答案。這取決于您的測試要求。如有疑問,請使用assertText,因為這是最嚴格的類型檢查點。您可以隨后更改它,但至少你不會遺漏任何潛在的故障。
Verify/ assertText是最特殊的測試類型。HTML元素(標簽)或文本的不符合都會導致測試失敗。也許你的網頁設計師經常改變頁面面,而你不希望在他們改變頁面時,你的測試失敗,因為這是期望中的周期性變更。但是,假如你仍然需要檢查的頁面上的東西,如段落、標題文本或圖像。在這種情況下,您可以使用verify/ assertElementPresent。這將確保一個特定類型的元素存在(如果使用XPath,可以確保它相對頁面內其他對象的存在)。但你不關心的內容是什么,你只關心某個特定的元素,比方說,一個圖片在一個特定的位置。
隨著時間的推移和經驗的積累,如何決定使用還是非常簡單的。
定位元素的策略
● 選擇一個定位策略
有多種方式選擇頁面上的對象。但面對這些定位類型,如何權衡呢?回想一下,我們定位一個對象的方式:
→ 元素的ID
→ 元素的name屬性
→ XPath語句
→ 通過一個鏈接的文本
→ 文檔對象模型(DOM)
使用元素的ID或name定位符,在測試執行方面來說,是最有效的方式。也讓你的測試代碼更具可讀性,如果在頁面源代碼中的ID或name屬性被友好命名的話。XPath語句需要更長的時間來處理,因為瀏覽器必須運行它的XPath處理器。在Internet Explorer 7,XPath出了名的慢。
使用鏈接的文本進行定位是很方便的,并運行起來也不錯。這種技術只適用于鏈接。另外,如果鏈接文本很可能會經常改變,使用<a>標簽定位元素將是更好的選擇。
不過,有時你必須使用XPath定位。如果一個頁面元素沒有一個ID或者name屬性,除了XPath定位沒得選擇。(DOM定位器不再普遍使用,因為,XPath可以做得更好。DOM定位器只簡單地為遺留測試而存在)。
相對使用ID或name屬性定位,使用XPath進行定位有一個獨特的優勢。使用XPath(DOM)中,你可以找到頁面上相對于其他對象的一個對象。例如,如果有一個鏈接必須存在<div>標簽里的第二個段落內,您可以使用XPath進行定位。使用ID和name屬性定位,你只能得出它們存在指定的頁面,而不知具體的頁面位置。如果你必須測試顯示公司標志的圖像出現在頁面頂部的頭部分,XPath定位可能是更好的選擇。
● 定位動態元素
正如前面測試類型部分所述,動態元素的頁面標識在不同的頁面實例上市不同的。例如,
<a class="button" id="adminHomeForm" onclick="return oamSubmitForm('adminHomeForm', 'adminHomeForm:_ID38');" href="#">View Archived Allocation Events</a> |
這個HTML錨標記定義了一個ID屬性為“adminHomeForm”按鈕。和大部分HTML標簽相比,這是一個相當復雜的錨標記,但它仍然是一個靜態標簽。每次頁面被瀏覽器加載時,HTML將保持不變。它的ID在所有的頁面實例里保持不變,也就是說,頁面被展示時,這個UI元素總是有同樣的標識符。所以,點擊此按鈕的測試腳本(Selenium Server)如下所示:
selenium.click("adminHomeForm"); |
然而,你的應用程序,可能生成動態的HTML標識符。在不同的網頁實例中,標識符發生改變。例如,一個動態的頁面的HTML元素可能會是這個樣子:
<input id="addForm:_ID74:_ID75:0:_ID79:0:checkBox" type="checkbox" name="addForm:_ID74:_ID75:0:_ID79:0:checkBox" value="true" /> |
這是一個復選框,id和name屬性都是addForm:_ID74:_ID75:0:_ID79:0:checkBox。在這種情況下,使用標準的定位,測試腳本應該是這樣子的:
selenium.click("addForm:_ID74:_ID75:0:_ID79:0:checkBox"); |
對于動態生成的標識符,這種做法行不通。下一次頁面加載時,標識符將是一個不同的值,執行上述腳本會遇到“element not found”錯誤。
要更正該問題,一個簡單的解決辦法是使用XPath定位替代ID定位器。因此,對于該復選框,可以簡單地使用
selenium.click("http://input"); |
或者,如果它不是在頁面上的第一個文本輸入域,嘗試一個更詳細的XPath語句。
selenium.click("http://input[3]"); |
或
selenium.click("http://div/p[2]/input[3]"); |
但是,如果你確實需要使用ID來定位元素,可以換一種不同的解決方案。您可以先捕捉到網站的這個ID,然后再使用它,例如:
String[] checkboxids = selenium.getAllFields(); // Collect all input IDs on page. for(String checkboxid:checkboxids) { if(checkboxid.contains("addForm")) { selenium.click(expectedText); } } |
如果頁面上只有一個復選框的ID文本為“expectedText”時,這種方法工作。
● 定位Ajax元素
定位、驗證AJAX元素的最好的方式是使用Selenium 2.0 webdriver的API,它專門解決Selenium 1.0測試AJAX元素的一些限制。
在Selenim 2.0中,可以使用waitfor()方法來等待一個頁面元素變得可用。該參數是一個WebDriver用來實現定位的By對象。這是WebDriver的章節中詳細解釋。
在Selenium 1.0(Selenium-RC的)中,要做到這一點需要編寫更多的編碼,但它并不難。首先檢查元素,如果它存在,等待預定義的時間段,然后再重新檢查。這在循環內執行,如果超過一個預定的超時,元素不存在則終止循環。
讓我們考慮頁面上實現AJAX效果的一個鏈接(鏈接= ajaxLink),可以使用循環處理:
// Loop initialization. for (int second = 0;; second++) { // If loop is reached 60 seconds then break the loop. if (second >= 60) break; // Search for element "link=ajaxLink" and if available then break loop. try { if (selenium.isElementPresent("link=ajaxLink")) break; } catch (Exception e) {} // Pause for 1 second. Thread.sleep(1000); } |
這當然不是唯一的解決辦法。Ajax是一個共同的話題,在用戶論壇上,查找一下之前的討論,看看別人是如何做的。
封裝Selenium調用
與任何編程一樣,你需要使用工具函數來處理在測試代碼中重復的函數。避免重復的方法之一是封裝常用的Selenium方法的調用。例如,測試時經常點擊頁面上的元素,等待頁面加載。
selenium.click(elementLocator); selenium.waitForPageToLoad(waitPeriod); |
為了不重復上述代碼,你可以寫一個包裝方法實現這兩個功能。
/** * Clicks and Waits for page to load. * * param elementLocator * param waitPeriod */ public void clickAndWait(String elementLocator, String waitPeriod) { selenium.click(elementLocator); selenium.waitForPageToLoad(waitPeriod); } |
● 判斷元素存在的“安全操作”
另一種常見的封裝Selenium的方法,在執行進一步操作前檢查頁面上的元素存在性。這有時被稱為“安全操作”。例如,下面的方法可用于實現一個依賴期望的元素存在的安全操作。
/** * Selenum-RC -- Clicks on element only if it is available on page. * * param elementLocator */ public void safeClick(String elementLocator) { if(selenium.isElementPresent(elementLocator)) { selenium.click(elementLocator); } else { // Using the TestNG API for logging Reporter.log("Element: " +elementLocator+ ", is not available on page - " +selenium.getLocation()); } } |
上述例子使用的是Selenium 1.0 API,Selenium 2.0同樣支持安全操作。
/** * Selenium-WebDriver -- Clicks on element only if it is available on page. * * param elementLocator */ public void safeClick(String elementLocator) { WebElement webElement = getDriver().findElement(By.XXXX(elementLocator)); if(webElement != null) { selenium.click(elementLocator); } else { // Using the TestNG API for logging Reporter.log("Element: " +elementLocator+ ", is not available on page - " + getDriver().getUrl()); } } |
在第二個例子中,’XXXX’方法是一個占位符,可以用元素定位方法進行替換。
使用安全方法取決于測試開發人員的決定。因此,如果測試需要繼續執行,即使知道頁面上一些元素沒有發現,這時可以使用安全方法,并發送一條缺少元素的消息到日志文件。這基本上等于實現了帶報告機制的驗證,而不是一個失敗就終止執行的斷言。但是,如果元素必須在頁面上出現,以便能夠執行進一步的操作(如一個門戶網站主頁上的登錄按鈕),這時安全方法技術不應該被使用。
本文轉載自:http://www.loggingselenium.com/
posted on 2013-01-28 10:55 順其自然EVO 閱讀(6603) 評論(1) 編輯 收藏 所屬分類: selenium and watir webdrivers 自動化測試學習