1. 程式人生 > 實用技巧 >【測試】安卓自動化測試程式碼片段Java

【測試】安卓自動化測試程式碼片段Java

【前言】

編寫安卓自動化測試程式碼,本文選擇的是夜神模擬器+Appium

【語言選擇】

Appium使用的是C/S架構方式,Client端可以支援的程式語言挺多的,本文選擇的是Java

【IDE選擇】

編寫Java程式碼,本文選擇的IDE是eclipse

【eclipse基礎配置】

使用Maven管理專案的依賴包

【依賴包】

在網站(https://mvnrepository.com/)中搜索需要安裝的依賴包的Maven程式碼放入pom.xml檔案中

【需要的依賴包】

1 java-client

2 testNG

啟動夜神模擬器中的駕考寶典app的配置:

// 1 建立配置物件
DesiredCapabilities desiredCapabilities = new
DesiredCapabilities(); // 2 新增配置-測試的裝置 desiredCapabilities.setCapability("deviceName", "127.0.0.1:62001"); // 2 新增配置-測試的平臺 desiredCapabilities.setCapability("platformName", "Android"); // 2 新增配置-測試的App desiredCapabilities.setCapability("appPackage", "com.handsgo.jiakao.android"); // 2 新增配置-測試App的啟動入口 desiredCapabilities.setCapability("appActivity", "com.handsgo.jiakao.android.splash.Login");
// 3 建立驅動(引數:Appium通訊地址 配置引數) androidDriver = new AndroidDriver<WebElement>(new URL("http://127.0.0.1:4723/wd/hub"), desiredCapabilities);

更改配置,解決輸入框不能輸入資料的問題

// 2 新增配置-更改自動化引擎來解決輸入框輸入不了資料的問題
desiredCapabilities.setCapability("automationName", "uiautomator2");

更改配置,不清除應用的資料啟動測試(預設和設定為true時為不清除)

desiredCapbilities.setCapability("noReset", "true");

元素等待

在自動化過程中,元素的出現受到網路環境,裝置效能等多種因素影響。因此元素載入的時間可能不一致,從而會導致元素無法定位超時報錯。

因此設定元素等待可以更加靈活的制定等待定位元素的時間,從而增強指令碼的健壯性,提高執行效率。

元素等待方式1:強制等待

固定的等待時間

Thread.sleep(8000);//等待8秒

元素等待方式2:隱式等待

針對全域性元素設定等待時間,如果沒有定位到UI元素,指令碼可以在全域性等待時間長度內進行反覆查詢定位,定位成功後會提前結束等待,繼續接下來的執行任務

androidDriver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);

元素等待方式3:顯示等待

針對某個元素設定等待時間

WebDriverWait webDriverWait = new WebDriverWait(androidDriver, 10);
WebElement webElement = webDriverWait.until(new ExpectedCondition<WebElement>() {
    @Override
    public WebElement apply(WebDriver arg0) {
        return  androidDriver.findElementById("com.handsgo.jiakao.android:id/btn_agree");
    }
});
webElement.click();    

定位UI元素的方式

定位方式1:ID定位

ID就是一個控制元件的唯一身份標識,由開發人員在專案中指定,如果有對應的resource-id,可以採取這種方式來實現定位操作。

注意:有可能app開發人員並不是很嚴謹,一個介面會出現多個相同的id,這種情況下預設定位到第一個有此id的元素。

測試用例程式碼示例:

androidDriver.findElementById("com.handsgo.jiakao.android:id/btn_agree").click();

如果有多個相同id的情況:

List<WebElement> listElements = androidDriver.findElementById("com.handsgo.jiakao.android:id/btn_agree");

listElements.get(2).click();

定位方式2:text定位

Appium 1.5之前的版本支援By.name方式,比如:

// 根據text屬性進行定位
androidDriver.findElementByname("上海");

Appium 1.5之後的版本不再支援By.name方式,需要使用UIAutonator原生自動化引擎,比如:

// 使用UIAutomator定位text屬性元素
androidDriver.findElementByAndroidUIAutomator("new UiSelector().text(\"上海\")");

【注意】如果該方式呼叫不出,檢查一下jre的版本是否在1.5以上,更改方式如下:

第一步:

第二步:

第三步:

定位方式3:className定位(棄用)

根據class屬性定位元素,一般在頁面中很多元素的class屬性一致,所以這種方式基本上不使用

定位方式4:xpath定位

