Menguji UI untuk beberapa aplikasi

Pengujian antarmuka pengguna (UI) yang melibatkan interaksi pengguna di beberapa aplikasi memungkinkan Anda memverifikasi bahwa aplikasi Anda berperilaku dengan benar saat alur pengguna melewati aplikasi lain atau UI sistem. Contoh alur pengguna tersebut adalah aplikasi pesan yang memungkinkan pengguna memasukkan pesan teks, meluncurkan pemilih kontak Android sehingga pengguna dapat memilih penerima yang akan dikirimi pesan, lalu menampilkan kontrol ke aplikasi asli yang digunakan pengguna untuk mengirim pesan.

Tutorial ini membahas cara menulis pengujian UI menggunakan framework pengujian UI Automator yang disediakan oleh AndroidX Test. UI Automator API memungkinkan Anda berinteraksi dengan elemen yang terlihat di perangkat, terlepas dari Activity mana yang menjadi fokus. Pengujian Anda bisa mencari komponen UI dengan menggunakan deskriptor sederhana seperti teks yang ditampilkan dalam komponen itu atau deskripsi kontennya. Pengujian UI Automator bisa dijalankan pada perangkat yang menjalankan Android 4.3 (API level 18) atau yang lebih tinggi.

Framework pengujian UI Automator adalah API berbasis instrumentasi dan berfungsi dengan runner pengujian AndroidJUnitRunner.

Anda juga harus membaca Referensi UI Automator API dan mencoba Contoh Kode UI Automator.

Menyiapkan UI Automator

Sebelum membuat pengujian UI dengan UI Automator, pastikan untuk mengonfigurasi lokasi kode sumber pengujian dan dependensi project Anda, seperti yang dijelaskan dalam Menyiapkan project untuk AndroidX Test.

Dalam file build.gradle modul aplikasi Android, Anda harus menentukan referensi dependensi ke library UI Automator:

    dependencies {
        ...
        androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'
    }
    

Untuk mengoptimalkan pengujian UI Automator, langkah pertama yang harus Anda lakukan adalah memeriksa komponen UI aplikasi target dan memastikannya dapat diakses. Tips pengoptimalan ini dijelaskan dalam dua bagian berikutnya.

Memeriksa UI pada perangkat

Sebelum mendesain pengujian Anda, periksa komponen UI yang terlihat pada perangkat. Untuk memastikan bahwa pengujian UI Automator Anda dapat mengakses komponen ini, pastikan komponen tersebut memiliki label teks yang terlihat, nilai android:contentDescription, atau keduanya.

Fitur uiautomatorviewer menyediakan antarmuka visual yang nyaman untuk memeriksa hierarki tata letak dan melihat properti komponen UI yang terlihat di latar depan perangkat. Dengan informasi ini, Anda dapat membuat lebih banyak pengujian lebih terperinci menggunakan UI Automator. Misalnya, Anda dapat membuat pemilih UI yang cocok dengan properti terlihat tertentu.

Untuk meluncurkan fitur uiautomatorviewer:

  1. Luncurkan aplikasi target di perangkat fisik.
  2. Hubungkan perangkat ke mesin pengembangan Anda.
  3. Buka jendela terminal dan buka direktori <android-sdk>/tools/.
  4. Jalankan fitur tersebut dengan perintah ini:
    $ uiautomatorviewer

Untuk melihat properti UI untuk aplikasi Anda:

  1. Dalam antarmuka uiautomatorviewer, klik tombol Screenshot Perangkat.
  2. Arahkan kursor ke snapshot di panel sebelah kiri untuk melihat komponen UI yang diidentifikasi oleh fitur uiautomatorviewer. Properti dicantumkan di panel kanan bawah dan hierarki tata letak di panel kanan atas.
  3. (Opsional) Klik tombol Toggle NAF Nodes untuk melihat komponen UI yang tidak dapat diakses oleh UI Automator. Hanya informasi terbatas yang tersedia untuk komponen ini.

Untuk mempelajari jenis umum komponen UI yang disediakan oleh Android, lihat Antarmuka Pengguna.

Memastikan aktivitas Anda dapat diakses

Framework pengujian UI Automator berperforma lebih baik pada aplikasi yang telah mengimplementasikan fitur aksesibilitas Android. Jika Anda menggunakan elemen UI dari jenis View, atau subclass View dari SDK, Anda tidak perlu mengimplementasikan dukungan aksesibilitas, karena class tersebut telah melakukannya untuk Anda.

