ไลบรารีการทดสอบการดำเนินการของแอป (AATL) มอบความสามารถที่จะช่วยให้นักพัฒนาซอฟต์แวร์ เพื่อทดสอบการดำเนินการของแอป Fulfillment แบบเป็นโปรแกรม ทำให้การทดสอบเป็นไปโดยอัตโนมัติ โดยปกติจะทำโดยใช้คำสั่งเสียงจริงหรือเครื่องมือทดสอบการดำเนินการของแอป
ไลบรารีช่วยให้มั่นใจได้ว่าการกำหนดค่า shortcut.xml
ถูกต้องและ
การเรียกใช้ Intent ของ Android ที่อธิบายไว้สำเร็จ ไลบรารีการทดสอบการดำเนินการของแอป
เป็นกลไกในการทดสอบความสามารถของแอปในการดำเนินการตามที่กำหนดโดย Google
Intent และพารามิเตอร์ของ Assistant โดยแปลงเป็น Deep Link สำหรับ Android หรือ
Intent ของ Android ซึ่งสามารถยืนยันและใช้ในการสร้างอินสแตนซ์ Android
กิจกรรม
การทดสอบจะดำเนินการในรูปแบบของหน่วย Robolectric หรือการทดสอบแบบมีเครื่องวัดใน สภาพแวดล้อมของ Android ซึ่งช่วยให้นักพัฒนาแอปสามารถทดสอบ โดยจำลองลักษณะการทำงานจริงของแอป สําหรับการทดสอบ BII, Intent ที่กําหนดเอง หรือการตอบสนองของ Deep Link คุณสามารถใช้เฟรมเวิร์กการทดสอบที่มีเครื่องมือวัดผลได้ (UI Automator, Espresso, JUnit4, Appium, Detox, Calabash)
หากแอปพลิเคชันเป็นหลายภาษา นักพัฒนาแอปสามารถตรวจสอบว่าฟังก์ชันการทํางานของแอปพลิเคชันทำงานได้อย่างถูกต้องในภาษาต่างๆ
วิธีการทำงาน
หากต้องการผสานรวม App Actions Test Library ภายในสภาพแวดล้อมการทดสอบของแอป นักพัฒนาแอปควรสร้างใหม่หรืออัปเดตการทดสอบ Robolectric หรือการทดสอบที่มีเครื่องมือวัดผลที่มีอยู่ในapp
โมดูลของแอป
รหัสทดสอบประกอบด้วยส่วนต่อไปนี้
- เริ่มต้นอินสแตนซ์ไลบรารีในวิธีการตั้งค่าทั่วไปหรือในเทสเคสแต่ละรายการ
- การทดสอบแต่ละรายการเรียกใช้เมธอด
fulfill
ของอินสแตนซ์ไลบรารีเพื่อสร้างผลลัพธ์การสร้าง Intent - จากนั้นนักพัฒนาซอฟต์แวร์จะยืนยัน Deep Link หรือทริกเกอร์ Fulfillment ของแอป และเรียกใช้การตรวจสอบที่กำหนดเองในสถานะของแอป
ข้อกำหนดในการตั้งค่า
หากต้องการใช้คลังทดสอบ คุณจะต้องทำการกําหนดค่าแอปเบื้องต้นก่อนเพิ่มการทดสอบลงในแอปพลิเคชัน
การกำหนดค่า
หากต้องการใช้คลังทดสอบการดำเนินการของแอป ให้ตรวจสอบว่าได้กําหนดค่าแอปดังนี้
- ติดตั้งปลั๊กอิน Android Gradle (AGP)
- รวมไฟล์
shortcuts.xml
ในโฟลเดอร์res/xml
ในโมดูลapp
- ตรวจสอบว่า
AndroidManifest.xml
มี<meta-data android:name="android.app.shortcuts" android:resource=”@xml/shortcuts” />
ใต้- แท็ก
<application>
- แท็ก Launcher
<activity>
- แท็ก
- วางองค์ประกอบ
<capability>
ภายในองค์ประกอบ<shortcuts>
ในshortcuts.xml
เพิ่มทรัพยากร Dependency ของ App Actions Test Library
เพิ่มที่เก็บของ 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
สร้างอินสแตนซ์ API ที่มีพารามิเตอร์บริบทของ 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
ของ API และรับออบเจ็กต์AppActionsFulfillmentResult
ดำเนินการยืนยัน
วิธีที่แนะนำในการยืนยันไลบรารีการดำเนินการของแอปคือ
- ยืนยันประเภทการดำเนินการตามคำสั่งซื้อของ
AppActionsFulfillmentResult
โดยต้องเป็นFulfillmentType.INTENT
หรือFulfillmentType.UNFULFILLED
เพื่อทดสอบลักษณะการทํางานของแอปในกรณีที่มีการส่งคําขอ BII ที่ไม่คาดคิด - การดำเนินการตามคำสั่งซื้อมี 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 ที่มีการเข้าถึงผ่าน เมธอดIntent.getData.getHost
- สำหรับเคส
DEEPLINK
ให้พิมพ์AppActionsFulfillmentResult
ถึงAppActionsIntentFulfillmentResult
(เช่นเดียวกับสถานการณ์INTENT
ด้านบน) ดึงข้อมูล Android Intent ด้วยการเรียกใช้เมธอดgetIntent
และยืนยัน URL ของ Deep Link (เข้าถึงผ่านintent.getData.getHost
) - สําหรับทั้ง
INTENT
และDEEPLINK
คุณสามารถใช้ Intent ที่ได้เพื่อเปิดใช้งานกิจกรรมด้วยเฟรมเวิร์กการทดสอบ 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 เพื่อรับข้อความเตือนหรือข้อความระดับข้อผิดพลาด นอกจากนี้ คุณยังเพิ่มระดับการบันทึกเพื่อบันทึกเอาต์พุตจากคลังได้มากขึ้น
ข้อจำกัด
ข้อจํากัดปัจจุบันของคลังการทดสอบ App Actions มีดังนี้
- AATL ไม่ได้ทดสอบฟีเจอร์การทําความเข้าใจภาษาธรรมชาติ (NLU) หรือฟีเจอร์การแปลงคำพูดเป็นข้อความ (STT)
- AATL ไม่ทำงานเมื่อการทดสอบอยู่ในโมดูลอื่นที่ไม่ใช่แอปเริ่มต้น
- AATL ใช้ได้กับ Android 7.0 "Nougat" (API ระดับ 24) ขึ้นไปเท่านั้น