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