天天看點

Android Studio自動化測試Espresso及Ui Automator1、Espresso自動化測試2、Ui Automator測試3、Ui Automator View的使用

簡述:

1 >自動化測試Espresso最顯著的特點就是,可以與Ui互動。

2 >自動化測試Ui Automator可以與多個app進行互動

Ui Automator與現狀業界裡主流的Android自動化測試工具相比有什麼優缺點呢?

優點:

① 可以對所有操作進行自動化測試,操作簡單

② 不需要對被測程式進行重命名,且可測試所有裝置上的程式,如某APP,撥号、發資訊等

③ 對應控件定位,要比robotium簡單一點

缺點:

① Ui Automator需要Android Level 16以上才可以使用,因為在Level 16及以上的API裡面才帶有UiAutomator工具

② 如果想要使用resource-id定位控件,則需要level 18及以上才可以

③ 對中文支援不好(不代表不支援,第三方jar可以實作)

3 >Ui Automator Viewer擷取頁面布局及控件屬性

Android Studio安裝及相關配置請參考Android Studio安裝與配置。

系統:Windows 7 64bit

Android系統:Android Studio 3.0.0.18

JDK:1.8.0_151

1、Espresso自動化測試

1 > 首先,在Android Studio 3.0中建立一個項目“EspressoTest”,建立方法參考Android Studio安裝與配置第3項。

同時删除自動生成的一些檔案,最終目錄結構如下:

Android Studio自動化測試Espresso及Ui Automator1、Espresso自動化測試2、Ui Automator測試3、Ui Automator View的使用

2> 在app目錄下的build.gradle檔案中添加下面的引入,根據提示點選Sync Now

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar']) 
    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
    implementation 'com.android.support:support-annotations:26.1.0'
    implementation 'com.android.support:recyclerview-v7:26.1.0'
    testImplementation 'junit:junit:4.12' 
    androidTestImplementation 'com.android.support.test:runner:1.0.1'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' 
    androidTestImplementation('com.android.support.test.espresso:espresso-contrib:3.0.1') {
        transitive false
    }
    androidTestImplementation 'com.android.support.test.espresso:espresso-web:3.0.1'
    androidTestImplementation 'com.android.support:support-annotations:26.1.0'
    androidTestImplementation 'com.android.support:recyclerview-v7:26.1.0'
}
           

3 > 編寫相關代碼

Android Studio自動化測試Espresso及Ui Automator1、Espresso自動化測試2、Ui Automator測試3、Ui Automator View的使用

其中MainActivity界面如下,輸入框中點選數字後點選計算可以在結果處顯示兩者相加的值,點選webview跳轉到WebViewActivity,點選recycleview跳轉到RecycleViewActivity。

Android Studio自動化測試Espresso及Ui Automator1、Espresso自動化測試2、Ui Automator測試3、Ui Automator View的使用
Android Studio自動化測試Espresso及Ui Automator1、Espresso自動化測試2、Ui Automator測試3、Ui Automator View的使用
Android Studio自動化測試Espresso及Ui Automator1、Espresso自動化測試2、Ui Automator測試3、Ui Automator View的使用

測試代碼:

MainActivityTest:

package com.hebbe.espressotest;

import android.support.test.espresso.Espresso;
import android.support.test.espresso.contrib.RecyclerViewActions;
import android.support.test.espresso.matcher.ViewMatchers;
import android.support.test.espresso.web.assertion.WebViewAssertions;
import android.support.test.espresso.web.webdriver.DriverAtoms;
import android.support.test.espresso.web.webdriver.Locator;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;

import org.hamcrest.Matchers;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import com.hebbe.espressotest.MainActivity;
import com.hebbe.espressotest.R;

import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.action.ViewActions.closeSoftKeyboard;
import static android.support.test.espresso.action.ViewActions.typeText;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static android.support.test.espresso.web.sugar.Web.onWebView;
import static android.support.test.espresso.web.webdriver.DriverAtoms.findElement;
import static android.support.test.espresso.web.webdriver.DriverAtoms.webClick;
import static org.junit.Assert.*;

/**
 * Created by Hebbe on 2018/1/15.
 */
@RunWith(AndroidJUnit4.class)
public class MainActivityTest {
    @Rule
    public ActivityTestRule activityTestRule = new ActivityTestRule(MainActivity.class);