Namun, beberapa aplikasi menggunakan elemen UI kustom untuk memberikan pengalaman pengguna yang lebih kaya. Elemen tersebut tidak akan memberikan dukungan aksesibilitas secara otomatis. Jika aplikasi Anda berisi instance subclass dari View yang bukan dari SDK, pastikan Anda menambahkan fitur aksesibilitas ke elemen ini dengan menyelesaikan langkah-langkah berikut:

  1. Buat class konkret yang memperluas ExploreByTouchHelper.
  2. Kaitkan instance class baru Anda dengan elemen UI kustom tertentu dengan memanggil setAccessibilityDelegate().

Untuk mendapatkan panduan tambahan terkait menambahkan fitur aksesibilitas ke elemen tampilan kustom, lihat Membuat Tampilan Kustom yang Dapat Diakses. Untuk mempelajari lebih lanjut praktik terbaik yang umum untuk aksesibilitas di Android, lihat Membuat Aplikasi Lebih Mudah Diakses.

Membuat class pengujian UI Automator

Class pengujian UI Automator Anda harus ditulis dengan cara yang sama seperti class pengujian JUnit 4. Untuk mempelajari lebih lanjut cara membuat class pengujian JUnit 4 serta menggunakan pernyataan dan anotasi JUnit 4, lihat Membuat Class Pengujian Unit Berinstrumen.

Tambahkan anotasi @RunWith(AndroidJUnit4.class) di awal definisi class pengujian Anda. Anda juga harus menentukan class AndroidJUnitRunner, yang disediakan di AndroidX Test, sebagai runner pengujian default Anda. Langkah ini dijelaskan secara lebih mendetail dalam Menjalankan pengujian UI Automator pada perangkat atau emulator.

Implementasikan model pemrograman berikut ke class pengujian UI Automator Anda:

  1. Dapatkan objek UiDevice untuk mengakses perangkat yang ingin Anda uji, dengan memanggil metode getInstance() dan meneruskan objek Instrumentation sebagai argumen.
  2. Dapatkan objek UiObject untuk mengakses komponen UI yang ditampilkan pada perangkat (misalnya, tampilan aktif di latar depan), dengan memanggil metode findObject().
  3. Simulasikan interaksi pengguna tertentu untuk dijalankan pada komponen UI tersebut, dengan memanggil metode UiObject. Misalnya, panggil performMultiPointerGesture() untuk menyimulasikan gestur multi-sentuh, dan setText() untuk mengedit kolom teks. Bila perlu, ulangi langkah 2 dan 3 untuk memanggil API guna menguji interaksi pengguna yang lebih kompleks yang melibatkan beberapa komponen UI atau serangkaian tindakan pengguna.
  4. Periksa apakah UI mencerminkan status atau perilaku yang diharapkan, setelah interaksi pengguna ini dilakukan.

Langkah ini dibahas lebih detail di bagian di bawah ini.

Mengakses komponen UI

Objek UiDevice adalah cara utama Anda mengakses dan memanipulasi status perangkat. Dalam pengujian, Anda dapat memanggil metode UiDevice untuk memeriksa status berbagai properti, seperti orientasi saat ini atau ukuran tampilan. Pengujian dapat menggunakan objek UiDevice untuk melakukan tindakan tingkat perangkat, seperti memaksa perangkat berpindah ke rotasi tertentu, menekan tombol fisik D-pad, dan menekan tombol Layar Utama dan Menu.

Sebaiknya mulai pengujian Anda dari Layar utama perangkat. Dari Layar utama (atau beberapa lokasi awal lain yang Anda pilih pada perangkat), Anda dapat memanggil metode yang disediakan oleh UI Automator API untuk memilih dan berinteraksi dengan elemen UI tertentu.

Cuplikan kode berikut menunjukkan cara pengujian Anda bisa mendapatkan instance UiDevice dan menyimulasikan penekanan tombol Layar Utama:

