【測試】安卓自動化測試程式碼片段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 = newDesiredCapabilities(); // 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