    @Test
    public void test() {
        //通過id找到edittext,在裡面輸入2并關閉輸入法
        Espresso.onView(withId(R.id.editText)).perform(typeText("2"),closeSoftKeyboard());
        //通過id找到edittext,在裡面輸入5并關閉輸入法
        Espresso.onView(withId(R.id.editText2)).perform(typeText("5"), closeSoftKeyboard());
        //通過id找到button,執行點選事件
        Espresso.onView(withId(R.id.button)).perform(click());
        //通過id找到textview,并判斷是否與文本比對
        //Espresso.onView(withId(R.id.textView)).check(matches(withText("計算結果:6")));
        Espresso.onView(withId(R.id.textView)).check(matches(withText("計算結果:7")));
    }

    @Test
    public void testRecycleView() {
        //通過文本RecycleView找到按鈕,并執行點選事件,跳轉到RecycleviewActivity
        Espresso.onView(withText("RecycleView")).perform(click());
        //通過文本"Item 0"找到view,并檢查是否顯示,然後執行點選事件,此時會彈出對話框
        Espresso.onView(withText("Item 0")).check(matches(isDisplayed())).perform(click());
        //通過文本"确定"找到對話框上的确定按鈕,執行點選事件,關閉對話框
        Espresso.onView(withText("确定")).perform(click());
        //通過文本"Item 2"找到view,并檢查是否顯示,然後執行點選事件,此時會彈出對話框
        Espresso.onView(withText("Item 2")).check(matches(isDisplayed())).perform(click());
        //執行點選傳回按鈕事件,關閉對話框
        Espresso.pressBack();
        //通過id找到recycleview,然後執行滑動事件,滑動到21項
        Espresso.onView(ViewMatchers.withId(R.id.recycleview)).perform(RecyclerViewActions.scrollToPosition(21));
        //通過文本"Item 20"找到view,并檢查是否顯示,然後執行點選事件,此時會彈出對話框
        Espresso.onView(withText("Item 20")).check(matches(isDisplayed())).perform(click());
        //通過文本"确定"找到對話框上的确定按鈕,執行點選事件,關閉對話框
        Espresso.onView(withText("确定")).perform(click());
        //執行點選傳回按鈕事件,關閉跳轉到RecycleviewActivity
        Espresso.pressBack();
    }

    @Test
    public void testWebView() {
        //通過文本RecycleView找到按鈕,并執行點選事件,跳轉到WebViewActivity
        Espresso.onView(withText("WebView")).perform(click());
        //通過name為"word"找到搜尋輸入框
        onWebView().withElement(findElement(Locator.NAME, "word"))
                //往輸入框中輸入字元串"android"
                .perform(DriverAtoms.webKeys("android"))
                //通過id為"index-bn"找到"百度一下"按鈕
                .withElement(DriverAtoms.findElement(Locator.ID, "index-bn"))
                //執行點選事件
                .perform(webClick())
                //通過id為"results"找到結果div
                .withElement(DriverAtoms.findElement(Locator.ID, "results"))
                //檢查div中是否包含字元串"android"
                .check(WebViewAssertions.webMatches(DriverAtoms.getText(), Matchers.containsString("android")));
        //執行點選傳回按鈕事件,關閉跳轉到WebViewActivity
        Espresso.pressBack();
    }

}
           

WebViewActivityTest:

package com.hebbe.espressotest;
import android.content.Intent;
import android.support.test.espresso.web.action.AtomAction;
import android.support.test.espresso.web.assertion.WebViewAssertions;
import android.support.test.espresso.web.sugar.Web;
import android.support.test.espresso.web.webdriver.DriverAtoms;
import android.support.test.espresso.web.webdriver.Locator;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;

import org.hamcrest.Matchers;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import com.hebbe.espressotest.WebViewActivity;

import static android.support.test.espresso.web.sugar.Web.onWebView;
import static android.support.test.espresso.web.webdriver.DriverAtoms.findElement;
import static android.support.test.espresso.web.webdriver.DriverAtoms.webClick;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.*;

/**
 * Created by Hebbe on 2018/1/15.
 */
@RunWith(AndroidJUnit4.class)
public class WebViewActivityTest {
    @Rule
    public ActivityTestRule activityTestRule = new ActivityTestRule(WebViewActivity.class, false);

    @Test
    public void test() {
        //傳遞資料到WebViewActivity
        Intent intent = new Intent();
        intent.putExtra(WebViewActivity.EXTRA_URL, "http://www.baidu.com");
        activityTestRule.launchActivity(intent);

        //通過name為"word"找到搜尋輸入框
        onWebView().withElement(findElement(Locator.NAME, "word"))
                //往輸入框中輸入字元串"android"
                .perform(DriverAtoms.webKeys("android"))
                //通過id為"index-bn"找到"百度一下"按鈕
                .withElement(DriverAtoms.findElement(Locator.ID, "index-bn"))
                //執行點選事件
                .perform(webClick())
                //通過id為"results"找到結果div
                .withElement(DriverAtoms.findElement(Locator.ID, "results"))
                //檢查div中是否包含字元串"android"
                .check(WebViewAssertions.webMatches(DriverAtoms.getText(), Matchers.containsString("android")));

    }
}
           

