ספריית הבדיקות של 'פעולות באפליקציה' (AATL) מספקת למפתחים יכולות חדשות כדי לבדוק את האפשרות לביצוע פעולות באפליקציה באופן פרוגרמטי, ביצוע אוטומציה של בדיקות מתבצעות בדרך כלל באמצעות שאילתות קוליות אמיתיות או באמצעות כלי הבדיקה של פעולות באפליקציה.
הספרייה עוזרת לוודא שההגדרה של shortcut.xml
נכונה ושקריאה ה-intent המתוארת ב-Android מצליחה. ספריית הבדיקה של פעולות האפליקציה מספקת מנגנון לבדיקת היכולת של האפליקציה למלא כוונה (intent) ופרמטרים נתונים של Google Assistant, על ידי המרתם לקישור עומק ל-Android או לכוונה ל-Android, שניתן לאמת ולהשתמש בהם כדי ליצור מופע של פעילות ב-Android.
הבדיקה מתבצעת באמצעות בדיקות יחידה או בדיקות מופעלות ב-Robolectric בסביבת Android. כך מפתחים יכולים לבדוק באופן מקיף באמצעות אמולציה של התנהגות האפליקציה בפועל. כדי לבדוק ממשקי BIIs, כוונות מותאמות אישית או השלמה של קישורי עומק, אפשר להשתמש בכל מסגרת בדיקה עם כלי מדידה (UI Automator, Espresso, JUnit4, Appium, Detox, Calabash).
אם האפליקציה רב-לשונית, המפתחים יכולים לוודא הפונקציונליות של האפליקציה פועלת באופן תקין באזורים שונים.
איך זה עובד
כדי לשלב את ספריית הבדיקות של פעולות האפליקציה בסביבת הבדיקה של האפליקציה, המפתחים צריכים ליצור בדיקות Robolectric או בדיקות עם מכשירי מדידה חדשות או לעדכן בדיקות קיימות במודול app
של האפליקציה.
קוד הבדיקה מכיל את החלקים הבאים:
- אתחול של מופע הספרייה, בשיטת ההגדרה הנפוצה או בתרחישי בדיקה ספציפיים.
- כל בדיקה בנפרד קוראת לשיטה
fulfill
של מופע הספרייה כדי ליצור את תוצאת יצירת הכוונה. - לאחר מכן, המפתח מבצע טענת נכוֹנוּת (assertion) של קישור העומק או מפעיל את מילוי ההזמנה באפליקציה, ומריץ אימות מותאם אישית של מצב האפליקציה.
הדרישות להגדרת 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
.יוצרים מופע של 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)); }
מריצים את השיטה
fulfill
של ה-API ומקבלים את האובייקטAppActionsFulfillmentResult
.
ביצוע טענות נכוֹנוּת (assertions)
הדרך המומלצת לאימות הספרייה לבדיקת פעולות באפליקציה היא:
- להצהיר על סוג האספקה של
AppActionsFulfillmentResult
. הוא צריך להיותFulfillmentType.INTENT
אוFulfillmentType.UNFULFILLED
כדי לבדוק איך האפליקציה פועלת במקרה של בקשות BII בלתי צפויות. - יש 2 סוגים של השלמת הזמנות: השלמות הזמנות מסוג
INTENT
והשלמות הזמנות מסוגDEEPLINK
.- בדרך כלל, המפתח יכול להבחין בין
INTENT
לביןDEEPLINK
עמידה בדרישות על ידי עיון בתג Intent ב-shortcuts.xml
שהם מממשים באמצעות הפעלת הספרייה. - אם יש תג של תבנית URL מתחת לתג Intent, המשמעות היא
שה-
DEEPLINK
ממלא את הכוונה הזו. - אם ה-method
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).
- AATL לא פועל כשהבדיקות הן במודולים אחרים מלבד אפליקציית ברירת המחדל של מודל טרנספורמר.
- AATL תואם רק ל-Android 7.0 'Nougat' (רמת API 24) ואילך.