Kotlin

    import org.junit.Before
    import androidx.test.runner.AndroidJUnit4
    import androidx.test.uiautomator.UiDevice
    import androidx.test.uiautomator.By
    import androidx.test.uiautomator.Until
    ...

    private const val BASIC_SAMPLE_PACKAGE = "com.example.android.testing.uiautomator.BasicSample"
    private const val LAUNCH_TIMEOUT = 5000L
    private const val STRING_TO_BE_TYPED = "UiAutomator"

    @RunWith(AndroidJUnit4::class)
    @SdkSuppress(minSdkVersion = 18)
    class ChangeTextBehaviorTest2 {

        private lateinit var device: UiDevice

        @Before
        fun startMainActivityFromHomeScreen() {
            // Initialize UiDevice instance
            device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())

            // Start from the home screen
            device.pressHome()

            // Wait for launcher
            val launcherPackage: String = device.launcherPackageName
            assertThat(launcherPackage, notNullValue())
            device.wait(
                    Until.hasObject(By.pkg(launcherPackage).depth(0)),
                    LAUNCH_TIMEOUT
            )

            // Launch the app
            val context = ApplicationProvider.getApplicationContext<Context>()
            val intent = context.packageManager.getLaunchIntentForPackage(
                    BASIC_SAMPLE_PACKAGE).apply {
                // Clear out any previous instances
                addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
            }
            context.startActivity(intent)

            // Wait for the app to appear
            device.wait(
                    Until.hasObject(By.pkg(BASIC_SAMPLE_PACKAGE).depth(0)),
                    LAUNCH_TIMEOUT
            )
        }

    }
    

Java

    import org.junit.Before;
    import androidx.test.runner.AndroidJUnit4;
    import androidx.test.uiautomator.UiDevice;
    import androidx.test.uiautomator.By;
    import androidx.test.uiautomator.Until;
    ...

    @RunWith(AndroidJUnit4.class)
    @SdkSuppress(minSdkVersion = 18)
    public class ChangeTextBehaviorTest {

        private static final String BASIC_SAMPLE_PACKAGE
                = "com.example.android.testing.uiautomator.BasicSample";
        private static final int LAUNCH_TIMEOUT = 5000;
        private static final String STRING_TO_BE_TYPED = "UiAutomator";
        private UiDevice device;

        @Before
        public void startMainActivityFromHomeScreen() {
            // Initialize UiDevice instance
            device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());

            // Start from the home screen
            device.pressHome();

            // Wait for launcher
            final String launcherPackage = device.getLauncherPackageName();
            assertThat(launcherPackage, notNullValue());
            device.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)),
                    LAUNCH_TIMEOUT);

            // Launch the app
            Context context = ApplicationProvider.getApplicationContext();
            final Intent intent = context.getPackageManager()
                    .getLaunchIntentForPackage(BASIC_SAMPLE_PACKAGE);
            // Clear out any previous instances
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
            context.startActivity(intent);

            // Wait for the app to appear
            device.wait(Until.hasObject(By.pkg(BASIC_SAMPLE_PACKAGE).depth(0)),
                    LAUNCH_TIMEOUT);
        }
    }
    

Dalam contoh, pernyataan @SdkSuppress(minSdkVersion = 18) membantu memastikan bahwa pengujian hanya berjalan di perangkat yang menggunakan Android 4.3 (API level 18) atau yang lebih tinggi, seperti yang diwajibkan oleh framework UI Automator.

Gunakan metode findObject() untuk mengambil UiObject yang merepresentasikan tampilan yang cocok dengan kriteria pemilih yang diberikan. Anda dapat menggunakan kembali instance UiObject yang telah Anda buat di bagian lain pengujian aplikasi, sesuai kebutuhan. Perhatikan bahwa framework pengujian UI Automator menelusuri tampilan saat ini untuk pencocokan setiap kali pengujian Anda menggunakan instance UiObject untuk mengklik elemen UI atau membuat kueri properti.

Cuplikan berikut menunjukkan cara pengujian dapat membuat instance UiObject yang merepresentasikan tombol Batal dan tombol OK di aplikasi.

Kotlin

    val cancelButton: UiObject = device.findObject(
            UiSelector().text("Cancel").className("android.widget.Button")
    )
    val okButton: UiObject = device.findObject(
            UiSelector().text("OK").className("android.widget.Button")
    )

    // Simulate a user-click on the OK button, if found.
    if (okButton.exists() && okButton.isEnabled) {
        okButton.click()
    }
    

Java

    UiObject cancelButton = device.findObject(new UiSelector()
            .text("Cancel")
            .className("android.widget.Button"));
    UiObject okButton = device.findObject(new UiSelector()
            .text("OK")
            .className("android.widget.Button"));

    // Simulate a user-click on the OK button, if found.
    if(okButton.exists() && okButton.isEnabled()) {
        okButton.click();
    }
    

Menentukan pemilih

Jika Anda ingin mengakses komponen UI tertentu dalam aplikasi, gunakan class UiSelector. Class ini merepresentasikan kueri untuk elemen tertentu di UI yang saat ini ditampilkan.