4 > 測試運作效果

Android Studio自動化測試Espresso及Ui Automator1、Espresso自動化測試2、Ui Automator測試3、Ui Automator View的使用

2、Ui Automator測試

Ui Automator自動化測試最顯著的特點就是可以與多個app進行互動。

1 > 首先,在Android Studio 3.0中建立一個項目“UIAutomatorTest”,建立方法參考Android Studio安裝與配置第3項。

同時删除自動生成的一些檔案,最終目錄結構如下:

Android Studio自動化測試Espresso及Ui Automator1、Espresso自動化測試2、Ui Automator測試3、Ui Automator View的使用
2> 在app目錄下的build.gradle檔案中添加下面的引入,根據提示點選Sync Now
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
    implementation 'com.android.support:support-annotations:26.1.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.1'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
    androidTestCompile 'com.android.support:support-annotations:26.1.0'
    // UiAutomator Testing
    androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.1'
    androidTestCompile 'org.hamcrest:hamcrest-integration:1.3'

}
           
3 > 生成測試類,在MainActivity類中單擊滑鼠右鍵 →Go To →Test →Create New Test
Android Studio自動化測試Espresso及Ui Automator1、Espresso自動化測試2、Ui Automator測試3、Ui Automator View的使用

選擇.../app/src/androidTest/java/...

點選OK,然後可以看到在剛剛選擇的目錄中生成了測試類AutomatorTest

4 > 編寫測試類

在AutomatorTest類中編寫測試代碼,為了測試多個app,選擇前面中的EspressoTest應用和手機中的設定app

Android Studio自動化測試Espresso及Ui Automator1、Espresso自動化測試2、Ui Automator測試3、Ui Automator View的使用
package com.hebbe.uiautomatortest;

import android.content.Context;
import android.content.Intent;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SdkSuppress;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject;
import android.support.test.uiautomator.UiScrollable;
import android.support.test.uiautomator.UiSelector;
import android.support.test.uiautomator.Until;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.ScrollView;
import android.widget.TextView;

import org.junit.Test;
import org.junit.runner.RunWith;


import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.*;

/**
 * Created by Hebbe on 2018/1/17.
 */
@RunWith(AndroidJUnit4.class)
@SdkSuppress(minSdkVersion = 22)
public class AutomatorTest {
    private static final String PACKAGE_ESPRESSOTEST = "com.hebbe.espressotest";
    private static final String PACKAGE_SETTING = "com.android.settings";

