我們繼續回到自動化測試框架的主線上來,在前面的文章中,我們定義一個頁面元素的主要參數有:路徑,找尋方式,等待時間,名稱,這個四個參數。另外,我們還需要考慮一個問題,就是網站的頁面。
舉個例子來說,如果A頁面上有“新增”,“選擇”,“保存”等按鈕,B頁面上也有“新增”,“選擇”,“保存”等按鈕,我們應該如何處理這種情況呢?
當然,有的小伙伴可能會說,我就直接命名為“新增A”,“選擇A”,“保存A”,“新增B”,“選擇B”,“保存B”就是了。這樣當然是可以的。
但是,在維護自動化腳本的時候,你就會發現最終完成測試用例的時候,元素非常多,查找不方便。而且直接在名字里增加說明的方法,只會讓名字越來越長。數據的結構也非常混亂。
如果能夠在元素的上一層我們增加一級,加入一個叫做pageName的參數,把一個頁面中操作的元素集中起來管理。這樣對元素的定義就會方面很多,也不怕名字重復的存在。
最重要的是,我們平時的語言習慣也是這么說的:“在登錄頁面上輸入用戶名為XXX,密碼是XXX”。
那么,我們以什么方式來提供給程序,然后讓程序能夠處理這些元素呢?
方式有很多,我們可以把參數變成xml節點的屬性,通過xml文件來讀取。我們也可以把元素參數寫成Excel,通過Excel來讀取。甚至,我們可以把這些參數存入MySQL數據庫中,通過數據庫來讀取。
對於這些讀取元素的方法,我們就逐步來實現。在實際運用中,選擇最合適自己的那個。
下面我們先從XML開始。
首先,讓我們來設計一下我們存儲元素用的XML文件。新建一個XML文件,eclipse里面在監理XML文件的時候,會自動加上一句<?xml version="1.0" encoding="UTF-8"?>,這個是通用基准,知道就好。
其次,我們需要來設計一個WebUI測試用元素的結構。比如:我們當前需要測試的系統是“文檔管理系統”,有若干頁面,每個頁面上有若干元素。那么,我們可以設計我們的XML是如下的結構。
<?xml version="1.0" encoding="UTF-8"?> <map><!-- 文檔管理系統元素 --> <page pageName="loginPage"><!-- 登錄頁面 --> <!--position lists --> <position type="id" timeOut="3" value="UserId">用戶名輸入框</position> <position type="id" timeOut="3" value="Password">密碼輸入框</position> <position type="xpath" timeOut="3" value="//button[text()='登錄']">登錄按鈕</position> <position type="id" timeOut="3" value="errorDiv">錯誤提示</position> </page> <page pageName="mainPage"><!-- 主頁面 --> <!--position lists --> <position type="xpath" timeOut="8" value="//*[@id='left']/ul[1]/li[3]">文檔登記</position> <position type="xpath" timeOut="10" value="//*[@id='left']/ul[1]/li[4]">文檔查詢</position> <position type="xpath" timeOut="30" value="//*[@id='left']/ul[2]/li[4]">會議資料</position> </page> <page pageName="docQueryPage"><!-- 查詢頁面 --> <position type="" timeOut="5" value="fra1d34c791-9a30-4438-a2e0-a282f3be0594">iframe1</position> <position type="xpath" timeOut="3" value="//*[@id='newnav']/tbody/tr[1]/td/a">科研資料平台</position> </page> </map>
那么,可以看到。我們在這里就是用XML文件來構建了我們元素存儲的方式。這里,需要說明2個問題。
1.關於timeOut的設置,timeOut在這里的定義是指定等待的時間。因為我們前面在寫頁面元素操作實現類UIExcutorImpl的時候,查找元素的代碼如下:
try { wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(By.xpath(path))); ele = driver.findElement(By.xpath(path)); }catch (Exception e) { logs.error("findElment ByXpath:" + path + "-failed! NoSuchElement"); Reporter.log("findElment ByXpath:" + path + "-failed! NoSuchElement"); }
這里,我們使用智能等待的方式,即:等待所有滿足該查找條件(xpath)的元素出現,這樣一種方式。我們期待程序自己能夠查找,比我們自己指定時間要好的多。
當然,我們也沒有把路堵死。在XML文件中,我們依然可以寫入timeOut,即等待時間。只是,這個等待時間,並沒有為我們的頁面操作實現類所調用,因此,這個timeOut在這里設置可以說是無效的。
然而,如果某個元素,或者某個頁面加載的時間實在太長。使得整體的程序失去響應,必須要強制等待元素出現的情況下。這種情況,我們需要重新再寫我們的實現類,這時候我們可以在這里使用這個timeOut的值。
因此,從數據准備的角度來說,我建議這里保留這個timeOut,因為這也算是測試人員准備數據的成果。
2.關於記錄iframe的情況
當我們的測試頁面需要制定iframe的時候,即切換至另一塊區域的情況下。我們需要把iframe的code(iframe的code一般不具備可讀性),作為頁面元素給記錄下來,便於使用。
雖然具體在網頁上,它並沒有一個具體位置,但是,我們依然可以把它作為頁面元素來處理。只是處理調用的方法和普通的頁面元素不一樣而已。
關於使用Java來讀取xml文件,首先我們還是要導入一個JAR包:dom4j-1.6.1.jar。下載地址:https://mvnrepository.com/artifact/dom4j/dom4j
接下來,我們開始寫一個讀取XML的類。
這個類的思路是:讀取一個xml文件,按照pageName進行查找,並遍歷該pageName節點下的節點,讀取節點屬性和名稱,按照頁面元素構造函數的形式,存入HashMap集合並返回。
package webui.xUtils; import java.io.File; import java.util.HashMap; import java.util.Iterator; import org.dom4j.Attribute; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; import org.testng.Reporter; import webui.xUtils.Position.ByType; public class XmlReadUtil { /**讀取頁面配置文件 * @param xmlUrl * * 頁面配置文件路徑 * * @param pageName * 頁面名稱 */ static logUtil logs = new logUtil(XmlReadUtil.class); public static HashMap<String, Position> readXMLDocument(String xmlUrl, String pageName) throws Exception {
//創建一個哈希Map,里面的鍵值對為(名字,元素) HashMap<String, Position> positionMap = new HashMap<>();
//判斷XML文件是否存在 File file = new File(xmlUrl); if (!file.exists()) { logs.error("can't find " + xmlUrl); Reporter.log("can't find " + xmlUrl);} else { // 創建SAXReader對象 SAXReader sr = new SAXReader(); // 讀取xml文件轉換為Document Document document = sr.read(file); // 獲取所有根節點元素對象 Element root = document.getRootElement(); Iterator<?> rootIte = root.elementIterator(); Position position = null; // 遍歷根節點 while (rootIte.hasNext()) { Element page = (Element) rootIte.next(); // 節點屬性,忽略大小寫比較 if (page.attribute(0).getValue().equalsIgnoreCase(pageName)) { Iterator<?> pageIte = page.elementIterator(); // 找到pageName后遍歷該page內各個節點 while (pageIte.hasNext()) { String type = ""; String timeOut = ""; String value = ""; String positionName = ""; Element ele = (Element) pageIte.next(); positionName = ele.getText(); Iterator<?> positionIte = ele.attributeIterator(); // 遍歷單個標簽內的元素 while (positionIte.hasNext()) { Attribute attribute = (Attribute) positionIte.next(); String attributeName = attribute.getName(); if (attributeName.equals("type")) { type = attribute.getValue(); } else if(attributeName.equals("value")){ value = attribute.getValue(); }else { timeOut = attribute.getValue(); } }
//封裝頁面元素 position = new Position(value,Integer.parseInt(timeOut),getType(type),positionName.trim());
//將頁面元素加入哈希Map的集合 positionMap.put(positionName.trim(), position); } break; } } } return positionMap; } //從讀取的type屬性的值,來定義尋找元素的方法 private static ByType getType(String type) { ByType byType = ByType.xpath; if (type == null || type.equalsIgnoreCase("xpath")) { byType = ByType.xpath; } else if (type.equalsIgnoreCase("id")) { byType = ByType.id; } else if (type.equalsIgnoreCase("linkText")) { byType = ByType.linkText; } else if (type.equalsIgnoreCase("name")) { byType = ByType.name; } else if (type.equalsIgnoreCase("className")) { byType = ByType.className; } else if (type.equalsIgnoreCase("cssSelector")) { byType = ByType.cssSelector; } else if (type.equalsIgnoreCase("partialLinkText")) { byType = ByType.partialLinkText; } else if (type.equalsIgnoreCase("tagName")) { byType = ByType.tagName; } return byType; } }
這樣,這個讀取XML文件的類就完成了。接下來我們可以使用這個類來作成一個基礎頁面類。