توفّر مكتبة اختبارات "مهامّ في التطبيقات" (AATL) إمكانات تمكِّن المطوّرين لاختبار تنفيذ "إجراءات التطبيق" آليًا، وإجراء اختبارات مبرمَجة عادةً باستخدام طلبات البحث الصوتية الفعلية أو أداة اختبار مهام التطبيق.
تساعد المكتبة في التأكّد من صحة إعدادات shortcut.xml
و
نجاح استدعاء نية Android الموضّح. توفّر "مكتبة اختبار إجراءات التطبيقات"
آلية لاختبار قدرة تطبيقك على تنفيذ نية ومعايير "مساعد Google" المحدّدة، وذلك من خلال تحويلها إلى رابط لموضع معيّن في تطبيق Android أو
نية Android، والتي يمكن تأكيدها واستخدامها لإنشاء مثيل لنشاط
Android.
يتم إجراء الاختبار على شكل وحدات Robolectric أو اختبارات مزوّدة بأدوات في بيئة Android. وهذا يتيح للمطوّرين إجراء اختبارات شاملة التطبيق من خلال محاكاة السلوك الفعلي للتطبيق. لاختبار عناوين URL لصفحات في التطبيق أو طلبات ملف شخصي مخصّصة أو عمليات إكمال روابط صفحات في التطبيق، يمكن استخدام أي إطار عمل اختبار مزوّد بأدوات اختبار (UI Automator أو Espresso أو JUnit4 أو Appium أو Detox أو Calabash).
وإذا كان التطبيق متعدد اللغات، فيمكن للمطورين التحقق من أن التطبيق تعمل وظيفة التطبيق بشكل صحيح في اللغات المختلفة.
آلية العمل
لدمج مكتبة اختبار مهام التطبيق في بيئة اختبار التطبيق، على المطوّرين
إنشاء اختبارات جديدة أو تعديل اختبارات Robolectric أو المسجَّلة حاليًا على app
التطبيق.
يحتوي رمز الاختبار على الأجزاء التالية:
- بدء تشغيل مثيل المكتبة، في طريقة الإعداد الشائعة أو في حالات الاختبار الفردية
- يستدعي كل اختبار فردي طريقة
fulfill
لمثيل المكتبة من أجل إنتاج نتيجة إنشاء النية. - بعد ذلك، يُثبت المطوِّر صحة الرابط لصفحة في التطبيق أو يشغّل عملية إكمال التطبيق، ويُجري عملية تحقّق مخصّصة لحالة التطبيق.
متطلّبات الإعداد
من أجل استخدام مكتبة الاختبار، يجب إجراء بعض الإعدادات الأولية للتطبيق مطلوبة قبل إضافة الاختبارات إلى طلبك.
الإعدادات
لاستخدام "مكتبة اختبار إجراءات التطبيقات"، تأكَّد من ضبط إعدادات تطبيقك على النحو التالي:
- تثبيت المكوّن الإضافي لنظام Gradle المتوافق مع Android (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…") }
إذا كنت تستخدم Espresso، عليك تعديل طريقة إطلاق النشاط استنادًا إلى نتائج AATL. في ما يلي مثال على Espresso باستخدام الأسلوب
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. على سبيل المثال، يتطابق
exercisePlan.forExercise.name
مع مستندات المَعلمة فيGET_EXERCISE_PLAN
.أنشئ مثيلًا لواجهة برمجة التطبيقات باستخدام مَعلمة سياق 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
، يمكنك تحويل النوعAppActionsFulfillmentResult
إلىAppActionsIntentFulfillmentResult
، ثم جلب Android Intent من خلال استدعاء الأسلوبgetIntent
وتنفيذ أحد الإجراءات التالية:- تأكيد حقول فردية لطلب Android
- تأكيد معرّف الموارد المنتظم (URI) للنية التي يتم الوصول إليها من خلال طريقة intent.getData.getHost.
- بالنسبة إلى حالة
DEEPLINK
، حوِّلAppActionsFulfillmentResult
إلىAppActionsIntentFulfillmentResult
(نفس سيناريوINTENT
أعلاه)، يمكنك جلب 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.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"); }
تحديد المشاكل وحلّها
إذا تعذّر اختبار الدمج بشكل غير متوقّع، يمكنك البحث عن رسائل سجلّ AATL في نافذة logcat في "استوديو Android" للحصول على رسالة مستوى التحذير أو الخطأ. يمكنك أيضًا زيادة مستوى تسجيل المحتوى لتسجيل المزيد من المحتوى من المكتبة.
القيود
في ما يلي القيود الحالية على مكتبة اختبار مهام التطبيق :
- لا تختبر AATL ميزة "فهم اللغة الطبيعية" (NLU) أو ميزة "تحويل الكلام إلى نص" (STT).
- لا يعمل AATL عندما تكون الاختبارات في وحدات غير التطبيق التلقائي. واحدة.
- لا يتوافق إطار عمل AATL إلا مع الإصدار 7.0 من نظام التشغيل Android (المستوى 24 لواجهة برمجة التطبيقات) والإصدارات الأحدث.