Appium的Java封装
生活随笔
收集整理的這篇文章主要介紹了
Appium的Java封装
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
文章出處 http://blog.csdn.net/niubitianping/article/details/52612211
一、為什么需要封裝?
封裝的本意就是為了方便、簡潔。
二、Android的顯式等待封裝
1. AndroidDriverWait.java
package com.example.base;/** * Created by LITP on 2016/9/8. */ import org.openqa.selenium.NotFoundException; import org.openqa.selenium.TimeoutException; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebDriverException; import org.openqa.selenium.remote.RemoteWebDriver; import org.openqa.selenium.support.ui.Clock; import org.openqa.selenium.support.ui.FluentWait; import org.openqa.selenium.support.ui.Sleeper; import org.openqa.selenium.support.ui.SystemClock; import java.util.concurrent.TimeUnit; import io.appium.java_client.android.AndroidDriver; public class AndroidDriverWait extends FluentWait<AndroidDriver> { public final static long DEFAULT_SLEEP_TIMEOUT = 500; private final WebDriver driver; public AndroidDriverWait(AndroidDriver driver, long timeOutInSeconds) { this(driver, new SystemClock(), Sleeper.SYSTEM_SLEEPER, timeOutInSeconds, DEFAULT_SLEEP_TIMEOUT); } public AndroidDriverWait(AndroidDriver driver, long timeOutInSeconds, long sleepInMillis) { this(driver, new SystemClock(), Sleeper.SYSTEM_SLEEPER, timeOutInSeconds, sleepInMillis); } public AndroidDriverWait(AndroidDriver driver, Clock clock, Sleeper sleeper, long timeOutInSeconds, long sleepTimeOut) { super(driver, clock, sleeper); withTimeout(timeOutInSeconds, TimeUnit.SECONDS); pollingEvery(sleepTimeOut, TimeUnit.MILLISECONDS); ignoring(NotFoundException.class); this.driver = driver; } @Override protected RuntimeException timeoutException(String message, Throwable lastException) { TimeoutException ex = new TimeoutException(message, lastException); ex.addInfo(WebDriverException.DRIVER_INFO, driver.getClass().getName()); if (driver instanceof RemoteWebDriver) { RemoteWebDriver remote = (RemoteWebDriver) driver; if (remote.getSessionId() != null) { ex.addInfo(WebDriverException.SESSION_ID, remote.getSessionId().toString()); } if (remote.getCapabilities() != null) { ex.addInfo("Capabilities", remote.getCapabilities().toString()); } } throw ex; } } ?
2.ExpectedCondition.java
接口
package com.example.base;import com.google.common.base.Function;import io.appium.java_client.android.AndroidDriver;/*** Created by LITP on 2016/9/8.*/
public interface ExpectedCondition<T> extends Function<AndroidDriver, T> {} ?
3. 使用
/*** 顯示等待,等待Id對應(yīng)的控件出現(xiàn)time秒,一出現(xiàn)馬上返回,time秒不出現(xiàn)也返回*/public AndroidElement waitAuto(By by, int time) {try { return new AndroidDriverWait(driver, time) .until(new ExpectedCondition<AndroidElement>() { @Override public AndroidElement apply(AndroidDriver androidDriver) { return (AndroidElement) androidDriver.findElements(by); } }); } catch (TimeoutException e) { Assert.fail("查找元素超時!! " + time + " 秒之后還沒找到元素 [" + by.toString() + "]", e); return null; } } ?
三、Assert斷言的封裝
封裝了 出現(xiàn)錯誤輸出了異常信息但不終止程序的運行,會繼續(xù)往下執(zhí)行。
1.Assertion.java
package com.example.base;import org.testng.Assert;import java.util.ArrayList;
import java.util.List;/** * Created by LITP on 2016/9/21. */ public class Assertion { public static boolean flag = true; //是否有錯誤 public static List<Error> errors = new ArrayList<>(); //錯誤集合 /** * 驗證值是否相等 * @param actual 第一個值 * @param expected 要對比的值 */ public static void verifyEquals(Object actual, Object expected){ try{ Assert.assertEquals(actual, expected); }catch(Error e){ errors.add(e); flag = false; } } /** * 驗證值是否相等 * @param actual 第一個值 * @param expected 要對比的值 * @param message 出錯時候的提示消息 */ public static void verifyEquals(Object actual, Object expected, String message){ try{ Assert.assertEquals(actual, expected, message); }catch(Error e){ errors.add(e); flag = false; } } } ?
2.AssertionListener.java
package com.example.base;import org.testng.ITestResult;
import org.testng.TestListenerAdapter;import java.util.ArrayList;
import java.util.Arrays; import java.util.List; import static javafx.scene.input.KeyCode.T; /** * Created by LITP on 2016/9/21. */ public class AssertionListener extends TestListenerAdapter { /** * 測試方法開始的時候回調(diào) * @param result */ @Override public void onTestStart(ITestResult result) { Assertion.flag = true; Assertion.errors.clear(); } /** * 測試終止時候回調(diào) * @param tr */ @Override public void onTestFailure(ITestResult tr) { this.handleAssertion(tr); } /** * Test跳過 的時候執(zhí)行 * @param tr */ @Override public void onTestSkipped(ITestResult tr) { this.handleAssertion(tr); } /** * Test運行完畢時候執(zhí)行 * @param tr */ @Override public void onTestSuccess(ITestResult tr) { this.handleAssertion(tr); } private int index = 0; //錯誤行號 /** * 處理斷言,每個Test執(zhí)行完畢回調(diào) * @param tr 測試結(jié)果 */ private void handleAssertion(ITestResult tr){ if(!Assertion.flag){ //為假,就是斷言出錯了就執(zhí)行下面的 //獲取異常 Throwable throwable = tr.getThrowable(); if(throwable==null){ throwable = new Throwable(); } //獲取異常堆棧信息 StackTraceElement[] traces = throwable.getStackTrace(); //創(chuàng)建要輸出的所有堆棧信息 StackTraceElement[] alltrace = new StackTraceElement[0]; //循環(huán)獲取斷言的異常信息, for (Error e : Assertion.errors) { //獲取錯誤的堆棧數(shù)組信息 StackTraceElement[] errorTraces = e.getStackTrace(); // StackTraceElement[] et = getKeyStackTrace(tr, errorTraces); //設(shè)置異常信息堆棧內(nèi)容 StackTraceElement[] message = handleMess(e.getMessage(),tr); //行號初始化為0 index = 0; //堆棧信息合并 alltrace = merge(alltrace, message); alltrace = merge(alltrace, et); } //如果異常信息不為空 if(traces!=null){ traces = getKeyStackTrace(tr, traces); alltrace = merge(alltrace, traces); } //保存異常信息 throwable.setStackTrace(alltrace); tr.setThrowable(throwable); //清空 Assertion.flag = true; Assertion.errors.clear(); //輸出異常信息 tr.setStatus(ITestResult.FAILURE); } } /** * 獲取堆棧信息 * @param tr * @param stackTraceElements * @return */ private StackTraceElement[] getKeyStackTrace(ITestResult tr, StackTraceElement[] stackTraceElements){ List<StackTraceElement> ets = new ArrayList<>(); //循環(huán)獲取信息 for (StackTraceElement stackTraceElement : stackTraceElements) { //返回測試類的堆棧信息 if(stackTraceElement.getClassName().equals(tr.getTestClass().getName())){ ets.add(stackTraceElement); index = stackTraceElement.getLineNumber(); //錯誤行號 } } return ets.toArray(new StackTraceElement[ets.size()]); } /** * 合并兩個堆棧信息 * @param traces1 第一個 * @param traces2 * @return */ private StackTraceElement[] merge(StackTraceElement[] traces1, StackTraceElement[] traces2){ StackTraceElement[] result = Arrays.copyOf(traces1, traces1.length + traces2.length); System.arraycopy(traces2, 0, result, traces1.length, traces2.length); return result; } /** * 處理消息提示內(nèi)容 * @param mess 報錯信息 * @param tr 結(jié)果描述 * @return */ private StackTraceElement[] handleMess(String mess,ITestResult tr){ String message = "\n報錯信息: "+mess; String method = "\n報錯方法名:"+tr.getMethod().getMethodName(); String className = "\n報錯類:"+tr.getTestClass().getRealClass().getSimpleName(); return new StackTraceElement[]{ new StackTraceElement(message, //內(nèi)容 method, //方法名 className+"\n報錯行號", //文件名 index)}; } } ?
?
四、Appium java的封裝
1. Builder.java
構(gòu)建器,在每個用例上都可以很方便設(shè)置app的屬性
package com.example.base;/*** Created by LITP on 2016/9/7.*/
public class Builder { String deviceName = BaseAppium.deviceName; String platformVersion = BaseAppium.platformVersion; String path = System.getProperty("user.dir") + "/src/main/java/apps/"; String appPath = BaseAppium.appPath; String appPackage = BaseAppium.appPackage; String noReset = BaseAppium.noReset; String noSign = BaseAppium.noSign; String unicodeKeyboard = BaseAppium.unicodeKeyboard; String resetKeyboard = BaseAppium.resetKeyboard; String appActivity = BaseAppium.appActivity; public Builder setAppPath(String appPath) { this.appPath = path + appPath; return this; } public Builder setDeviceName(String deviceName) { this.deviceName = deviceName; return this; } public Builder setPlatformVersion(String platformVersion) { this.platformVersion = platformVersion; return this; } public Builder setApp(String appPath) { this.appPath = appPath; return this; } public Builder setAppPackage(String appPackage) { this.appPackage = appPackage; return this; } public Builder setNoReset(String noReset) { this.noReset = noReset; return this; } public Builder setNoSign(String noSign) { this.noSign = noSign; return this; } public Builder setUnicodeKeyboard(String unicodeKeyboard) { this.unicodeKeyboard = unicodeKeyboard; return this; } public Builder setResetKeyboard(String resetKeyboard) { this.resetKeyboard = resetKeyboard; return this; } public Builder setAppActivity(String appActivity) { this.appActivity = appActivity; return this; } public BaseAppium build() { return new BaseAppium(this); } } ?
?
2. BaseAppium.java
父類,里面封裝了一堆方法,只管用,傳id、name那些就行了。當(dāng)然這只是一部分,僅供參考,可以自己修改添加。這個封裝沒有利用po模式,僅供參考,接下來的文章繼續(xù)優(yōu)化封裝。
package com.example.base;import org.apache.http.util.TextUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.TimeoutException; import org.openqa.selenium.remote.DesiredCapabilities; import org.testng.Assert; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Listeners; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.util.List; import java.util.concurrent.TimeUnit; import io.appium.java_client.MultiTouchAction; import io.appium.java_client.TouchAction; import io.appium.java_client.android.AndroidDriver; import io.appium.java_client.android.AndroidElement; /** * Created by LITP on 2016/9/7. */ @Listeners({com.example.base.AssertionListener.class}) public class BaseAppium { //調(diào)試設(shè)備名字 public static String deviceName = "minote"; //調(diào)試設(shè)備系統(tǒng)版本 public static String platformVersion = "4.4.2"; //app路徑 public static String appPath = System.getProperty("user.dir") + "/src/main/java/apps/shouhu2.2.3.apk"; //包名 public static String appPackage = "com.minstone.mdoctor"; //是否需要重新安裝 public static String noReset = "True"; //是否不重新簽名 public static String noSign = "True"; //是否使用unicode輸入法,真是支持中文 public static String unicodeKeyboard = "True"; //是否禍福默認(rèn)呢輸入法 public static String resetKeyboard = "True"; //要啟動的Activity public static String appActivity = appPackage + ".activity.login.WelcomeActivity"; public AndroidDriver<AndroidElement> driver = null; //單個觸摸操作類 TouchAction touchAction; //多個觸摸操作時間 MultiTouchAction multiTouchAction; private static int WAIT_TIME = 10; //默認(rèn)的等待控件時間 private static int SWIPE_DEFAULT_PERCENT = 5; //默認(rèn)滑動比例 //構(gòu)造方法 public BaseAppium() { this(new Builder()); } public BaseAppium(Builder builder) { print("基類初始化!"); appActivity = builder.appActivity; appPackage = builder.appPackage; appPath = builder.appPath; deviceName = builder.deviceName; noReset = builder.noReset; noSign = builder.noSign; unicodeKeyboard = builder.unicodeKeyboard; resetKeyboard = builder.resetKeyboard; } /** * appium啟動參數(shù) * * @throws MalformedURLException */ @BeforeSuite public void beforeSuite() throws MalformedURLException { DesiredCapabilities capabilities = new DesiredCapabilities(); capabilities.setCapability("deviceName", deviceName); capabilities.setCapability("platformVersion", platformVersion); capabilities.setCapability("app", new File(appPath).getAbsolutePath()); capabilities.setCapability("appPackage", appPackage); //支持中文 capabilities.setCapability("unicodeKeyboard", unicodeKeyboard); //運行完畢之后,變回系統(tǒng)的輸入法 capabilities.setCapability("resetKeyboard", resetKeyboard); //不重復(fù)安裝 capabilities.setCapability("noReset", noReset); //不重新簽名 capabilities.setCapability("noSign", noSign); //打開的activity capabilities.setCapability("appActivity", appActivity); //啟動Driver driver = new AndroidDriver<>(new URL("http://127.0.0.1:4723/wd/hub"), capabilities); } @AfterTest public void afterTest() { //結(jié)束這次測試 driver.quit(); } public boolean isIdElementExist(String id) { return isIdElementExist(id, false); } /** * 根據(jù)id判斷當(dāng)前界面是否存在并顯示這個控件 * * @param id 要查找的id * @param isShow 是否判斷控件顯示 * @return 返回對應(yīng)的控件 */ public boolean isIdElementExist(String id, boolean isShow) { AndroidElement ae; try { if (driver != null) { ae = driver.findElementById(appPackage + ":id/" + id); if (isShow) { return ae.isDisplayed(); } else { return ae != null; } } else { print("driver為空"); } } catch (NoSuchElementException e) { print("找不到控件" + e.getMessage()); } return false; } /** * 選擇當(dāng)前界面的有這個文字的控件 * * @param name * @param hasShow 是否顯示 * @return */ public boolean isNameElementExist(String name, boolean hasShow) { try { AndroidElement ae = driver.findElement(By.name(name)); if (hasShow) { return ae.isDisplayed(); } else return ae != null; } catch (NoSuchElementException e) { return false; } } public boolean isNameElementExist(String name) { return isNameElementExist(name, false); } /** * 判斷控件時候存在 * * @param by By * @param timeout 等待的事件 * @return */ public boolean isElementExist(By by, int timeout) { try { waitAuto(by, timeout); return true; } catch (Exception e) { return false; } } /** * 根據(jù)id獲取當(dāng)前界面的一個控件 * * @param id 要查找的id * @return 返回對應(yīng)的控件 */ public AndroidElement findById(String id) { try { if (driver != null) { return driver.findElementById(appPackage + ":id/" + id); } else { print("driver為空"); } } catch (NoSuchElementException e) { print("找不到控件" + e.getMessage()); } return null; } /** * 選擇當(dāng)前界面的有這個文字的控件 * * @param name 內(nèi)容 * @return 找到的控件 */ public AndroidElement findByName(String name) { return driver.findElement(By.name(name)); } /** * 根據(jù)id獲取當(dāng)前界面的一個控件 * * @param name 要查找的控件的類名 * @return 返回對應(yīng)的控件 */ public AndroidElement findByClassName(String name) { try { if (driver != null) { return driver.findElementByClassName(name); } else { print("dricer為空"); } } catch (NoSuchElementException e) { print("找不到控件" + e.getMessage()); } return null; } /** * 打印字符 * * @param str 要打印的字符 */ public <T> void print(T str) { if (!TextUtils.isEmpty(String.valueOf(str))) { System.out.println(str); } else { System.out.println("輸出了空字符"); } } /** * Click點擊空格鍵 * * @param ae 要點擊的控件 * @return 返回是否點擊 */ public boolean clickView(AndroidElement ae) { return clickView(ae, ""); } /** * Click點擊控件 * * @param ae 控件 * @param str 控件的文字描述,供錯誤時候輸出 * @return 返回是否存在控件 */ public boolean clickView(AndroidElement ae, String str) { if (ae != null) { ae.click(); return true; } else { print(str + "為空,點擊錯誤"); }
轉(zhuǎn)載于:https://www.cnblogs.com/111testing/p/7823815.html
總結(jié)
以上是生活随笔為你收集整理的Appium的Java封装的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 201621123068 作业08-集合
- 下一篇: 好听的抖音名字女3个字