Library pengujian Action Aplikasi (AATL) menyediakan kemampuan bagi developer untuk menguji fulfillment Action Aplikasi secara terprogram, yang mengotomatiskan pengujian yang biasanya dilakukan menggunakan kueri suara sebenarnya atau alat pengujian Action Aplikasi.
Library ini membantu memastikan bahwa konfigurasi shortcut.xml
sudah benar dan
pemanggilan intent Android yang dijelaskan berhasil. Library Pengujian Action Aplikasi
menyediakan mekanisme untuk menguji kemampuan aplikasi Anda dalam memenuhi intent
dan parameter Asisten Google tertentu, dengan mengonversinya menjadi deep link Android atau
intent Android yang dapat dinyatakan dan digunakan untuk membuat instance aktivitas
Android.
Pengujian dilakukan dalam bentuk uji unit Robolectric atau uji instrumentasi di lingkungan Android. Ini membuat developer dapat menguji aplikasi secara komprehensif dengan mengemulasi perilaku aplikasi yang sebenarnya. Semua framework uji instrumentasi (UI Automator, Espresso, JUnit4, Appium, Detox, Calabash) dapat digunakan untuk menguji BII, intent kustom, atau fulfillment deep link.
Jika aplikasi tersedia dalam beberapa bahasa, developer dapat memvalidasi bahwa fungsi aplikasi bekerja dengan benar di lokalitas yang berbeda.
Cara kerjanya
Untuk mengintegrasikan Library Pengujian Action Aplikasi dalam lingkungan pengujian aplikasi, developer harus
membuat uji instrumentasi atau Robolectric yang baru atau mengupdate yang sudah ada di modul
app
aplikasi.
Kode pengujian berisi bagian berikut:
- Inisialisasi instance library, dalam metode penyiapan umum atau dalam masing-masing kasus pengujian.
- Setiap pengujian memanggil metode
fulfill
dari instance library untuk memproduksi hasil pembuatan intent. - Kemudian, developer menyatakan deep link atau memicu fulfillment Aplikasi, dan menjalankan validasi kustom pada status aplikasi.
Persyaratan penyiapan
Untuk menggunakan library pengujian, ada beberapa konfigurasi aplikasi awal yang diperlukan sebelum menambahkan pengujian ke aplikasi Anda.
Konfigurasi
Untuk menggunakan Library Pengujian Action Aplikasi, pastikan aplikasi Anda dikonfigurasi sebagai berikut:
- Instal Plugin Android Gradle (AGP)
- Sertakan file
shortcuts.xml
dalam folderres/xml
di modulapp
. - Pastikan
AndroidManifest.xml
menyertakan<meta-data android:name="android.app.shortcuts" android:resource=”@xml/shortcuts” />
dalam:- tag
<application>
- tag
<activity>
peluncur
- tag
- Tempatkan elemen
<capability>
di dalam elemen<shortcuts>
dishortcuts.xml
Menambahkan dependensi Library Pengujian Action Aplikasi
Tambahkan repositori Google ke daftar repositori project di
settings.gradle
:allprojects { repositories { … google() } }
Dalam file
build.gradle
modul aplikasi, tambahkan dependensi AATL:androidTestImplementation 'com.google.assistant.appactions:testing:1.0.0'
Pastikan untuk menggunakan nomor versi library yang sudah Anda download.
Membuat pengujian integrasi
Buat pengujian baru di bagian
app/src/androidTest
. Untuk pengujian Robolectric, buat pengujian baru di bagianapp/src/test
:Kotlin
import android.content.Context import android.content.Intent import android.widget.TextView import androidx.test.core.app.ApplicationProvider import androidx.test.core.app.ActivityScenario import com.google.assistant.appactions.testing.aatl.AppActionsTestManager import com.google.assistant.appactions.testing.aatl.fulfillment.AppActionsFulfillmentIntentResult import com.google.assistant.appactions.testing.aatl.fulfillment.AppActionsFulfillmentResult import com.google.assistant.appactions.testing.aatl.fulfillment.FulfillmentType import com.google.common.collect.ImmutableMap import org.junit.Assert.assertEquals import org.junit.Before import org.junit.runner.RunWith import org.junit.Test import org.robolectric.RobolectricTestRunner … @Test fun IntentTestExample() { val intentParams = mapOf("feature" to "settings") val intentName = "actions.intent.OPEN_APP_FEATURE" val result = aatl.fulfill(intentName, intentParams) assertEquals(FulfillmentType.INTENT, result.getFulfillmentType()) val intentResult = result as AppActionsFulfillmentIntentResult val intent = intentResult.intent // Developer can choose to assert different relevant properties of the returned intent, such as the action, activity, package, scheme and so on assertEquals("youtube", intent.scheme) assertEquals("settings", intent.getStringExtra("featureParam")) assertEquals("actions.intent.OPEN_APP_FEATURE", intent.action) assertEquals("com.google.android.youtube/.MainActivity", intent.component.flattenToShortString()) assertEquals("com.google.myapp", intent.package) // Developers can choose to use returned Android Intent to launch and assess the activity. Below are examples for how it will look like for Robolectric and Espresso tests. // Please note that the below part is just a possible example of how Android tests are validating Activity functionality correctness for given Android Intent. // Robolectric example: val activity = Robolectric.buildActivity(MainActivity::class.java, intentResult.intent).create().resume().get() val title: TextView = activity.findViewById(R.id.startActivityTitle) assertEquals(title?.text?.toString(), "Launching…") }
Java
import android.content.Context; import android.content.Intent; import android.widget.TextView; import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ActivityScenario; import com.google.assistant.appactions.testing.aatl.AppActionsTestManager; import com.google.assistant.appactions.testing.aatl.fulfillment.AppActionsFulfillmentIntentResult; import com.google.assistant.appactions.testing.aatl.fulfillment.AppActionsFulfillmentResult; import com.google.assistant.appactions.testing.aatl.fulfillment.FulfillmentType; import com.google.common.collect.ImmutableMap; import org.junit.Assert.assertEquals; import org.junit.Before; import org.junit.runner.RunWith; import org.junit.Test; import org.robolectric.RobolectricTestRunner; ... @Test public void IntentTestExample() throws Exception { Map<String, String> intentParams = ImmutableMap.of("feature", "settings"); String intentName = "actions.intent.OPEN_APP_FEATURE"; AppActionsFulfillmentResult result = aatl.fulfill(intentName, intentParams); assertEquals(FulfillmentType.INTENT, result.getFulfillmentType()); AppActionsFulfillmentIntentResult intentResult = (AppActionsFulfillmentIntentResult) result; Intent intent = intentResult.getIntent(); // Developer can choose to assert different relevant properties of the returned intent, such as the action, activity, package, or scheme assertEquals("settings", intent.getStringExtra("featureParam")); assertEquals("actions.intent.OPEN_APP_FEATURE", intent.getAction()); assertEquals("com.google.android.youtube/.MainActivity", intent.getComponent().flattenToShortString()); assertEquals("com.google.myapp", intent.getPackage()); // Developers can choose to use returned Android Intent to launch and assess the activity. Below are examples for how it will look like for Robolectric and Espresso tests. // Please note that the below part is just a possible example of how Android tests are validating Activity functionality correctness for given Android Intent. // Robolectric example: MainActivity activity = Robolectric.buildActivity(MainActivity.class,intentResult.intent).create().resume().get(); TextView title: TextView = activity.findViewById(R.id.startActivityTitle) assertEquals(title?.getText()?.toString(), "Launching…") }
Jika menggunakan Espresso, Anda perlu mengubah cara meluncurkan Aktivitas berdasarkan hasil AATL. Berikut adalah contoh untuk Espresso yang menggunakan metode
ActivityScenario
:Kotlin
ActivityScenario.launch<MainActivity>(intentResult.intent); Espresso.onView(ViewMatchers.withId(R.id.startActivityTitle)) .check(ViewAssertions.matches(ViewMatchers.withText("Launching…")))
Java
ActivityScenario.launch<MainActivity>(intentResult.intent); Espresso.onView(ViewMatchers.withId(R.id.startActivityTitle)) .check(ViewAssertions.matches(ViewMatchers.withText("Launching…")))
Pastikan nama dan properti kunci dalam pemetaan parameter sama dengan parameter dari BII. Misalnya,
exercisePlan.forExercise.name
sama dengan dokumentasi untuk parameter diGET_EXERCISE_PLAN
.Buat instance API dengan parameter Konteks Android (diperoleh dari
ApplicationProvider
atauInstrumentationRegistry
):- Arsitektur aplikasi modul tunggal:
Kotlin
private lateinit var aatl: AppActionsTestManager @Before fun init() { val appContext = ApplicationProvider.getApplicationContext() aatl = AppActionsTestManager(appContext) }
Java
private AppActionsTestManager aatl; @Before public void init() { Context appContext = ApplicationProvider.getApplicationContext(); aatl = new AppActionsTestManager(appContext); }
- Arsitektur aplikasi multi-modul:
Kotlin
private lateinit var aatl: AppActionsTestManager @Before fun init() { val appContext = ApplicationProvider.getApplicationContext() val lookupPackages = listOf("com.myapp.mainapp", "com.myapp.resources") aatl = AppActionsTestManager(appContext, lookupPackages) }
Java
private AppActionsTestManager aatl; @Before public void init() throws Exception { Context appContext = ApplicationProvider.getApplicationContext(); List<String> lookupPackages = Arrays.asList("com.myapp.mainapp","com.myapp.resources"); aatl = new AppActionsTestManager(appContext, Optional.of(lookupPackages)); }
Jalankan metode
fulfill
API dan dapatkan objekAppActionsFulfillmentResult
.
Menjalankan pernyataan
Cara yang disarankan untuk menyatakan Library Pengujian Action Aplikasi adalah:
- Nyatakan jenis fulfillment
AppActionsFulfillmentResult
. Jenis fulfillment harus berupaFulfillmentType.INTENT
, atauFulfillmentType.UNFULFILLED
agar dapat menguji perilaku aplikasi jika terjadi permintaan BII yang tidak terduga. - Ada 2 ragam fulfillment: fulfillment
INTENT
danDEEPLINK
.- Biasanya, developer dapat membedakan antara fulfillment
INTENT
danDEEPLINK
dengan melihat tag intent dishortcuts.xml
yang mereka penuhi dengan memicu library. - Adanya tag url-template di bawah tag intent menunjukkan
bahwa
DEEPLINK
memenuhi intent ini. - Jika metode
getData()
intent hasil menampilkan objek non-null, hal ini juga menunjukkan fulfillmentDEEPLINK
. Demikian pula, jikagetData
menampilkannull
, berarti itu adalah fulfillmentINTENT
.
- Biasanya, developer dapat membedakan antara fulfillment
- Untuk kasus
INTENT
, ubahAppActionsFulfillmentResult
menjadiAppActionsIntentFulfillmentResult
, ambil Intent Android dengan memanggil metodegetIntent
, lalu lakukan salah satu hal berikut:- Nyatakan masing-masing kolom Intent Android.
- Nyatakan URI intent yang diakses melalui metode intent.getData.getHost.
- Untuk kasus
DEEPLINK
, ubahAppActionsFulfillmentResult
menjadiAppActionsIntentFulfillmentResult
(sama seperti untuk skenarioINTENT
di atas), ambil Intent Android dengan memanggil metodegetIntent
dan nyatakan URL deeplink (diakses melaluiintent.getData.getHost
). - Untuk
INTENT
danDEEPLINK
, Anda dapat menggunakan intent yang dihasilkan untuk meluncurkan aktivitas dengan framework pengujian Android yang dipilih.
Internasionalisasi
Jika Aplikasi memiliki beberapa lokalitas, Anda dapat mengonfigurasi pengujian agar dijalankan pada lokalitas tertentu. Atau, Anda dapat mengubah lokalitas secara langsung:
Kotlin
import android.content.res.Configuration import java.util.Locale ... val newLocale = Locale("es") val conf = context.resources.configuration conf = Configuration(conf) conf.setLocale(newLocale)
Java
Locale newLocale = new Locale("es"); Configuration conf = context.getResources().getConfiguration(); conf = new Configuration(conf); conf.setLocale(newLocale);
Berikut adalah contoh pengujian AATL yang dikonfigurasi untuk lokalitas bahasa Spanyol (ES):
Kotlin
import com.google.common.truth.Truth.assertThat import org.junit.Assert.assertEquals import android.content.Context import android.content.res.Configuration import androidx.test.platform.app.InstrumentationRegistry import com.google.assistant.appactions.testing.aatl.AppActionsTestManager import com.google.assistant.appactions.testing.aatl.fulfillment.AppActionsFulfillmentIntentResult import com.google.assistant.appactions.testing.aatl.fulfillment.AppActionsFulfillmentResult import com.google.assistant.appactions.testing.aatl.fulfillment.FulfillmentType import com.google.common.collect.ImmutableMap import java.util.Locale import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner @RunWith(RobolectricTestRunner::class) class ShortcutForDifferentLocaleTest { @Before fun setUp() { val context = InstrumentationRegistry.getInstrumentation().getContext() // change the device locale to 'es' val newLocale = Locale("es") val conf = context.resources.configuration conf = Configuration(conf) conf.setLocale(newLocale) val localizedContext = context.createConfigurationContext(conf) } @Test fun shortcutForDifferentLocale_succeeds() { val aatl = AppActionsTestManager(localizedContext) val intentName = "actions.intent.GET_EXERCISE_PLAN" val intentParams = ImmutableMap.of("exercisePlan.forExercise.name", "Running") val result = aatl.fulfill(intentName, intentParams) assertThat(result.getFulfillmentType()).isEqualTo(FulfillmentType.INTENT) val intentResult = result as AppActionsFulfillmentIntentResult assertThat(intentResult.getIntent().getData().toString()) .isEqualTo("myexercise://browse?plan=running_weekly") } }
Java
import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import android.content.Context; import android.content.res.Configuration; import androidx.test.platform.app.InstrumentationRegistry; import com.google.assistant.appactions.testing.aatl.AppActionsTestManager; import com.google.assistant.appactions.testing.aatl.fulfillment.AppActionsFulfillmentIntentResult; import com.google.assistant.appactions.testing.aatl.fulfillment.AppActionsFulfillmentResult; import com.google.assistant.appactions.testing.aatl.fulfillment.FulfillmentType; import com.google.common.collect.ImmutableMap; import java.util.Locale; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; @Test public void shortcutForDifferentLocale_succeeds() throws Exception { Context context = InstrumentationRegistry.getInstrumentation().getContext(); // change the device locale to 'es' Locale newLocale = new Locale("es"); Configuration conf = context.getResources().getConfiguration(); conf = new Configuration(conf); conf.setLocale(newLocale); Context localizedContext = context.createConfigurationContext(conf); AppActionsTestManager aatl = new AppActionsTestManager(localizedContext); String intentName = "actions.intent.GET_EXERCISE_PLAN"; ImmutableMap<String, String> intentParams = ImmutableMap.of("exercisePlan.forExercise.name", "Running"); AppActionsFulfillmentResult result = aatl.fulfill(intentName, intentParams); assertThat(result.getFulfillmentType()).isEqualTo(FulfillmentType.INTENT); AppActionsFulfillmentIntentResult intentResult = (AppActionsFulfillmentIntentResult) result; assertThat(intentResult.getIntent().getData().toString()) .isEqualTo("myexercise://browse?plan=running_weekly"); }
Memecahkan masalah
Jika pengujian integrasi gagal secara tidak terduga, Anda dapat mencari pesan log AATL di jendela logcat Android Studio untuk melihat pesan peringatan atau level error. Anda juga dapat meningkatkan level logging untuk mengambil lebih banyak output dari library.
Batasan
Berikut adalah batasan Library Pengujian Action Aplikasi saat ini:
- AATL tidak menguji fitur Natural Language Understanding (NLU) atau Speech-to-text (STT).
- AATL tidak berfungsi jika pengujian berlangsung di luar modul aplikasi default.
- AATL hanya kompatibel dengan Android 7.0 "Nougat" (API level 24) dan yang lebih baru.