Uygulama İşlemleri Test Kitaplığı

Uygulama İşlemleri test kitaplığı (AATL), geliştiricilerin Uygulama İşlemi karşılama durumunu programatik olarak test etmesini sağlayan özellikler sunar. Böylece, normalde gerçek sesli sorgular veya Uygulama İşlemleri test aracı kullanılarak yapılacak testleri otomatik hale getirir.

Kitaplık, shortcut.xml yapılandırmasının doğru olduğundan ve açıklanan Android amaç çağrısının başarılı olduğundan emin olunmasına yardımcı olur. Uygulama İşlemleri Test Kitaplığı, uygulamanızın belirli Google Asistan amacını ve parametrelerini yerine getirme becerisini test etmek için bir mekanizma sağlar. Bunu, bunları bir Android derin bağlantısına veya Android amacına dönüştürerek, üzerinde hak iddia edip bir Android etkinliğini örneklendirmek için kullanabilirsiniz.

Test, Android ortamında Robofactric birimi veya donanımlı testler şeklinde gerçekleştirilir. Bu sayede geliştiriciler, gerçek uygulama davranışına öykünerek uygulamalarını kapsamlı bir şekilde test edebilirler. BiI'ları, özel niyetleri veya derin bağlantı karşılamayı test etmek için herhangi bir araçlı test çerçevesi kullanılabilir (UI Automator, Espresso, JUnit4, Appium, Detox, Calabash).

Uygulama çok dilliyse geliştiriciler uygulamanın işlevselliğinin farklı yerel ayarlarda düzgün çalıştığını doğrulayabilirler.

Nasıl çalışır?

Geliştiriciler, Uygulama İşlemleri Test Kitaplığı'nı uygulamanın test ortamına entegre etmek için uygulamanın app modülünde yeni Robofactric veya enstrümanlı testler oluşturmalı ya da mevcut testleri güncellemelidir.

Test kodu aşağıdaki bölümleri içerir:

  • Ortak kurulum yönteminde veya bağımsız test durumlarında kitaplık örneğinin başlatılması.
  • Her bir test, amaç oluşturma sonucunu oluşturmak için kitaplık örneğinin fulfill yöntemini çağırır.
  • Geliştirici daha sonra derin bağlantıyı onaylar veya Uygulama istek karşılamayı tetikler ve uygulama durumunda özel doğrulama çalıştırır.

Kurulum gereksinimleri

Test kitaplığını kullanmak için testleri uygulamanıza eklemeden önce bazı başlangıç uygulama yapılandırması gerekir.

Yapılandırma

Uygulama İşlemleri Test Kitaplığı'nı kullanmak için uygulamanızın aşağıdaki gibi yapılandırıldığından emin olun:

  • Android Gradle Eklentisi'ni (AGP) yükleyin
  • app modülündeki res/xml klasörüne bir shortcuts.xml dosyası ekleyin.
  • AndroidManifest.xml öğesinin, şunlardan birinin altında <meta-data android:name="android.app.shortcuts" android:resource=”@xml/shortcuts” /> içerdiğinden emin olun:
    • <application> etiketi
    • başlatıcı <activity> etiketi
  • <capability> öğesini shortcuts.xml alt kısmındaki <shortcuts> öğesinin içine yerleştirin

Uygulama İşlemleri Test Kitaplığı bağımlılıkları ekleme

  1. Google deposunu settings.gradle bölgesindeki proje depoları listesine ekleyin:

        allprojects {
            repositories {
                …
                google()
            }
        }
    
  2. Uygulama modülü build.gradle dosyasına AATL bağımlılıklarını ekleyin:

        androidTestImplementation 'com.google.assistant.appactions:testing:1.0.0'
    

    İndirdiğiniz kitaplığın sürüm numarasını kullandığınızdan emin olun.

