Selenium封裝
在封裝過程中我儘量做到2點:多次出現的代碼儘量提取出來;結構清晰保證可閱讀性。下面是我規劃了一個相對明瞭的結構體系,可以幫助自己比較好的構建好整個封裝思路。
在這個封裝過程中會發現我們在元素查找僅到By,這是因爲爲了更好的解決由於頁面元素變化增加自動化維護成本的問題,我在下面的文章中會對頁面元素封裝思路中有具體的介紹。
我們在開始方法之前我們先做一個準備工作,我們需要測試的相關瀏覽器包含哪些,我這裏先選擇了四種:chrome,opera,gecko,ie。那麼我們針對四個瀏覽器準備一下驅動文件:在目錄:StudySelenium\res 下放入相關的驅動文件。之後我們做一下準備工作:
1.將驅動的先關路徑及驅動名保存在properties
BrowserCoreType=1
# Drivers
ChromeDriver =webdriver.chrome.driver
OperaDriver=webdriver.opera.driver
GeckoDriver=webdriver.gecko.driver
IEDriver =webdriver.ie.driver
# Drivers' path
ChromeDriverPath =res/chromedriver.exe
OperaDriverPath=res/operadriver.exe
GeckoDriverPath=res/geckodriver.exe
IEDriverPath = res/IEDriverServer.exe
# UI actions' interval in millisecond
StepInterval = 500
# UI actions' timeout in millisecond
Timeout = 30000
# UI actions' timepass in millisecond
TimePass = 1000
並在 GlobalSettings.java 中進行一個調用
/**
* SeleniumKing webdriver
*/
public static String chromeDriver = prop.getProperty("ChromeDriver");
public static String ieDriver = prop.getProperty("IEDriver");
public static String operaDriver = prop.getProperty("OperaDriver");
public static String geckoDriver = prop.getProperty("GeckoDriver");
public static String chromeDriverPath = prop.getProperty("ChromeDriverPath");
public static String ieDriverPath = prop.getProperty("IEDriverPath");
public static String operaDriverPath = prop.getProperty("OperaDriverPath");
public static String geckoDriverPath = prop.getProperty("GeckoDriverPath");
public static int browserCoreType = Integer.parseInt(prop.getProperty("BrowserCoreType"));
public static String stepInterval = prop.getProperty("StepInterval");
public static String timeout = prop.getProperty("Timeout");
public static String timePass = prop.getProperty("TimePass");
public static String baseStorageUrl = prop.getProperty("baseStorageUrl", System.getProperty("user.dir"));
2.在SeleniumKing.java中將準備工作做好
public WebDriver driver;
private Logger logger = Logger.getLogger(SeleniumKing.class.getName());
public SeleniumKing() {
Properties props = System.getProperties(); // 獲得系統屬性集
String currentPlatform = props.getProperty("os.name"); // 操作系統名稱 logger.info("當前操作系統是:[" + currentPlatform + "]");
if (currentPlatform.toLowerCase().contains("win")) {
//如果是windows平臺
switch (GlobalSettings.browserCoreType) {
//1:chrome
case 1:
System.setProperty(GlobalSettings.chromeDriver, GlobalSettings.chromeDriverPath); ChromeOptions option = new ChromeOptions(); option.addArguments("disable-infobars");
driver = new ChromeDriver(option); driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS); logger.info("啓動測試瀏覽器:[" + GlobalSettings.chromeDriver + "]");
break;
//2:opera
case 2:
System.setProperty(GlobalSettings.operaDriver, GlobalSettings.operaDriverPath); driver = new OperaDriver();
logger.info("啓動測試瀏覽器:[" + GlobalSettings.operaDriver + "]");
break;
//3:firefox
case 3:
System.setProperty(GlobalSettings.geckoDriver, GlobalSettings.geckoDriverPath); driver = new FirefoxDriver();
logger.info("啓動測試瀏覽器:[" + GlobalSettings.geckoDriver + "]");
break;
//4:ie
case 4:
System.setProperty(GlobalSettings.ieDriver, GlobalSettings.ieDriverPath); driver = new InternetExplorerDriver();
logger.info("啓動測試瀏覽器:[" + GlobalSettings.ieDriver + "]");
break; }
driver.manage().deleteAllCookies();
}else if (currentPlatform.toLowerCase().contains("linux")) {
//如果是linux平臺
logger.error("暫不支持當前操作系統:[" + currentPlatform + "]");
Assert.fail("暫不支持當前操作系統:[" + currentPlatform + "]");
} else if (currentPlatform.toLowerCase().contains("mac")) {
//如果是mac平臺
logger.error("暫不支持當前操作系統:[" + currentPlatform + "]");
Assert.fail("暫不支持當前操作系統:[" + currentPlatform + "]"); }
else{
logger.error("暫不支持當前操作系統:[" + currentPlatform + "]");
Assert.fail("暫不支持當前操作系統:[" + currentPlatform + "]"); } }
這裏需要說明的兩點:1,是爲了以後我們能兼容更多的平臺,我們做了個平臺的判斷;2.我們需要做個info等級的記錄。說道記錄我們還需要做一個準備工作就是截圖功能,能夠在出現異常的時候進行一個異常記錄。
private String screenShot() {
String dir = "target/screenshot"; // TODO
String time = new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date()); String screenShotPath = dir + File.separator + time + ".png";
try {
File sourceFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE); FileUtils.copyFile(sourceFile, new File(screenShotPath));
} catch (Exception e) {
e.printStackTrace();
return "Failed to screenshot";
}
return screenShotPath.replace("\\", "/");
}
這個截圖功能我們是返回了一個截圖信息,在不同的使用情況下我們可以做不同的處理。
之後我們需要進行整理的就是操作類,輔助類,斷言類。這裏操作類主要是對一些控件或者必要元素的操作比如:點擊,輸入還有就是常用到的frame的操作;輔助類主要是來獲取元素及控件的相關屬性比如:文本內容,勾選狀態等;斷言類主要是對預期以及實際效果的一個對比比如:文本一致,文本包含,大小對比。
會發現在進行操作前我們是需要獲取到WebElement對象前面也有提到過這裏我們選擇將元素封裝成BY 來進行查找,主要是爲了保障我們在UI元素在新的版本中發生的情況下,儘可能的減少我們的一個維護工作量,其實在以前我使用的是將元素的某一個元素屬性已String的形式保存下來,之後在用例中通過不同的方法進行一個獲取及操作。但是在實際的項目中發現這樣的封裝效果其實很差。其實在UI改版的過程中好多屬性都會失效,導致我們需要其它屬性進行一個定位。還是需要在case級別進行一個修改。那麼現在我們只需要將這個元素獲取的方式進行封裝,那麼只要這個入口控件是存在的我們都只需要進行一處的修改就可以了。同時在定位過程中我們發現元素定位是一個比較快的過程,但是元素在加載過程中可能比較慢,導致我們在發起定位時元素還沒有加載出來,導致用例執行失敗,穩定性極差。那麼我們需要做一個延時查找到動作,在一定時間範圍內,我們每隔一定時間進行一個查找,如果查到了我們進行返回,如果沒有查到我們就在等一段時間後再次進行查找。如果超出規定時間還是沒有找打元素,我們直接報錯並記錄日誌及先關截圖工作供以後複查的一個參考。下面是相關代碼:
private WebElement findElement(By by){
final long endTime = System.currentTimeMillis()+timeout;
WebElement element = null;
while (true) {
try { element =driver.findElement(by);
if (element.isDisplayed()) {
break; }
} catch (Exception e) {
if (System.currentTimeMillis() < endTime) {
try { Thread.sleep(500);
} catch (InterruptedException e1) { e1.printStackTrace();
}
} else {
handleFailure("相關元素未找到"+by);
break; } } }
try { Thread.sleep(timePass);
} catch (InterruptedException e) {
e.printStackTrace(); }
return element;
}
這裏我們需要對未找到元素的截圖做一個簡單的封裝,也可以在之後操作異常中能夠使用,我們在調用過程中需要給到一個截圖原因方便我們對代碼的維護。
private void handleFailure(String notice) {
String png = LogTools.screenShot(this);
String log = "【"+notice + "】捕捉屏幕截圖>> " + png;
logger.error(log);
Assert.fail(log); }
下面是整體需要進行實現的一些方法:
由於代碼量比較多,我進做幾個舉例:
/** * 打開瀏覽器 * @param url 瀏覽器地址 */
public void openUrl(String url) {
driver.get(url);
logger.info("打開地址【"+url+"】"); }
/** * 退出瀏覽器 */
public void quit() {
driver.quit();
logger.info("退出瀏覽器"); }
/** * 點擊 *@param by 界面元素 */
public void click(By by) {
WebElement webElement =findElement(by);
webElement.click();
logger.info("點擊;【"+by+"】"); }
/** * 獲得頁面的標題 * */
public String getTitle() {
return driver.getTitle(); }
/** * 獲得元素的文本 * */
public String getText(By elementLocator) {
return driver.findElement(elementLocator).getText(); }
/** * 包含斷言 * @param text1 包含 * @param text2 被包含 */
public void assertStringContain(String text1,String text2){
if (text1.contains(text2)) {
logger.info("包含斷言成功 : 【"+text1+"】"+" 包含 【"+text2+"】");
Assert.assertTrue(true); } else {
handleFailure("包含斷言失敗 : 【"+text1+"】"+" 不包含 【"+text2+"】"); } }
到這裏我們的SeleniumKing類基本上就封裝完了,在以後的工作中我們可以跟具不同的項目需要進行添加或者修改。