Android自動化測試入門(二)UI Automator

UI Automator是一個界面測試框架,支持跨進程,幾乎可以模擬所有的人工操作。需要運行在4.3或者更高的系統版本上。它的測試代碼的編寫不依賴於目標應用的內部實現細節,非常適用編寫黑盒自動化測試。

官方文檔

UI Automator 測試框架的主要功能包括:

  • uiautomatorviewer: 用來掃描和分析當前設備的當前頁面的佈局結構,它是sdk中自帶的工具位置在 sdk/tools/bin/uiautomatorviewer.bat
  • UiDevice:可以訪問目標設備的各種屬性,執行設備上的一些操作,比如獲取設備的屏幕尺寸,旋轉設備,點擊設備的返回鍵,菜單鍵,home鍵等。比如點擊home鍵UiDevice.pressHome()
  • UI Automator API:用來編寫可靠的測試

UI Automator API中有幾個比較重要的類

  • UiObject:代表設備上可見的界面元素,也就是一個一個的控件
  • UiObject2:也是代表界面上的一個元素,它和特定的視圖綁定,如果所綁定的視圖失效,它也會跟着失效。
  • UiSelector:主要封裝了用於界面定位的一系列的方法,主要通過控件的屬性來實現控件的定位,用來定位的屬性一般有:Text,descirption,class,package,resource-id等。如果搜索到多個滿足條件的控件,會返回第一個。屬性的搜索可以疊加搜索,比如使用Text篩選出一組控件,還可以使用descirption繼續篩選。一般配合UiObject來使用,最終返回一個UiObject對象
  • UiCollection:按照一定的條件列舉出界面中所有符合條件的元素,然後在根據內容的文本或者可見內容描述來定位界面上的一個控件或者一個元素。UiCollection對應Android中的ViewGrop
  • UiScrollable:用來處理可滾動控件的滾動操作。
  • Configurator:用來設置用於運行 UI Automator測試的關鍵參數

官方demo

下面開始使用UI Automator來測試一下系統的計算器,完成一個1+9=10的操作。雖然前面介紹了一堆UI Automator API相關的類,不過用起來的時候很簡單,使用官方封裝的By類可以很方便的找到對應的界面元素。

打開AndroidStudio,新建一個項目,首先在app下的build.gradle中引入UI Automator的依賴:

androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'

當新建完一個項目的時候,會看到項目中有兩個測試相關的文件夾app/src/androidTestapp/src/test

  • app/src/androidTest 主要是運行在真實手機或者模擬器上的測試,比如集成測試,端到端測試,以及僅靠JVM無法完成的功能驗證測試
  • app/src/test 在本地計算機上運行的測試,比如單元測試

UI Automator屬於運行在手機端,所以去項目中找到app/src/androidTest目錄,在這裏面就可以編寫UI Automator的測試代碼了。新建一個測試類CalculateTest

//執行單元測試的執行類
@RunWith(AndroidJUnit4.class)
//4.3以上系統可以使用
@SdkSuppress(minSdkVersion = 18)
public class CalculateTest {......}
  • 指定執行單元測試的執行類爲AndroidJUnit4
  • 限制最小運行的sdk是18

一個測試類主要包括三部分,分別用3個註解表示:

  • @Before 測試之前執行,一般用來創建對象或者一些準備工作
  • @Test 用來標註測試方法,可以有多個
  • @After 測試完成之後執行,可以做一些清理工作

想要定位界面上的一個元素,可以通過它的resource-id,包名,文本,類名,內容等信息來定位,如果要測試的應用沒有源碼,可以通過uiautomatorviewer.bat來獲取如下圖,點擊某個元素,右邊就會顯示出它的一些信息。
在這裏插入圖片描述

//執行單元測試的執行類
@RunWith(AndroidJUnit4.class)
//4.3以上系統可以使用
@SdkSuppress(minSdkVersion = 18)
public class CalculateTest {

     private UiDevice mUiDevice;

