手把手教你uiautomator_android自動化測試第一個示例
android的自動化測試方案,弄了好久了。
Google在sdk4.0以後提供了一個自動化解決方案uiautomator:
優點:可以跨應用了;這可是親生的;
缺點:必須sdk4.0以上版本;要想實現的好,最好有開發配合;java專案編譯為jar後需要push到手機才能執行,也就是說必須列印日誌暴力除錯。
後來聽到群友Teddy說到appium和calabash-android,翻了一下appium的文章,發現:
01.jpg
Appium基於Android InstrumentationFramework和UIAutomator,也就是說這個工具是可以跨應用的。說遠了,好吧,為了幫大家更容易理解appium的使用,我這裡就講一下uiautomator的使用方法。
首先提供uiautomator的官方網頁:
你應該有android-sdk吧,升級到4.0以上,進入目錄android-sdk\tools,你會看到兩個檔案:
traceview.bat 和 uiautomatorviewer.bat,這倆檔案讓你想起了monkeyrunner了吧,是的,traceview.bat就對應於hierarchyviewer.bat,用來檢視程式的ui介面的,通常也是使用管理員許可權啟動的。
除了androidsdk,還需要弄一個ant,用來編譯程式用,配置一下環境變數:
ANT_HOME=C:\PROGRAM\apache-ant-1.8.2
好了,現在用eclipse建立一個java project,是的,你沒看錯,是java project不是android project,新增引用:
02.jpg
在project.properties中內容為:
# Project target. target=android-16 |
這裡的android-16需要和之前的android.jar和uiautomator.jar位置相一致。
然後呢?寫程式碼吧,建立一個類,得,發個給大家參考:
package com.uia.example.my; import org.apache.http.util.EncodingUtils; import android.graphics.Bitmap; import android.graphics.BitmapFactory import android.graphics.Rect; import android.os.Environment; import com.android.uiautomator.core.UiObject; import com.android.uiautomator.core.UiObjectNotFoundException; import com.android.uiautomator.core.UiScrollable; import com.android.uiautomator.core.UiSelector; import com.android.uiautomator.testrunner.UiAutomatorTestCase; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; public class TAppWorkAssistV1 extendsUiAutomatorTestCase { public StringsLog; public Filefout =null; public FileOutputStreamoutStream=null; public void write2file(String filename,String sData) { String sLog=""; //初始化日誌檔案 if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ sLog = Environment.getExternalStorageDirectory().getAbsolutePath(); try{ fout = new File(sLog,filename); outStream = new FileOutputStream(fout,true); //此處的true是append sData=sData +"\n"; outStream.write(sData.getBytes()); outStream.flush(); outStream.close(); fout=null; } catch(Exception e){ e.printStackTrace(); } }else{ System.out.println("該手機沒有SD卡"); } } public void testDemo() throws UiObjectNotFoundException { //1. 啟動app getUiDevice().pressHome(); UiObject allAppsButton = new UiObject(new UiSelector().description("Apps")); allAppsButton.clickAndWaitForNewWindow(); UiObject appsTab = new UiObject(new UiSelector().text("Apps")); appsTab.click(); UiScrollable appViews = new UiScrollable(new UiSelector().scrollable(true)); UiObject settingsApp = appViews.getChildByText(new UiSelector().className(android.widget.TextView.class.getName()),"Efilm"); settingsApp.clickAndWaitForNewWindow(); //2. 進入主介面 System.out.println("into main view"); System.out.println(getUiDevice().waitForWindowUpdate("com.eshore.efilm", 60000)); System.out.println("intoed main view"); UiObject tv1 = new UiObject(new UiSelector().text("影院")); tv1.click(); //3.點選影院 UiObject oyy= new UiObject(new UiSelector().description("cinema_row")); System.out.println("wait yingyuan come out"); oyy.waitForExists(60000); System.out.println("yingyuan come out"); oyy.clickAndWaitForNewWindow(); System.out.println("click yingyuan"); //4.場次 UiObject occ= new UiObject(new UiSelector().description("LinearLayout10")); System.out.println("wait changci come out"); oyy.waitForExists(60000); System.out.println("changci come out"); occ.clickAndWaitForNewWindow(); System.out.println("click changci"); //5.座位 UiObject oseat= new UiObject(new UiSelector().description("cinema_shows_list_item").index(0).childSelector(new UiSelector().description("LinearLayout10"))); System.out.println("wait seat come out"); oseat.waitForExists(5000); int h=getUiDevice().getDisplayHeight(); int w=getUiDevice().getDisplayWidth(); System.out.println("(h/2,w/2)="+h/2+","+w/2); getUiDevice().click(h/2,w/2); //System.out.println("seat count:"+String.valueOf(oseat.getChildCount())); //System.out.println("seat getText:"+ oseat.getText()); //截座點陣圖 Process process; try { process = Runtime.getRuntime().exec("screencap /mnt/sdcard/EfilmFailSnapShot01.png"); try { process.waitFor(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } //takeScreenShots("EfilmSeatSnapShot"); } } |
這個例子是隨便寫的,可能不夠嚴謹。大體就這麼個情況吧。下一步就是編譯執行了,先插上手機usb介面,然後開啟cmd,執行:
找到SDKID,也就是android create中的-t引數: cd C:\ PROGRAM\android-sdk\tools android list |
找到t引數的值以後:
cd C:\ PROGRAM\android-sdk\tools android create uitest-project -n TAppWorkAssistV1 -t 25 -p C:\android自動化\Tv2.0\TestSetting cd C:\android自動化\Tv2.0\TestSetting ant build cd C:\android自動化\Tv2.0\TestSetting\bin adb push TAppWorkAssistV1.jar /data/local/tmp/ adb shell uiautomator runtest TAppWorkAssistV1.jar -c com.uia.example.my. TAppWorkAssistV1 |
看了看,好像沒有什麼特別值得解釋的
-n TAppWorkAssistV1:類名
-p: 專案所在目錄
Ant build 把這個類編譯成一個jar包:TAppWorkAssistV1.jar
然後把jar包push到手機上,呼叫執行這個類就可以了
大致是這麼個步驟,不過有一個非常重要的細節,就是如果你需要更省心,就最好把介面元素,無論動態的還是佈局檔案中的,都加上content-description屬性,並保證唯一性,根據:
UiSelector:description(String desc)
Set the search criteria to match thecontent-description property for a widget.
那就可以統一隻使用這一個引用介面元素的方法就行了,就不用去想方設法利用其它的屬性來引用了。
如果你沒有原始碼,那就只能根據那個traceview.bat工具來找不同的引用方法了,如果有原始碼,可以參考下文:
說回來了,appium還有instrument部分,可以參考下文:
或者參考ranorex的instrument程式碼,就可以理解instrument是怎麼回事了,說穿了加上個instrument的jar包引用,然後設hook。
有了這幾部分知識做底,appium如何實現就會比較容易理解了。
如有錯漏,不吝賜教。