Uygulama İşlemleri Test Kitaplığı

Uygulama İşlemleri test kitaplığı (AATL), geliştiricilerin normalde gerçek sesli sorgular veya Uygulama İşlemleri test aracı kullanılarak yapılacak testleri otomatikleştirerek uygulama işleminin yerine getirilmesini programatik olarak test etmelerini sağlayan özellikler sunar.

Kitaplık, shortcut.xml yapılandırmasının doğru olmasını ve açıklanan Android intent çağrısının başarılı olmasını sağlar. Uygulama İşlemleri Test Kitaplığı uygulamanızın, belirli Google Asistan amacını ve parametrelerini Android derin bağlantısına dönüştürerek veya Android'i örneklendirmek için iddia edilebilen ve kullanılabilecek Android niyeti etkinliği'ne dokunun.

Test, Android ortamında Robolectric birim veya araçla test şeklinde gerçekleştirilir. Bu, geliştiricilerin kullandıkları her bir gerçek uygulama davranışını taklit ederek. BII'leri, özel intent'leri veya derin bağlantı yerine getirmeyi test etmek için herhangi bir enstrümante test çerçevesi (UI Automator, Espresso, JUnit4, Appium, Detox, Calabash) kullanılabilir.

Uygulama çok dilliyse geliştiriciler, uygulamanın işlevinin farklı yerel ayarlarda doğru şekilde çalıştığını doğrulayabilir.

İşleyiş şekli

Geliştiricilerin, uygulamanın test ortamına App Actions Test Kitaplığı'nı entegre edebilmesi için uygulamanın appmodülünde yeni Robolectric veya enstrümante edilmiş testler oluşturması ya da mevcut testleri güncellemesi gerekir.

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

  • Ortak kurulum yönteminde veya ayrı test durumlarında kitaplık örneğinin başlatılması.
  • Her test, intent oluşturma sonucunu üretmek için kitaplık örneğinin fulfill yöntemini çağırır.
  • Geliştirici daha sonra derin bağlantıyı belirtir veya uygulama yerine getirme işlemini tetikler ve uygulama durumunda özel doğrulama yapar.

Kurulum gereksinimleri

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

Yapılandırma

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

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

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

  1. Google deposunu şuradaki proje depoları listesine ekleyin: settings.gradle:

        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. Robolectric testlerini 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. ActivityScenario yöntemini kullanan Espresso örneğini aşağıda bulabilirsiniz:

    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 parametrelerini değiştirebilirsiniz. Örneğin, exercisePlan.forExercise.name, GET_EXERCISE_PLAN parametresinin dokümanıyla eşleşir.

  3. Android Bağlam parametresiyle (alınan kaynak: ApplicationProvider veya InstrumentationRegistry):

    • 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 nesne algılandı.

İddialarda bulunma

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

  1. AppActionsFulfillmentResult sipariş karşılama türünü belirtin. Yapması gerekenler FulfillmentType.INTENT veya FulfillmentType.UNFULFILLED olması beklenmedik BII istekleri durumunda uygulamanın nasıl davrandığını test etmek için kullanılır.
  2. 2 tür istek karşılama vardır: INTENT ve DEEPLINK istek karşılamaları.
    • Normalde geliştirici, kitaplığı tetikleyerek yerine getirdiği shortcuts.xml'deki intent etiketine bakarak INTENT ve DEEPLINK yerine getirmeleri arasında ayrım yapabilir.
    • Niyet etiketinin altında bir url şablonu etiketi varsa bu durum DEEPLINK, bu amacı gerçekleştiriyor.
    • Sonuç amacının getData() yöntemi boş olmayan bir nesne döndürüyorsa bu,DEEPLINK yerine getirildiğini de gösterir. Benzer şekilde, getData null değerini döndürürse INTENT sipariş karşılama olduğu anlamına gelir.
  3. INTENT durumu için AppActionsFulfillmentResult'u AppActionsIntentFulfillmentResult olarak türüne dönüştürün, getIntent yöntemini çağırarak Android Intent'i alın ve aşağıdakilerden birini yapın:
    • Android Intent'in bağımsız alanlarını iddia edin.
    • Üzerinden erişilen bir intent'in URI'sını iddia edin intent.getData.getHost yöntemini kullanarak devam edin.
  4. DEEPLINK destek kaydı için AppActionsFulfillmentResult yazıp şu değere yazın: AppActionsIntentFulfillmentResult (INTENT senaryosuyla aynı) yukarıda belirtilen şekilde) getIntent yöntemini çağırarak Android Intent'i getirin ve derin bağlantı URL'sini (intent.getData.getHost üzerinden erişilir).
  5. Hem INTENT hem de DEEPLINK için, elde edilen niyeti kullanarak lansman yapabilirsiniz. bu etkinliği, seçilen Android test çerçevesiyle oluşturuyoruz.

Uluslararası hale getirme

Uygulamanızın birden fazla yerel ayarı varsa testleri belirli bir uygulamayı çalıştıracak şekilde yapılandırabilirsiniz. yerel ayar altında test ediliyor. 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);
    
  

İspanyolca (ES) yerel ayarı için yapılandırılmış bir AATL testi örneği aşağıda 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.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");
      }
      
    

Sorunu giderin

Entegrasyon testiniz beklenmedik bir şekilde başarısız olursa uyarı veya hata düzeyi mesajını 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 kaydetme düzeyini de artırabilirsiniz.

Sınırlamalar

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

  • AATL, doğal dil anlama (NLU) veya konuşma metne dönüştürme (STT) özelliklerini test etmez.
  • Testler varsayılan uygulamanın dışındaki modüllerde olduğunda AATL çalışmaz modülünü kullanabilirsiniz.
  • AATL yalnızca Android 7.0 "Nougat" (API düzeyi 24) ve sonraki sürümlerle uyumludur.