    @Test
    public void testEspressoTestApp() throws Exception {
        //初始化一個UiDevice對象
        UiDevice mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
        // 點選home鍵,回到home界面
        mDevice.pressHome();
        String launcherPackage = mDevice.getLauncherPackageName();
        assertThat(launcherPackage,notNullValue());
        mDevice.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)),3);

        // 啟動espressotest App
        Context context = InstrumentationRegistry.getContext();
        Intent intent = context.getPackageManager().getLaunchIntentForPackage(PACKAGE_ESPRESSOTEST);
        // 清除以前的執行個體
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
        context.startActivity(intent);

        // 等待應用程式啟動
        mDevice.wait(Until.hasObject(By.pkg(PACKAGE_ESPRESSOTEST).depth(0)),3);
        //通過id找到輸入框一
        UiObject edt1 = mDevice.findObject(new UiSelector().resourceId("com.hebbe.espressotest:id/editText").className(EditText.class));
        //往裡面輸入字元2
        edt1.setText("2");
        //通過id找到輸入框二
        UiObject edt2 = mDevice.findObject(new UiSelector().resourceId("com.hebbe.espressotest:id/editText2").className(EditText.class));
        //往裡面輸入字元5
        edt2.setText("5");
        //通過文本"計算"找到按鈕
        UiObject btn = mDevice.findObject(new UiSelector().text("計算").className(Button.class));
        //執行點選事件,計算結果
        btn.click();
        //通過id找到顯示結果的textview
        UiObject tvResult = mDevice.findObject(new UiSelector().resourceId("com.hebbe.espressotest:id/textView").className(TextView.class));
        //判斷結果與預期是否比對
        assertEquals(tvResult.getText(),"計算結果:7");

        //點選傳回關閉對話框
        mDevice.pressBack();
    }

    @Test
    public void testSettingApp() throws Exception {
        //初始化一個UiDevice對象
        UiDevice mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
        Context context = InstrumentationRegistry.getContext();
        //回到home界面
        mDevice.pressHome();
        // 啟動設定
        Intent intent = context.getPackageManager().getLaunchIntentForPackage(PACKAGE_SETTING);
        // 清除以前的執行個體
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
        context.startActivity(intent);
        //通過id找到scrollview
        UiScrollable scrollview = new UiScrollable(new UiSelector().className(ScrollView.class).resourceId("com.android.settings:id/dashboard"));
        //滑動到底部
        scrollview.flingForward();
        //通過文本找到關于手機
        UiObject aboutPhone = scrollview.getChild(new UiSelector().text("關于手機"));
        //點選跳轉到手機資訊界面
        aboutPhone.click();
        //通過description找到向上傳回的ImageButton
        UiObject ibtnBack = mDevice.findObject(new UiSelector().className(ImageButton.class).description("向上導航"));
        //點選傳回
        ibtnBack.click();
        //滑動到包含"提示音和通知"的地方
        scrollview.scrollTextIntoView("提示音和通知");
        //通過顯示的文本找到控件
        UiObject notify = scrollview.getChild(new UiSelector().text("提示音和通知"));
        //點選跳轉到下一個界面
        notify.click();
        //通過顯示的文本"手機鈴聲"找到控件
        UiObject sound = mDevice.findObject(new UiSelector().text("手機鈴聲"));
        //點選跳轉到鈴聲對話框
        sound.click();
        //通過id找到鈴聲清單
        UiScrollable listview = new UiScrollable(new UiSelector().className(ListView.class).resourceId("android:id/select_dialog_listview"));
        //活動到包含"Beat Plucker"處
        listview.scrollTextIntoView("Beat Plucker");
        //通過顯示的文本找到該項
        UiObject beat = listview.getChild(new UiSelector().text("Beat Plucker"));
        //執行點選選中鈴聲
        beat.click();
        //通過文本"确定"找到對話框中的确定按鈕
        UiObject btnConfirm = mDevice.findObject(new UiSelector().text("确定").className(Button.class));
        //點選确定關閉對話框
        btnConfirm.click();
        //通過id找到顯示結果的TextView
        UiObject tvSound = mDevice.findObject(new UiSelector().resourceId("android:id/summary").className(TextView.class));
        //比較與預期結果是否一緻
        assertEquals(tvSound.getText(),"Beat Plucker");
        //點選home鍵
        mDevice.pressHome();
        //點選最近應用鍵
        mDevice.pressRecentApps();
        //通過類名找到顯示最近app的控件TaskStackView
        UiScrollable taskStackView = new UiScrollable(new UiSelector().className("com.android.systemui.recents.views.TaskStackView"));
        //滑動到包含"EspressoTests"處
        taskStackView.scrollTextIntoView("EspressoTest");
        //通過顯示的文本找到item
        UiObject espressoTestApp = taskStackView.getChild(new UiSelector().text("EspressoTest"));
        //點選切換到前面的espressoTestsApp
        espressoTestApp.click();
    }
}
           

5 > 測試運作效果

直接在測試類上單擊滑鼠右鍵 → 選擇 Run 'AutomatorTest'即可。

Android Studio自動化測試Espresso及Ui Automator1、Espresso自動化測試2、Ui Automator測試3、Ui Automator View的使用

3、Ui Automator View的使用

從上面的測試代碼可以看到,需要提前知道目标控件的一些屬性值,然後再圍繞目标屬性值建構一個比對規則。

而實際開發中,我們并不知道app的實作,控件的屬性也并不清楚,這時,便可以使用Android提供的uiautormatorviewer工具來分析。(uiautormatorviewer路徑:...\Android\Sdk\tools\bin)

1 > Android Studio中點選“ Tools ” → “Android”→“Android Device Monitor ”,彈出Android Device Monitor 界面。

2 > 該界面最左邊會顯示連接配接的裝置

3 > 點選“Dump View Hierarchy for UI Automator” 圖示,顯示目前頁面布局

Android Studio自動化測試Espresso及Ui Automator1、Espresso自動化測試2、Ui Automator測試3、Ui Automator View的使用
4 > 在右邊會顯示布局結構以及view詳細的資訊
Android Studio自動化測試Espresso及Ui Automator1、Espresso自動化測試2、Ui Automator測試3、Ui Automator View的使用

參考:

Android自動化測試