Entegrasyon testleri oluşturma

  1. app/src/androidTest altında yeni testler oluşturun. Roboecric testleri için bunları app/src/test altında oluşturun:

    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…")
          }
      
    

    Espresso kullanıyorsanız AATL sonuçlarına göre Etkinliği başlatma şeklinizi değiştirmeniz gerekir. Aşağıda, ActivityScenario yöntemi kullanılan bir Espresso örneği verilmiştir:

    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. Parametre eşlemelerindeki ad ve anahtar özelliklerinin BII'deki parametrelerle eşleşmesini sağlayın. Örneğin order.orderedItem.name, GET_ORDER içindeki parametreyle ilgili dokümanlarla eşleşir.

  3. API örneğini Android Bağlam parametresiyle örneklendirme (ApplicationProvider veya InstrumentationRegistry üzerinden alınır):

    • Tek modüllü uygulama mimarisi:

    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);
          }
        
      
    • Çok modüllü uygulama mimarisi:

    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. API'nin fulfill yöntemini yürütün ve AppActionsFulfillmentResult nesnesini alın.

Onaylama işlemleri gerçekleştirme

Uygulama İşlemleri Test Kitaplığı'nı doğrulamak için önerilen yöntem:

  1. AppActionsFulfillmentResult sipariş karşılama türünü belirtin. Beklenmeyen BII istekleri durumunda uygulamanın nasıl davrandığını test etmek için FulfillmentType.INTENT veya FulfillmentType.UNFULFILLED olmalıdır.
  2. İki farklı sipariş karşılama türü vardır: INTENT ve DEEPLINK sipariş karşılama.
    • Normalde geliştirici, kitaplığı tetikleyerek yerine getirdiği shortcuts.xml intent etiketine bakarak INTENT ve DEEPLINK istek karşılamalarını ayırt edebilir.
    • Niyet etiketi altında bir URL şablonu etiketi varsa bu, DEEPLINK öğesinin bu amacı yerine getirdiğini gösterir.
    • Sonuç amacının getData() yöntemi null olmayan bir nesne döndürürse bu, DEEPLINK karşılamayı da gösterir. Benzer şekilde, getData null değerini döndürürse bu, bunun bir INTENT karşılama olduğu anlamına gelir.
  3. INTENT durumunda, AppActionsFulfillmentResult türünü AppActionsIntentFulfillmentResult'e yazın, getIntent yöntemini çağırarak Android Intent'i getirin ve aşağıdakilerden birini yapın:
    • Android Intent'in bağımsız alanları üzerinde hak iddia edin.
    • intent.getData.getHost yöntemiyle erişilen bir amacın URI'sini talep edin.
  4. DEEPLINK destek kaydı için AppActionsFulfillmentResult türünü AppActionsIntentFulfillmentResult adresine yazın (yukarıdaki INTENT senaryosuyla aynı şekilde), getIntent yöntemini çağırarak Android Intent'i getirin ve derin bağlantı URL'sini (intent.getData.getHost üzerinden erişildi) onaylayın.
  5. Hem INTENT hem de DEEPLINK için, sonuçta elde edilen amacı kullanarak etkinliği seçilen Android test çerçevesiyle başlatabilirsiniz.

Uluslararası hale getirme

Uygulamanızda birden fazla yerel ayar varsa testleri, belirli bir yerel ayarda test altında çalıştırılacak şekilde yapılandırabilirsiniz. Alternatif olarak, yerel ayarı doğrudan değiştirebilirsiniz:

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);
    
  

Burada, İspanyolca (ES) yerel ayarı için yapılandırılmış bir AATL testi örneği verilmiştir:

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");
      }
      
    

Sorunu giderin

Entegrasyon testiniz beklenmedik bir şekilde başarısız olursa uyarı veya hata düzeyi mesajı almak için Android Studio logcat penceresinde AATL günlük mesajlarını arayabilirsiniz. Kitaplıktan daha fazla çıkış yakalamak için günlük kaydı düzeyini de artırabilirsiniz.

Sınırlamalar

Uygulama İşlemleri Test Kitaplığı'nın mevcut sınırlamaları şunlardır :

  • AATL, Doğal Dil Anlama (NLU) veya Sesle Yazma (STT) özelliklerini test etmez.
  • Testler, varsayılan uygulama modülünün dışındaki modüllerde olduğunda AATL çalışmaz.
  • AATL yalnızca Android 7.0 "Nougat" (API düzeyi 24) ve daha yeni sürümlerle uyumludur.