Library Pengujian Action Aplikasi

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 kerja

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 folder res/xml di modul app.
  • Pastikan AndroidManifest.xml menyertakan <meta-data android:name="android.app.shortcuts" android:resource=”@xml/shortcuts” /> dalam:
    • tag <application>
    • tag <activity> peluncur
  • Tempatkan elemen <capability> di dalam elemen <shortcuts> di shortcuts.xml

Menambahkan dependensi Library Pengujian Action Aplikasi

  1. Tambahkan repositori Google ke daftar repositori project di settings.gradle:

        allprojects {
            repositories {
                …
                google()
            }
        }
    
  2. 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

  1. Buat pengujian baru di bagian app/src/androidTest. Untuk pengujian Robolectric, buat pengujian baru di bagian app/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…")))
        
    
  2. Pastikan nama dan properti kunci dalam pemetaan parameter sama dengan parameter dari BII. Misalnya, order.orderedItem.name sama dengan dokumentasi untuk parameter di GET_ORDER.

  3. Buat instance API dengan parameter Konteks Android (diperoleh dari ApplicationProvider atau InstrumentationRegistry):

    • 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));
          }
        
      
  4. Jalankan metode fulfill API dan dapatkan objek AppActionsFulfillmentResult.

Menjalankan pernyataan

Cara yang disarankan untuk menyatakan Library Pengujian Action Aplikasi adalah:

  1. Nyatakan jenis fulfillment AppActionsFulfillmentResult. Jenis fulfillment harus berupa FulfillmentType.INTENT, atau FulfillmentType.UNFULFILLED agar dapat menguji perilaku aplikasi jika terjadi permintaan BII yang tidak terduga.
  2. Ada 2 ragam fulfillment: fulfillment INTENT dan DEEPLINK.
    • Biasanya, developer dapat membedakan antara fulfillment INTENT dan DEEPLINK dengan melihat tag intent di shortcuts.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 fulfillment DEEPLINK. Demikian pula, jika getData menampilkan null, berarti itu adalah fulfillment INTENT.
  3. Untuk kasus INTENT, ubah AppActionsFulfillmentResult menjadi AppActionsIntentFulfillmentResult, ambil Intent Android dengan memanggil metode getIntent, lalu lakukan salah satu hal berikut:
    • Nyatakan masing-masing kolom Intent Android.
    • Nyatakan URI intent yang diakses melalui metode intent.getData.getHost.
  4. Untuk kasus DEEPLINK, ubah AppActionsFulfillmentResult menjadi AppActionsIntentFulfillmentResult (sama seperti untuk skenario INTENT di atas), ambil Intent Android dengan memanggil metode getIntent dan nyatakan URL deeplink (diakses melalui intent.getData.getHost).
  5. Untuk INTENT dan DEEPLINK, 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.ORDER_MENU_ITEM"
          val intentParams = ImmutableMap.of("menuItem.name", "hamburguesa con queso")

          val result = aatl.fulfill(intentName, intentParams)
          assertThat(result.getFulfillmentType()).isEqualTo(FulfillmentType.INTENT)

          val intentResult = result as AppActionsFulfillmentIntentResult

          assertThat(intentResult.getIntent().getData().toString())
            .isEqualTo("myfoodapp://browse?food=food_hamburger")
        }
      }
      
    

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.ORDER_MENU_ITEM";
        ImmutableMap<String, String> intentParams = ImmutableMap.of("menuItem.name", "hamburguesa con queso");

        AppActionsFulfillmentResult result = aatl.fulfill(intentName, intentParams);
        assertThat(result.getFulfillmentType()).isEqualTo(FulfillmentType.INTENT);

        AppActionsFulfillmentIntentResult intentResult = (AppActionsFulfillmentIntentResult) result;

        assertThat(intentResult.getIntent().getData().toString())
          .isEqualTo("myfoodapp://browse?food=food_hamburger");
      }
      
    

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.