Appium也可以支援xpath定位,在專案中此種方式能夠使用多場景,xpath定位在web自動化測試中可以使用在app自動化測試中也可以使用,xpath定位有兩種定位方式,一種是絕對位置定位另一種是相對位置定位,相對位置定位使用更加普遍,因為如果使用絕對位置定位UI元素有所改變的情況下,相關UI元素的xpath都需要相應進行改變。xpath相對路徑需要使用到class屬性和text屬性內容進行拼接:

androidDriver.findElementByXPath("//android.widget.TextView[@text='上海']").click();

定位方式5:accessibility id定位

在UIAutomatorViewer並沒有此屬性,對應是content-desc屬性 。

注意:很多UI元素沒有這個屬性

androidDriver.findElementByAccessibilityId("上海").click();

定位方式6:座標定位

選擇設定中關於手機-連續點選五次版本號-進入開發者選項-勾選指標位置

注意:座標定位受裝置螢幕尺寸/解析度/DPI影響,萬不得已不要使用此種方式定位元素

定位方式7:Toast元素的獲取

獲取要求:Java-client 5.0+、使用UIAutomator2自動化引擎、Android系統版本5.0+

獲取方法:

WebElement toastElement = androidDriver.findElementByXPath("//*[contains(@text, '使用者名稱與密碼')]");
System.out.print(toastElement.getText());

對UI元素的操作

UI元素操作1:點選操作

.click();//點選

UI元素操作2:輸入操作

.sendKeys("深圳");//輸入

UI元素操作3:滑動手勢

Java-clilent 5.0之前版本提供的滑動API

// Java-client 4.1.2
androidDriver.swipe(356, 594, 356, 794, 800);
// (起始點座標x, 起始點座標y, 終止點座標x, 終止點座標y, 滑動時間)

Java-client 5.0之後需要自定義實現(可採用之前版本的實現思路)

// Java-client 6.1.0
TouchAction touchAction = new TouchAction(androidDriver);

PointOption startPointOption = PointOption.point(356, 594);
PointOption endPointOption = PointOption.point(356, 794);
Duration duration = Duration.ofMillis(800);
WaitOptions waitOptions = WaitOptions.waitOptions(duration);

touchAction.press(startPointOption).waitAction(waitOptions).moveTo(endPointOption).release();
touchAction.perform();// 讓滑動生效

滑動的使用場景:下拉重新整理、手勢解鎖等

手勢解鎖需要滑動到多個點,程式碼上使用多個.moveTo()方法就行了:

touchAction.press(pointOption1).waitAction(waitOptions).moveTo(pointOption2).moveTo(pointOption3).moveTo(pointOption4).release();

UI元素操作4:多點觸控手勢

使用場景:地圖縮放

MultiTouchAction類可以模擬使用者多點觸控操作

主要包含有add()和perform()兩個方法

可以結合TouchAction模擬多根手指滑動效果

// 1 例項化MultiTouchAction物件
MultiTouchAction multiTouchAction = new MultiTouchAction(androidDriver);
// 2 例項化兩個TouchAction(因為需要兩根手指進行放大操作)
TouchAction touchAction1 = new TouchAction<>(androidDriver);
TouchAction touchAction2 = new TouchAction<>(androidDriver);
// 3 得到當前螢幕的高度和寬度
int x = androidDriver.manage().window().getSize().getWidth();
int y = androidDriver.manage().window().getSize().getHeight();
// 第一根手指的滑動
touchAction1.press(PointOption.point(x * 4 / 10, y * 4 / 10))
.waitAction(WaitOptions.waitOptions(Duration.ofMillis(1000)))
.moveTo(PointOption.point(x * 2 / 10, y * 2 / 10)).release(); // 第二根手指的滑動 touchAction2.press(PointOption.point(x * 6 / 10, y * 6 / 10))
.waitAction(WaitOptions.waitOptions(Duration.ofMillis(1000)))
.moveTo(PointOption.point(x * 8 / 10, y * 8 / 10)).release(); // 把兩根手指的動作新增到MultiTouchAction裡面 multiTouchAction.add(touchAction1).add(touchAction2); multiTouchAction.perform();

斷言

使用testNG整合斷言框架 ,選擇src/test/java中的.java檔案,右擊選擇“testNG”-->“Convert to TestNG”,如下圖所示

(如果右擊沒有TestNG選項,可以在eclipse中的MarketPlace中搜索TestNG線上安裝)

