توفّر مكتبة اختبار "إجراءات التطبيقات" (AATL) إمكانات لتمكين المطوّرين من اختبار تنفيذ "إجراءات التطبيقات" آليًا، ما يؤدي إلى برمجة الاختبار الذي يتم عادةً باستخدام طلبات صوتية فعلية أو أداة اختبار "إجراءات التطبيقات".
تساعد المكتبة في التأكّد من أنّ إعدادات shortcut.xml
صحيحة
ونجاح عملية استدعاء أهداف Android الموضّحة الموضّحة. توفّر "مكتبة اختبار الإجراءات في التطبيقات" آلية لاختبار قدرة تطبيقك على تحقيق أهداف "مساعد Google" ومعاييره المحدّدة، من خلال تحويلها إلى رابط لصفحة في تطبيق Android أو إلى هدف Android يمكن تأكيده واستخدامه لإنشاء مثيل لأحد أنشطة Android.
يتم إجراء الاختبار في شكل وحدة Robolectric أو اختبارات مدمَجة في بيئة Android. ويتيح ذلك للمطورين اختبار تطبيقاتهم بشكل شامل من خلال محاكاة سلوك التطبيق الفعلي. لاختبار BII أو نية الشراء المخصّصة أو تنفيذ الروابط لصفحات معيّنة، يمكن استخدام أي إطار اختبار مبرمج (UI Automator وEspresso وJUnit4 وAppium وDetox وCalabash).
إذا كان التطبيق متعدد اللغات، يمكن للمطوّرين التحقّق من عمل وظائف التطبيق بشكل صحيح في لغات مختلفة.
طريقة العمل
لدمج مكتبة اختبار إجراءات التطبيق في بيئة اختبار التطبيق، على المطوّرين إنشاء اختبارات Robolectric أو اختبارات جديدة أو تعديل الاختبارات الحالية في وحدة app
للتطبيق.
يحتوي الرمز التجريبي على الأجزاء التالية:
- تهيئة مثيل المكتبة، في طريقة الإعداد الشائعة، أو في حالات الاختبار الفردية.
- يستدعي كل اختبار فردي طريقة
fulfill
لمثيل المكتبة للحصول على نتيجة إنشاء الغرض. - ويؤكِّد المطوّر بعد ذلك على الرابط لصفحة معيّنة في التطبيق أو يشغِّل عملية تنفيذ التطبيق، وينفِّذ عملية تحقّق مخصَّصة على حالة التطبيق.
متطلّبات الإعداد
لاستخدام مكتبة الاختبار، هناك بعض الإعدادات الأولية للتطبيق المطلوبة قبل إضافة الاختبارات إلى تطبيقك.
الإعدادات
لاستخدام "مكتبة اختبار الإجراءات في التطبيقات"، تأكّد من ضبط تطبيقك على النحو التالي:
- تثبيت المكوّن الإضافي Android Gradle الإضافي (AGP)
- ضمِّن ملف
shortcuts.xml
في المجلدres/xml
في الوحدةapp
. - تأكَّد من أنّ
AndroidManifest.xml
تتضمّن<meta-data android:name="android.app.shortcuts" android:resource=”@xml/shortcuts” />
ضمن أي مما يلي:- العلامة
<application>
- علامة
<activity>
لمشغِّل التطبيقات
- العلامة
- يمكنك وضع العنصر
<capability>
داخل العنصر<shortcuts>
فيshortcuts.xml
.
إضافة العناصر الاعتمادية لمكتبة اختبار الإجراءات في التطبيقات
إضافة مستودع Google إلى قائمة مستودعات المشاريع في
settings.gradle
:allprojects { repositories { … google() } }
في ملف
build.gradle
في وحدة التطبيق، أضِف تبعيات AATL:androidTestImplementation 'com.google.assistant.appactions:testing:1.0.0'
احرص على استخدام رقم إصدار المكتبة التي نزّلتها.
إنشاء اختبارات دمج
إنشاء اختبارات جديدة ضمن
app/src/androidTest
. بالنسبة لاختبارات Robolectric، يمكنك إنشاؤها ضمن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…") }
إذا كنت تستخدم الإسبريسو، ستحتاج إلى تعديل طريقة إطلاق النشاط بناءً على نتائج AATL. في ما يلي مثال لقهوة إسبرسو باستخدام طريقة
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…")))
أن يتطابق الاسم والخصائص الرئيسية في تعيينات المعلَمات مع المعلَمات من BII. على سبيل المثال، تتطابق السمة
order.orderedItem.name
مع الوثائق الخاصة بالمَعلمة فيGET_ORDER
.إنشاء مثيل واجهة برمجة التطبيقات باستخدام مَعلمة سياق Android (التي تم الحصول عليها من
ApplicationProvider
أوInstrumentationRegistry
):- بنية التطبيق التي تستخدم وحدة واحدة:
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); }
- بنية التطبيق متعدّدة الوحدات:
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)); }
نفِّذ طريقة
fulfill
لواجهة برمجة التطبيقات واحصل على الكائنAppActionsFulfillmentResult
.
تنفيذ التأكيدات
الطريقة المُقترَحة لتأكيد مكتبة اختبار الإجراءات في التطبيقات هي:
- أكِّد نوع تنفيذ
AppActionsFulfillmentResult
. يجب أن يكونFulfillmentType.INTENT
أوFulfillmentType.UNFULFILLED
لاختبار سلوك التطبيق في حال حدوث طلبات غير متوقعة من BII. - ثمة طريقتان لتنفيذ الطلب:
INTENT
وDEEPLINK
.- يمكن عادةً لمطوّر البرامج التمييز بين عمليات تنفيذ
INTENT
وDEEPLINK
من خلال الاطّلاع على علامة النية فيshortcuts.xml
التي يفي بها من خلال تفعيل المكتبة. - إذا كانت هناك علامة نموذج عنوان URL ضمن علامة النية، هذا يشير إلى أن
DEEPLINK
تحقق هذا الهدف. - إذا كانت طريقة
getData()
لغرض النتيجة تعرض كائنًا غير فارغ، يشير هذا أيضًا إلى تنفيذDEEPLINK
. وبالمثل، إذا عرضgetData
null
، يعني ذلك أنّه تنفيذINTENT
.
- يمكن عادةً لمطوّر البرامج التمييز بين عمليات تنفيذ
- في حالة
INTENT
، عليك استرجاع typecastAppActionsFulfillmentResult
إلىAppActionsIntentFulfillmentResult
من خلال استدعاء طريقة Android Intent من خلال استدعاء طريقةgetIntent
وتنفيذ أحد الإجراءات التالية:- التأكيد على حقول فردية في Android Intent
- أكِّد معرّف الموارد المنتظم (URI) لعنصر يتم الوصول إليه من خلال طريقة intent.getData.getHost.
- بالنسبة إلى حالة
DEEPLINK
، عليك تحويل النوع منAppActionsFulfillmentResult
إلىAppActionsIntentFulfillmentResult
(كما هو الحال في سيناريوINTENT
أعلاه)، واسترجاع هدف Android من خلال استدعاء طريقةgetIntent
وتأكيد عنوان URL لرابط لصفحة معيّنة (يتم الوصول إليه من خلالintent.getData.getHost
). - بالنسبة إلى كل من
INTENT
وDEEPLINK
، يمكنك استخدام الغرض الناتج لإطلاق النشاط باستخدام إطار عمل اختبار Android الذي تم اختياره.
التوافق مع أسواق عالمية
إذا كان تطبيقك يحتوي على لغات متعددة، يمكنك ضبط إعدادات الاختبارات لتشغيل لغة محدّدة تخضع للاختبار. بدلاً من ذلك، يمكنك تغيير اللغة مباشرةً:
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);
في ما يلي مثال على اختبار AATL تم إعداده للّغة الإسبانية (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"); }
تحديد المشاكل وحلّها
إذا تعذّر اختبار الدمج بشكلٍ غير متوقع، يمكنك البحث عن رسائل سجلّ AATL في نافذة Logcat في "استوديو Android" للحصول على رسالة التحذير أو الخطأ على مستوى الخطأ. يمكنك أيضًا زيادة مستوى التسجيل للحصول على مزيد من المخرجات من المكتبة.
القيود
في ما يلي القيود الحالية على مكتبة اختبارات الإجراءات في التطبيقات :
- لا يختبر AATL ميزات فهم اللغة الطبيعية (NLU) أو تحويل الكلام إلى نص (STT).
- لا تعمل AATL عندما تكون الاختبارات في وحدات أخرى غير وحدة التطبيق الافتراضية.
- تتوافق تقنية AATL فقط مع نظام التشغيل Android 7.0 "Nougat" (المستوى 24 من واجهة برمجة التطبيقات) والإصدارات الأحدث.