ספריית הבדיקות של 'פעולות באפליקציה' (AATL) מספקת למפתחים כדי לבדוק את האפשרות לביצוע פעולות באפליקציה באופן פרוגרמטי, ביצוע אוטומציה של בדיקות מתבצעות בדרך כלל באמצעות שאילתות קוליות אמיתיות או באמצעות כלי הבדיקה של פעולות באפליקציה.
הספרייה עוזרת לוודא שההגדרה של shortcut.xml
נכונה
ההפעלה המתוארת של Intent של Android מצליחה. ספריית הבדיקות של 'פעולות באפליקציה'
שמספק מנגנון לבדיקת היכולת של האפליקציה למלא את הבקשה,
כוונת רכישה ופרמטרים של Assistant, על ידי המרה שלהם לקישור עומק ל-Android או
Intent Android, שאפשר להצהיר עליו ולהשתמש בו כדי ליצור מכשיר Android
פעילות.
הבדיקה מתבצעת בצורה של יחידות רובולקטריות או בדיקות אינסטרומנטליות בסביבת Android. כך מפתחים יכולים לבדוק באופן מקיף באמצעות אמולציה של התנהגות האפליקציה בפועל. לבדיקת BII, התאמה אישית ב-Intents, או מילוי של קישורי עומק, כל מסגרת בדיקה אינסטרומנטלית יכולה להיות בשימוש (UI Automator, Espresso, JUnit4, Appium, Detox, Calabash).
אם האפליקציה רב-לשונית, המפתחים יכולים לוודא הפונקציונליות של האפליקציה פועלת באופן תקין באזורים שונים.
איך זה עובד
כדי לשלב את ספריית הבדיקות של 'פעולות באפליקציה' בסביבת הבדיקה של האפליקציה, המפתחים צריכים
ליצור או לעדכן בדיקות Robolectric או מכשירים אינסטרומנטליות קיימות ב-app
של האפליקציה.
קוד הבדיקה מכיל את החלקים הבאים:
- אתחול של מופע הספרייה, בשיטת ההגדרה הנפוצה או בתרחישי בדיקה נפרדים.
- כל בדיקה בודדת מפעילה את ה-method
fulfill
של מכונת הספרייה כדי כדי ליצור את התוצאה של יצירת הכוונה. - לאחר מכן המפתח מצהיר על קישור עומק או מפעיל את מילוי ההזמנות של האפליקציה, ומריץ אימות מותאם אישית על מצב האפליקציה.
הדרישות להגדרת YouTube Music
כדי להשתמש בספריית הבדיקות, צריך לבצע הגדרות ראשוניות באפליקציה לפני שמוסיפים את הבדיקות לאפליקציה.
הגדרות אישיות
כדי להשתמש בספריית הבדיקות של 'פעולות באפליקציה', צריך לוודא שהאפליקציה מוגדרת כך:
- התקנת הפלאגין של 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…") }
אם משתמשים ב-Espresso, צריך לשנות את האופן שבו מפעילים את הפעילות על סמך תוצאות 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. לדוגמה, הערך
exercisePlan.forExercise.name
תואם למסמכי העזרה של הפרמטר ב-GET_EXERCISE_PLAN
.מופע של Instantiate API עם הפרמטר Android Context (מתקבל מ-
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)); }
מפעילים את ה-method
fulfill
ב-API ומשיגים אובייקטAppActionsFulfillmentResult
.
ביצוע טענות נכוֹנוּת (assertions)
הדרך המומלצת להצהיר בעלות על ספריית הבדיקות של 'פעולות באפליקציה' היא:
- בודקים את סוג המילוי של
AppActionsFulfillmentResult
. כדי לבדוק איך האפליקציה מתנהגת במקרה של בקשות BII בלתי צפויות, הערך צריך להיותFulfillmentType.INTENT
אוFulfillmentType.UNFULFILLED
. - יש 2 טעמים של מילוי הזמנות:
INTENT
ו-DEEPLINK
.- בדרך כלל, המפתח יכול להבחין בין
INTENT
לביןDEEPLINK
עמידה בדרישות על ידי עיון בתג Intent ב-shortcuts.xml
שהם מממשים באמצעות הפעלת הספרייה. - אם יש תג של תבנית URL מתחת לתג Intent, המשמעות היא
שה-
DEEPLINK
ממלא את הכוונה הזו. - אם השיטה
getData()
של ה-intent בתוצאה מחזירה אובייקט שאינו null, זה גם מציין שהבקשהDEEPLINK
בוצעה. באופן דומה, אםgetData
מחזירה את הערךnull
, המשמעות היא שמדובר במילוי בקשה מסוגINTENT
.
- בדרך כלל, המפתח יכול להבחין בין
- באותיות רישיות במסגרת
INTENT
, מקלידים את הערךAppActionsFulfillmentResult
בתורAppActionsIntentFulfillmentResult
, אחזר את ה-Intent של Android על ידי התקשרותgetIntent
מבצעים אחת מהפעולות הבאות:- הצהרת בעלות על שדות ספציפיים ב-Android Intent.
- הצהרת בעלות על ה-URI של Intent שהגישה אליו מתבצעת דרך ה-method Intent.getData.getHost.
- באותיות רישיות במסגרת
DEEPLINK
, מקלידים את הערךAppActionsFulfillmentResult
בתורAppActionsIntentFulfillmentResult
(זהה לתרחישINTENT
שלמעלה), לאחזר את ה-Intent של Android על ידי קריאה ל-methodgetIntent
ומצהירים על זכויות יוצרים כתובת ה-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 Studio כדי לקבל את הודעת האזהרה או רמת השגיאה. אפשר גם להגדיל את הרישום ביומן רמה כדי להפיק יותר פלט בספרייה.
מגבלות
אלו המגבלות הנוכחיות של ספריית הבדיקות של 'פעולות באפליקציה':
- AATL לא בודק את הבנת שפה טבעית (NLU) או המרת דיבור לטקסט (STT) (STT).
- AATL לא פועל כשהבדיקות הן במודולים אחרים מלבד אפליקציית ברירת המחדל של מודל טרנספורמר.
- AATL תואם רק ל-Android 7.0 'Nougat' (רמת API 24) ואילך.