之後在專案中會自動生成一個testng.xml檔案,在剛剛選中的java檔案中會在一些方法前面有@Test標識,測試開始之前的初始化@BeforeTest標識,刻可以將之前放在main函式中的執行程式碼放置到beforeTest標識下的自定義setup方法中,然後把main函式去掉。使用@AfterTest標識的函式用來當測試用例執行完畢後銷燬測試驅動(呼叫測試驅動物件的quit方法)。此後執行方式使用"Run As"--"TestNG Test"。

斷言1:檢查當前展示的介面是否是測試用例預期的結果

先確定預期介面類的名字,終端執行

adb shell dumpsys activity | find "mFocusedActivity"

輸出的結果中,斜槓後面的一長串就是類名,例如下圖所示

在測試用例中:

String expected = "cn.mucang.android.mars.student.refactor.business.inquiry.activity.InquiryActivuty";
String actual = androidDriver.currentActivity();
Assert.assertEquals(actual, expected);

執行完之後會有一個測試報告自動生成。

Appium常用API

Appium常用API1:實現頁面跳轉(startActivity)

頁面跳轉,包括App內部頁面及App相互跳轉

// 開啟某一個activity,實現跳轉
// 首先我們需要建立activity物件,用activity構建方法初始化,引數為對應的包名和類名
Activity activity = new Activity("com.lemon.lemonban", "com.lemon.lemonban.LoginActivity");
androidDriver.startActivity(activity);

注意:如找不到startActivity方法,請確認你的eclipse java compiler是否設定的是JDK1.8

Appium常用API2:得到當前頁面的dom結構(getPageSource)

可以用於斷言當前頁面是否有某個元素,或者判斷當前頁面有沒有產生變化,比如上下滾動判斷是否已經到了底端或者頂端。

String pageSource = androidDrivr.getPageSource();
System.out.println(pageSource);

Appium常用API3:得到當前頁面的類名(currentActivity)

String currentActivityName = androidDrivr.currentActivity();
System.out.println(currentActivityName);

Appium常用API4:重置應用的資料(resetApp)

有些場景我們需要清除應用的資料,相當於第一次安裝時候的狀態,比如:第一次啟動app的引導頁,登入等

androidDriver.resetApp();

Appium常用API5:判斷App是否安裝(isAppInstalled)

androidDriver.isAppInstalled("應用程式的包名");

Appium常用API6:向系統傳送鍵值事件(pressKey)

Android平臺獨有,向系統傳送鍵值事件,不同的鍵值對應不同的功能,如keyevent(4)表示手機的HOME按鍵

// 1 建立keyEvent物件
KeyEvent keyEvent = new keyEvent();
// 2 使用withKey傳入鍵值
keyEvent.withKey(AndroidKey.VOLUME_UP);
// 3 使用pressKey傳送鍵值
androidDriver.pressKey(keyEvent);

Appium常用API7:截圖功能

使用場景:當測試用例執行失敗之後螢幕截圖,儲存到本地為了更好的查詢問題

File file = androidDriver.getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(file, new File("D:\\AppAuto\\test.png"));

Appium常用API8:獲取裝置時間資訊(getDeviceTime)

返回String型別

Appium常用API9:獲取裝置DPI(getDisplayDensity)

返回String型別,注意不是解析度

Appium常用API10:獲取automation name(getAutomationName)

預設為null,如果有指定automation name為uiautomator2就為對應的值

Appium常用API11:獲取裝置橫豎屏狀態(getOrientation)

有豎屏(PORTRAIT)和橫屏(LANDSCAPE)

【root狀態的Hybrid應用自動化測試介紹】

Appium提供的解決方案:基於UIAutomator+ChromeDriver

準備工作:

1 準備Android 4.4+的手機或者模擬器

2 在app原始碼中將webview除錯模式開啟webview.setWebContentsDebuggingEnabled(true)

如果是第三方線上app,一般webview debug開關都是關閉的,這就需要藉助第三方工具,才能將debug開關開啟

解決方案:(Root狀態 )

Xposed.apk+WebviewDebugHook.apk裝入模擬器或者是手機上

Xposed是一個框架,能夠整合很多功能模組,這些模組能夠在不修改APK的情況下,修改APP的執行方式。

安裝好Xposed開啟顯示沒有啟用,需要在official選單中選擇安裝,安裝前需要選擇適應的框架,如果是模擬器一般是x86框架,如果是真機需要選擇arm框架。

需要WebviewDebugHook模組來開啟APP的WebView debug模式 。