Jika elemen pencocokan yang ditemukan lebih dari satu, elemen pencocokan pertama dalam hierarki tata letak ditampilkan sebagai target UiObject. Saat membuat UiSelector, Anda dapat mengaitkan beberapa properti untuk mempersempit penelusuran. Jika tidak ditemukan elemen UI yang cocok, UiAutomatorObjectNotFoundException akan dimunculkan.

Anda dapat menggunakan metode childSelector() untuk menyarangkan beberapa instance UiSelector. Misalnya, contoh kode berikut menunjukkan cara pengujian Anda dapat menentukan penelusuran untuk menemukan ListView pertama dalam UI yang saat ini ditampilkan, lalu menelusuri di dalam ListView untuk menemukan elemen UI dengan Aplikasi properti teks.

Kotlin

    val appItem: UiObject = device.findObject(
            UiSelector().className("android.widget.ListView")
                    .instance(0)
                    .childSelector(
                            UiSelector().text("Apps")
                    )
    )
    

Java

    UiObject appItem = device.findObject(new UiSelector()
            .className("android.widget.ListView")
            .instance(0)
            .childSelector(new UiSelector()
            .text("Apps")));
    

Sebagai praktik terbaik, saat menentukan pemilih, sebaiknya gunakan ID Resource (jika ada yang ditetapkan untuk elemen UI), bukan elemen teks atau deskriptor konten. Tidak semua elemen memiliki atribut teks (misalnya, ikon di toolbar). Pemilih teks bersifat rapuh dan dapat menyebabkan kegagalan pengujian jika terdapat perubahan kecil pada UI. Pemilih teks juga mungkin tidak mendukung bahasa-bahasa lain. Pemilih teks Anda mungkin tidak mencocokkan string yang diterjemahkan.

Hal tersebut mungkin berguna untuk menentukan status objek dalam kriteria pemilih Anda. Misalnya, jika Anda ingin memilih daftar semua elemen yang dicentang sehingga Anda dapat menghapus centangnya, panggil metode checked() dengan argumen yang ditetapkan ke true.

Melakukan tindakan

Setelah pengujian Anda mendapatkan objek UiObject, Anda dapat memanggil metode dalam class UiObject untuk menjalankan interaksi pengguna pada komponen UI yang direpresentasikan oleh objek tersebut. Anda dapat menentukan tindakan seperti:

Framework pengujian UI Automator mengizinkan Anda mengirimkan Intent atau meluncurkan Activity tanpa menggunakan perintah shell, dengan mendapatkan objek Context melalui getContext().

Cuplikan berikut menunjukkan menggunakan Intent dalam pengujian Anda untuk meluncurkan aplikasi yang sedang diuji. Pendekatan ini berguna saat Anda hanya tertarik untuk menguji aplikasi kalkulator, dan tidak memerlukan peluncur.

Kotlin

    fun setUp() {
        ...

        // Launch a simple calculator app
        val context = getInstrumentation().context
        val intent = context.packageManager.getLaunchIntentForPackage(CALC_PACKAGE).apply {
            addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
        }
        // Clear out any previous instances
        context.startActivity(intent)
        device.wait(Until.hasObject(By.pkg(CALC_PACKAGE).depth(0)), TIMEOUT)
    }
    

Java

    public void setUp() {
        ...

        // Launch a simple calculator app
        Context context = getInstrumentation().getContext();
        Intent intent = context.getPackageManager()
                .getLaunchIntentForPackage(CALC_PACKAGE);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);

        // Clear out any previous instances
        context.startActivity(intent);
        device.wait(Until.hasObject(By.pkg(CALC_PACKAGE).depth(0)), TIMEOUT);
    }
    

Menjalankan tindakan pada koleksi

Gunakan class UiCollection jika Anda ingin menyimulasikan interaksi pengguna pada koleksi item (misalnya, lagu dalam album musik atau daftar email di Kotak Masuk). Untuk membuat objek UiCollection, tentukan UiSelector yang menelusuri penampung UI atau wrapper elemen UI turunan lainnya, seperti tampilan tata letak yang berisi elemen UI turunan.

Cuplikan kode berikut menunjukkan bagaimana pengujian Anda dapat membuat UiCollection untuk merepresentasikan album video yang ditampilkan dalam FrameLayout:

Kotlin

    val videos = UiCollection(UiSelector().className("android.widget.FrameLayout"))

    // Retrieve the number of videos in this collection:
    val count = videos.getChildCount(
            UiSelector().className("android.widget.LinearLayout")
    )

    // Find a specific video and simulate a user-click on it
    val video: UiObject = videos.getChildByText(
            UiSelector().className("android.widget.LinearLayout"),
            "Cute Baby Laughing"
    )
    video.click()

    // Simulate selecting a checkbox that is associated with the video
    val checkBox: UiObject = video.getChild(
            UiSelector().className("android.widget.Checkbox")
    )
    if (!checkBox.isSelected) checkBox.click()
    

Java

    UiCollection videos = new UiCollection(new UiSelector()
            .className("android.widget.FrameLayout"));

    // Retrieve the number of videos in this collection:
    int count = videos.getChildCount(new UiSelector()
            .className("android.widget.LinearLayout"));

    // Find a specific video and simulate a user-click on it
    UiObject video = videos.getChildByText(new UiSelector()
            .className("android.widget.LinearLayout"), "Cute Baby Laughing");
    video.click();

    // Simulate selecting a checkbox that is associated with the video
    UiObject checkBox = video.getChild(new UiSelector()
            .className("android.widget.Checkbox"));
    if(!checkBox.isSelected()) checkbox.click();
    

Menjalankan tindakan pada tampilan yang dapat di-scroll

Gunakan class UiScrollable untuk menyimulasikan scroll vertikal atau horizontal di seluruh tampilan. Teknik ini berguna bila elemen UI ditempatkan di belakang layar dan Anda perlu men-scroll untuk menampilkannya.

Cuplikan kode berikut menunjukkan cara menyimulasikan scroll ke bawah menu Setelan dan mengklik opsi Tentang tablet:

Kotlin

    val settingsItem = UiScrollable(UiSelector().className("android.widget.ListView"))
    val about: UiObject = settingsItem.getChildByText(
            UiSelector().className("android.widget.LinearLayout"),
            "About tablet"
    )
    about.click()
    

Java

    UiScrollable settingsItem = new UiScrollable(new UiSelector()
            .className("android.widget.ListView"));
    UiObject about = settingsItem.getChildByText(new UiSelector()
            .className("android.widget.LinearLayout"), "About tablet");
    about.click();
    

Memverifikasi hasil

InstrumentationTestCase memperluas TestCase, sehingga Anda dapat menggunakan metode Assert JUnit standar untuk menguji komponen UI dalam aplikasi yang menampilkan hasil yang diharapkan.

Cuplikan berikut menunjukkan cara pengujian Anda dapat menemukan beberapa tombol di aplikasi kalkulator, mengklik tombol tersebut secara berurutan, lalu memverifikasi bahwa hasil yang benar ditampilkan.

Kotlin

    private const val CALC_PACKAGE = "com.myexample.calc"

    fun testTwoPlusThreeEqualsFive() {
        // Enter an equation: 2 + 3 = ?
        device.findObject(UiSelector().packageName(CALC_PACKAGE).resourceId("two")).click()
        device.findObject(UiSelector().packageName(CALC_PACKAGE).resourceId("plus")).click()
        device.findObject(UiSelector().packageName(CALC_PACKAGE).resourceId("three")).click()
        device.findObject(UiSelector().packageName(CALC_PACKAGE).resourceId("equals")).click()

        // Verify the result = 5
        val result: UiObject2 = device.findObject(By.res(CALC_PACKAGE, "result"))
        assertEquals("5", result.text)
    }
    

Java

    private static final String CALC_PACKAGE = "com.myexample.calc";

    public void testTwoPlusThreeEqualsFive() {
        // Enter an equation: 2 + 3 = ?
        device.findObject(new UiSelector()
                .packageName(CALC_PACKAGE).resourceId("two")).click();
        device.findObject(new UiSelector()
                .packageName(CALC_PACKAGE).resourceId("plus")).click();
        device.findObject(new UiSelector()
                .packageName(CALC_PACKAGE).resourceId("three")).click();
        device.findObject(new UiSelector()
                .packageName(CALC_PACKAGE).resourceId("equals")).click();

        // Verify the result = 5
        UiObject result = device.findObject(By.res(CALC_PACKAGE, "result"));
        assertEquals("5", result.getText());
    }
    

Menjalankan pengujian UI Automator pada perangkat atau emulator

Anda dapat menjalankan pengujian UI Automator dari Android Studio atau dari command line. Pastikan untuk menentukan AndroidJUnitRunner sebagai runner instrumentasi default dalam project Anda.

Referensi lainnya

Untuk mengetahui informasi selengkapnya tentang penggunaan UI Automator dalam pengujian Android, lihat referensi berikut.

Contoh

Codelab