     //測試執行之前的操作
    @Before
    public void startMainActivityFromHomeScreen() {
        mUiDevice = UiDevice.getInstance(getInstrumentation());
        //點擊home鍵
        mUiDevice.pressHome();
        // 獲取啓動頁的包名,並判斷是否爲空
        final String launcherPackage = getLauncherPackageName();
        assertThat(launcherPackage, notNullValue());
        //等待啓動完成
        mUiDevice.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)), 3000);

        //啓動計算器程序
        Context context = getApplicationContext();
        //通過包名創建啓動的intent
        Intent intent = context.getPackageManager()
                .getLaunchIntentForPackage("com.android.calculator2");
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
        context.startActivity(intent);
        //等待啓動完成
        mUiDevice.wait(Until.hasObject(By.pkg("com.android.calculator2").depth(0)),3000);
    }

    @Test
    public void calculate() throws InterruptedException, UiObjectNotFoundException {
        //點擊1
        Thread.sleep(1000);
        mUiDevice.pressKeyCode(KeyEvent.KEYCODE_1);
        Thread.sleep(1000);
        //點擊加號
        mUiDevice.findObject(By.res("com.android.calculator2:id/op_add")).click();
        Thread.sleep(1000);
        //點擊9
        mUiDevice.findObject(By.text("9")).click();
        Thread.sleep(1000);
        //點擊等號
        mUiDevice.findObject(By.desc("等於")).click();
        Thread.sleep(1000);
        //斷言驗證結果是否正確
        //模擬器
        UiObject2 result = mUiDevice.findObject(By.res("com.android.calculator2:id/result"));
        //華爲mate20
//        UiObject2 result = mUiDevice.findObject(By.res("com.android.calculator2:id/formula"));
        //使用UiSelector的方式查找
//        UiObject result = mUiDevice.findObject(new UiSelector().resourceId("com.android.calculator2:id/result"));
        Assert.assertEquals("10",result.getText());
    }

    @After
    public void clearNum() {
        //測試完成之後,點擊clear鍵清除界面上是數字
        //模擬器
        mUiDevice.findObject(By.res("com.android.calculator2:id/clr")).click();
        //華爲mate20
//        mUiDevice.findObject(By.res("com.android.calculator2:id/op_clr")).click();
    }

    /**
     * 獲取程序的啓動包名
     * @return
     */
    private String getLauncherPackageName() {
        final Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_HOME);
        // 通過PackageManager獲取啓動的包名
        PackageManager pm = getApplicationContext().getPackageManager();
        ResolveInfo resolveInfo = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
        return resolveInfo.activityInfo.packageName;
    }
}
  • 代碼中嘗試了幾種不同方式找到界面上的一個元素控件,比如通過keyCode,通過resourceID,通過text,通過desc。還有別的方式可以進By類中查看。屬性篩選可以疊加
  • 代碼中一個控件的各種屬性通過uiautomatorviewer工具獲取,工具位置在sdk/tools/bin/uiautomatorviewer.bat,雙擊打開就可以了。點擊左上角的Device ScreenShot按鈕,就能獲取當前手機屏幕的快照信息。點擊目標控件就能在右邊看到該控件的各種屬性信息如圖。
  • 尋找一個界面控件可以使用mUiDevice.findObject(By...的方式也可以使用mUiDevice.findObject(new UiSelector()....的方式,分別返回UiObject和UiObject2
  • 每個步驟之間最好延時一下,防止測試機還沒運行完當前指令後面的指令就執行了。

最後是運行結果:
在這裏插入圖片描述
運行完之後可以在下面的地方導出測試報告
在這裏插入圖片描述
可以在指定目錄生成一個HTML文件,打開文件就可以查看測試的一些信息。
在這裏插入圖片描述

注意: 官方建議只有在應用必須要跟系統或者第三方應用有一定的交互的時候,才使用UI Automator來測試。一般情況下如果只是測試自己的應用,建議使用Espresso來代替UI Automator。而且新建一個項目的時候,Espresso相關的依賴都已經在項目中默認引入了,所以官方更推薦我們使用Espresso來測試我們的應用,下一篇來練習Espresso的使用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章