安裝並激活好Xposed之後將WebviewDebugHook.apk放入模擬器或者手機,注意此時不會提示安裝成功,需要在Xposed中找到“模組”選單,找到WebviewDebugHook並勾選上,然後重啟裝置就會生效。

3 在電腦上安裝UC開發者工具(uc-devtools.msi,設定成“本地Devtools Inspector UI資源”)

UC-Dectools工具的使用需要上面兩步配置的支援才能使用,當模擬器或者手機上的當前介面是webView時UC-Dectools工具會檢測到,點選UC-Dectools工具上面的“inspect”按鈕進入到UI定位介面。

【Hybrid應用自動化指令碼編寫】

# 獲取所有的上下文contexts

driver.getContextHandles();

# 切換到對應的上下文context

driver.context(webview檢視對應的上下文);

# 定位webview中的元素,並執行操作

web網頁元素定位和操作,利用Appium提供的解決方案:基於UIAutomator+ChromeDriver,進行webview中元素的定位

# 切換回預設的檢視

driver.context(native檢視);

示例:

// 1 進入到web頁面中
androidDriver.findElementByAndroidUIAutomator("new UiSelector().text(\"網頁版\")").click();
// 2 獲取所有的contexts
Set<String> contexts = androidDriver.getContextHandles();
System.out.printIn(contexts);
// 3 切換到webview所對應的上下文
androidDriver.context("WEBVIEW_COM.wuba"); 
// 4 找到網頁中的“價格區間”按鈕
androidDriver.findElementByXPath("//li[@data-id='p25-30']").click();
// 5 點選網頁中的“確認”按鈕
androidDriver.findElementByXPath("//a[text()='確認']").click();

【注意】在上面的切換到webview所對應的上下文操作中可能會遇上因為ChromeDriver和webView的版本不匹配所導致的錯誤。簡單來說就是,ChromeDriver是appium中的一個工具,app中使用的webview有自己的版本號,ChromeDriver每個版本對webview的可支援版本都不一樣,所以需要保證版本的可支援性。

1 檢視ChromeDriver版本號,mac電腦的appium中ChromeDriver所在路徑為:

/Applications/Appium.app/Contents/Resources/app/node_modules/appium/node_modules/appium-chromedriver/chromedriver

雙擊會終端執行ChromeDriver會顯示出版本號,如下圖所示

2 檢視模擬器或者手機的webview版本號,有三種方式:

1)在模擬器或者真機上開啟一款需要webview的app,然後進入到設定-應用程式中開啟“顯示系統程序”,找到類似下圖所示的程序:

然後點選進去便可檢視到版本號:

2)通過UC-Dectools工具中檢測到的webview時,資訊上會附帶有版本資訊。

3)使用adb工具,首先確保連線上夜神模擬器

$adb connect 127.0.0.1:62001

可以通過下面的命令確保是否連線成功:

$adb devices

然後檢視系統的所有程式:

$adb shell pm list package -s

找到webview:

複製好此包名,然後檢視該應用包的資訊:

adb shell dumpsys package com.google.android.webview

最後找到關於version的相關資訊:

3 第三步對照版本匹配表,在github可以查詢到淘寶的映象網站:

github上appium【https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/web/chromedriver.md

淘寶的映象網站【http://npm.taobao.org/mirrors/chromedriver

我電腦上的appium中的ChromeDriver版本號通過上面方式的查詢是2.38版本,在映象網站上找到對應的2.38目錄,點選進去長相如下:

前面三個是安裝包,點選最後一個檔案“notes.txt”檢視該ChromeDriver版本支援哪些webview版本:

4 如果版本不匹配,替換掉appium中的ChromeDriver應用程式。

比如本文所示,通過檢視ChromeDriver的版本是2.38版本,支援的webview是65-67版本;通過檢視webview的版本是75,存在不匹配的情況,因為webview的版本不能更改,因此只能替換掉appium中的ChromeDriver應用程式。

【非root狀態的Hybrid應用自動化測試解決方案】

解決方案:通過VirtualXposed完成線上App開啟webview除錯,VirtualXposed相當於一個“應用分身”提供一個虛擬環境,這個虛擬環境中預設裝了一個Xposed,

1 將VirtualXpose.apk安裝到真機中,在VirtualXposed中安裝WebviewDebugHook.apk和需要測試的app安裝包

2 在VirtualXposed中開啟測試的目標app,就相當於在root狀態下測試app