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
fulfillyö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
appmodülündekires/xmlklasörüne birshortcuts.xmldosyası 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
Google deposunu şuradaki proje depoları listesine ekleyin:
settings.gradle:allprojects { repositories { … google() } }Uygulama modülü
build.gradledosyası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
app/src/androidTestaltında yeni testler oluşturun. Robolectric testleriniapp/src/testaltı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.
ActivityScenarioyö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…")))
Parametre eşlemelerindeki ad ve anahtar özelliklerinin parametrelerini değiştirebilirsiniz. Örneğin,
exercisePlan.forExercise.name,GET_EXERCISE_PLANparametresinin dokümanıyla eşleşir.Android Bağlam parametresiyle (alınan kaynak:
ApplicationProviderveyaInstrumentationRegistry):- 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)); }
API'nin
fulfillyöntemini yürütün veAppActionsFulfillmentResultnesne algılandı.
İddialarda bulunma
Uygulama İşlemleri Test Kitaplığı'nı doğrulamak için önerilen yöntem şu şekildedir:
AppActionsFulfillmentResultsipariş karşılama türünü belirtin. Yapması gerekenlerFulfillmentType.INTENTveyaFulfillmentType.UNFULFILLEDolması beklenmedik BII istekleri durumunda uygulamanın nasıl davrandığını test etmek için kullanılır.- 2 tür istek karşılama vardır:
INTENTveDEEPLINKistek karşılamaları.- Normalde geliştirici, kitaplığı tetikleyerek yerine getirdiği
shortcuts.xml'deki intent etiketine bakarakINTENTveDEEPLINKyerine 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,DEEPLINKyerine getirildiğini de gösterir. Benzer şekilde,getDatanulldeğerini döndürürseINTENTsipariş karşılama olduğu anlamına gelir.
- Normalde geliştirici, kitaplığı tetikleyerek yerine getirdiği
INTENTdurumu içinAppActionsFulfillmentResult'uAppActionsIntentFulfillmentResultolarak türüne dönüştürün,getIntentyö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.
DEEPLINKdestek kaydı içinAppActionsFulfillmentResultyazıp şu değere yazın:AppActionsIntentFulfillmentResult(INTENTsenaryosuyla aynı) yukarıda belirtilen şekilde)getIntentyöntemini çağırarak Android Intent'i getirin ve derin bağlantı URL'sini (intent.getData.getHostüzerinden erişilir).- Hem
INTENThem deDEEPLINKiç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.