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 mencakup cara menulis pengujian UI tersebut 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 pun yang difokuskan. 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 bekerja dengan test runner 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, periksa apakah komponen ini 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
:
- Luncurkan aplikasi target di perangkat fisik.
- Hubungkan perangkat ke mesin pengembangan Anda.
- Buka jendela terminal dan buka direktori
<android-sdk>/tools/
. - Jalankan fitur tersebut dengan perintah ini:
$ uiautomatorviewer
Untuk melihat properti UI untuk aplikasi Anda:
- Di antarmuka
uiautomatorviewer
, klik tombol Device Screenshot. - Arahkan kursor ke panel sebelah kiri snapshot untuk melihat komponen UI yang diidentifikasi oleh fitur
uiautomatorviewer
. Properti dicantumkan di panel kanan bawah dan hierarki tata letak di panel kanan atas. - (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 menerapkan fitur aksesibilitas Android. Saat menggunakan elemen UI jenis View
, atau subclass View
dari SDK, Anda tidak perlu menerapkan dukungan aksesibilitas, karena class ini sudah 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 dari subclass View
yang bukan dari SDK, pastikan untuk menambahkan fitur aksesibilitas ke elemen ini dengan melakukan langkah berikut:
- Buat class konkret yang memperluas
ExploreByTouchHelper
. - Kaitkan instance dari class baru Anda dengan elemen UI kustom 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 penggujian Anda. Anda juga harus menentukan class AndroidJUnitRunner
, yang disediakan di AndroidX Test, sebagai test runner 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:
- Dapatkan objek
UiDevice
untuk mengakses perangkat yang ingin Anda uji, dengan memanggil metodegetInstance()
dan meneruskan objekInstrumentation
sebagai argumen. - Dapatkan objek
UiObject
untuk mengakses komponen UI yang ditampilkan pada perangkat (misalnya, tampilan saat ini di latar depan), dengan memanggil metodefindObject()
. - Simulasikan interaksi pengguna tertentu untuk dijalankan pada komponen UI tersebut, dengan memanggil metode
UiObject
; misalnya, panggilperformMultiPointerGesture()
untuk menyimulasikan gerakan multi-sentuh, dansetText()
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. - 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 untuk mengakses dan memanipulasi status perangkat. Dalam pengujian, Anda bisa memanggil metode UiDevice
untuk memeriksa status berbagai properti, misalnya orientasi saat ini atau ukuran tampilan.
Pengujian Anda dapat menggunakan objek UiDevice
untuk menjalankan tindakan tingkat perangkat, misalnya memaksa perangkat berpindah ke rotasi tertentu, menekan tombol fisik D-pad, dan menekan tombol Menu dan Beranda.
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 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 ini, pernyataan @SdkSuppress(minSdkVersion = 18)
membantu memastikan bahwa pengujian hanya akan berjalan pada perangkat yang menggunakan Android 4.3 (API level 18) atau 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 dari pengujian aplikasi Anda, sesuai kebutuhan. Perhatikan bahwa framework pengujian UI Automator mencari tampilan saat ini untuk pencocokan setiap kali pengujian Anda menggunakan instance UiObject
untuk mengklik elemen UI atau mengkueri properti.
Cuplikan berikut menunjukkan bagaimana 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 ini menunjukkan bagaimana pengujian Anda dapat menentukan penelusuran untuk menemukan ListView
pertama di 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 dapat tidak menskala di berbagai bahasa; pemilih teks Anda mungkin tidak cocok dengan string yang diterjemahkan.
Hal tersebut mungkin berguna untuk menentukan status objek dalam kriteria pemilih Anda. Misalnya, jika ingin memilih daftar semua elemen yang dicentang sehingga Anda dapat menghapus centangnya, panggil metode checked()
dengan argumen yang ditetapkan ke true
.
Menjalankan tindakan
Setelah pengujian menerima 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:
-
click()
: Mengklik di tengah bagian yang terlihat dari elemen UI. -
dragTo()
: Menarik objek ini ke koordinat arbitrer. -
setText()
: Menyetel teks dalam kolom yang dapat diedit, setelah menghapus konten kolom. Sebaliknya, metodeclearTextField()
menghapus teks yang ada di kolom yang dapat diedit. -
swipeUp()
: Menjalankan tindakan geser ke atas padaUiObject
. Begitu juga, metodeswipeDown()
,swipeLeft()
, danswipeRight()
akan menjalankan tindakan yang sesuai.
Framework pengujian UI Automator memungkinkan Anda mengirim Intent
atau meluncurkan Activity
tanpa menggunakan perintah shell, dengan mendapatkan objek Context
melalui getContext()
.
Cuplikan berikut menunjukkan bagaimana pengujian Anda dapat menggunakan Intent
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 ingin menyimulasikan interaksi pengguna pada koleksi item (misalnya, lagu dalam suatu album musik atau daftar email di Kotak Masuk). Untuk membuat objek UiCollection
, tetapkan UiSelector
yang akan menelusuri container UI atau wrapper elemen UI turunan lainnya, misalnya 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 pada 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 bahwa komponen UI dalam aplikasi menampilkan hasil yang diharapkan.
Cuplikan berikut menunjukkan bagaimana 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 di project Anda.
Referensi lainnya
Untuk mengetahui informasi selengkapnya tentang penggunaan UI Automator dalam pengujian Android, lihat referensi berikut.
Contoh
- BasicSample: Contoh dasar UI Automator.