Библиотека тестирования действий приложения (AATL) предоставляет разработчикам возможность программно тестировать выполнение действий приложения, автоматизируя тестирование, которое обычно выполняется с использованием реальных голосовых запросов или инструмента тестирования действий приложения.
Библиотека помогает убедиться в правильности конфигурации shortcut.xml
и успешности описанного вызова намерения Android. Библиотека тестирования действий приложения предоставляет механизм для проверки способности вашего приложения выполнять заданные намерения и параметры Google Ассистента путем преобразования их в глубокую ссылку Android или намерение Android, которые можно утверждать и использовать для создания экземпляра действия Android.
Тестирование проводится в виде модульных Robolectric или инструментальных тестов в среде Android. Это позволяет разработчикам всесторонне тестировать свое приложение, эмулируя фактическое поведение приложения. Для тестирования BII, пользовательских намерений или выполнения глубоких ссылок можно использовать любую инструментальную среду тестирования (UI Automator, Espresso, JUnit4, Appium, Detox, Calabash).
Если приложение является многоязычным, разработчики могут проверить правильность работы функций приложения в разных языковых стандартах.
Как это работает
Чтобы интегрировать библиотеку тестов App Actions в среду тестирования приложения, разработчикам следует создать новые или обновить существующие 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
Добавление зависимостей библиотеки тестов App Actions
Добавьте репозиторий 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
:Котлин
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…") }
Ява
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
:Котлин
ActivityScenario.launch<MainActivity>(intentResult.intent); Espresso.onView(ViewMatchers.withId(R.id.startActivityTitle)) .check(ViewAssertions.matches(ViewMatchers.withText("Launching…")))
Ява
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
):- Архитектура приложения с одним модулем:
Котлин
private lateinit var aatl: AppActionsTestManager @Before fun init() { val appContext = ApplicationProvider.getApplicationContext() aatl = AppActionsTestManager(appContext) }
Ява
private AppActionsTestManager aatl; @Before public void init() { Context appContext = ApplicationProvider.getApplicationContext(); aatl = new AppActionsTestManager(appContext); }
- Многомодульная архитектура приложения:
Котлин
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) }
Ява
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 API и получите объектAppActionsFulfillmentResult
.
Выполнение утверждений
Рекомендуемый способ утверждения библиотеки тестов действий приложения:
- Укажите тип выполнения
AppActionsFulfillmentResult
. Это должен бытьFulfillmentType.INTENT
илиFulfillmentType.UNFULFILLED
, чтобы проверить, как приложение ведет себя в случае неожиданных запросов BII. - Существует два варианта выполнения: выполнение
INTENT
иDEEPLINK
.- Обычно разработчик может различать выполнение
INTENT
иDEEPLINK
, просматривая тег намерения вshortcuts.xml
, который они выполняют, запуская библиотеку. - Если под тегом намерения есть тег шаблона URL-адреса, это означает, что
DEEPLINK
выполняет это намерение. - Если метод
getData()
результирующего намерения возвращает ненулевой объект, это также указывает на выполнениеDEEPLINK
. Аналогично, еслиgetData
возвращаетnull
это означает, что это выполнениеINTENT
.
- Обычно разработчик может различать выполнение
- В случае
INTENT
введитеAppActionsFulfillmentResult
вAppActionsIntentFulfillmentResult
, получите намерение Android, вызвав методgetIntent
, и выполните одно из следующих действий:- Утвердите отдельные поля Android Intent.
- Укажите uri намерения, доступ к которому осуществляется с помощью метода Intent.getData.getHost.
- В случае
DEEPLINK
введитеAppActionsFulfillmentResult
вAppActionsIntentFulfillmentResult
(так же, как и для сценарияINTENT
выше), получите намерение Android, вызвав методgetIntent
, и утвердите URL-адрес глубокой ссылки (доступ к которому осуществляется черезintent.getData.getHost
). - Как для
INTENT
, так иDEEPLINK
вы можете использовать полученное намерение для запуска активности с выбранной платформой тестирования Android.
Интернационализация
Если ваше приложение имеет несколько языковых стандартов, вы можете настроить тесты для запуска определенного тестируемого языкового стандарта. Альтернативно вы можете напрямую изменить локаль:
Котлин
import android.content.res.Configuration import java.util.Locale ... val newLocale = Locale("es") val conf = context.resources.configuration conf = Configuration(conf) conf.setLocale(newLocale)
Ява
Locale newLocale = new Locale("es"); Configuration conf = context.getResources().getConfiguration(); conf = new Configuration(conf); conf.setLocale(newLocale);
Вот пример теста AATL, настроенного для испанского языка (ES):
Котлин
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") } }
Ява
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) и новее.
Библиотека тестирования действий приложения (AATL) предоставляет разработчикам возможность программно тестировать выполнение действий приложения, автоматизируя тестирование, которое обычно выполняется с использованием реальных голосовых запросов или инструмента тестирования действий приложения.
Библиотека помогает убедиться в правильности конфигурации shortcut.xml
и успешности описанного вызова намерения Android. Библиотека тестирования действий приложения предоставляет механизм для проверки способности вашего приложения выполнять заданные намерения и параметры Google Ассистента путем преобразования их в глубокую ссылку Android или намерение Android, которые можно утверждать и использовать для создания экземпляра действия Android.
Тестирование проводится в виде модульных Robolectric или инструментальных тестов в среде Android. Это позволяет разработчикам всесторонне тестировать свое приложение, эмулируя фактическое поведение приложения. Для тестирования BII, пользовательских намерений или выполнения глубоких ссылок можно использовать любую инструментальную среду тестирования (UI Automator, Espresso, JUnit4, Appium, Detox, Calabash).
Если приложение является многоязычным, разработчики могут проверить правильность работы функций приложения в разных языковых стандартах.
Как это работает
Чтобы интегрировать библиотеку тестов App Actions в среду тестирования приложения, разработчикам следует создать новые или обновить существующие 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
Добавление зависимостей библиотеки тестов App Actions
Добавьте репозиторий 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
:Котлин
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…") }
Ява
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
:Котлин
ActivityScenario.launch<MainActivity>(intentResult.intent); Espresso.onView(ViewMatchers.withId(R.id.startActivityTitle)) .check(ViewAssertions.matches(ViewMatchers.withText("Launching…")))
Ява
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
):- Архитектура приложения с одним модулем:
Котлин
private lateinit var aatl: AppActionsTestManager @Before fun init() { val appContext = ApplicationProvider.getApplicationContext() aatl = AppActionsTestManager(appContext) }
Ява
private AppActionsTestManager aatl; @Before public void init() { Context appContext = ApplicationProvider.getApplicationContext(); aatl = new AppActionsTestManager(appContext); }
- Многомодульная архитектура приложения:
Котлин
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) }
Ява
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 API и получите объектAppActionsFulfillmentResult
.
Выполнение утверждений
Рекомендуемый способ утверждения библиотеки тестов действий приложения:
- Укажите тип выполнения
AppActionsFulfillmentResult
. Это должен бытьFulfillmentType.INTENT
илиFulfillmentType.UNFULFILLED
, чтобы проверить, как приложение ведет себя в случае неожиданных запросов BII. - Существует два варианта выполнения: выполнение
INTENT
иDEEPLINK
.- Обычно разработчик может различать выполнение
INTENT
иDEEPLINK
, просматривая тег намерения вshortcuts.xml
, который они выполняют, запуская библиотеку. - Если под тегом намерения есть тег шаблона URL-адреса, это означает, что
DEEPLINK
выполняет это намерение. - Если метод
getData()
результирующего намерения возвращает ненулевой объект, это также указывает на выполнениеDEEPLINK
. Аналогично, еслиgetData
возвращаетnull
это означает, что это выполнениеINTENT
.
- Обычно разработчик может различать выполнение
- В случае
INTENT
введитеAppActionsFulfillmentResult
вAppActionsIntentFulfillmentResult
, получите намерение Android, вызвав методgetIntent
, и выполните одно из следующих действий:- Утвердите отдельные поля Android Intent.
- Укажите uri намерения, доступ к которому осуществляется с помощью метода Intent.getData.getHost.
- В случае
DEEPLINK
введитеAppActionsFulfillmentResult
вAppActionsIntentFulfillmentResult
(так же, как и для сценарияINTENT
выше), получите намерение Android, вызвав методgetIntent
, и утвердите URL-адрес глубокой ссылки (доступ к которому осуществляется черезintent.getData.getHost
). - Как для
INTENT
, так иDEEPLINK
вы можете использовать полученное намерение для запуска активности с выбранной платформой тестирования Android.
Интернационализация
Если ваше приложение имеет несколько языковых стандартов, вы можете настроить тесты для запуска определенного тестируемого языкового стандарта. Альтернативно вы можете напрямую изменить локаль:
Котлин
import android.content.res.Configuration import java.util.Locale ... val newLocale = Locale("es") val conf = context.resources.configuration conf = Configuration(conf) conf.setLocale(newLocale)
Ява
Locale newLocale = new Locale("es"); Configuration conf = context.getResources().getConfiguration(); conf = new Configuration(conf); conf.setLocale(newLocale);
Вот пример теста AATL, настроенного для испанского языка (ES):
Котлин
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") } }
Ява
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) и новее.
Библиотека тестирования действий приложения (AATL) предоставляет разработчикам возможность программно тестировать выполнение действий приложения, автоматизируя тестирование, которое обычно выполняется с использованием реальных голосовых запросов или инструмента тестирования действий приложения.
Библиотека помогает убедиться в правильности конфигурации shortcut.xml
и успешности описанного вызова намерения Android. Библиотека тестирования действий приложения предоставляет механизм для проверки способности вашего приложения выполнять заданные намерения и параметры Google Ассистента путем преобразования их в глубокую ссылку Android или намерение Android, которые можно утверждать и использовать для создания экземпляра действия Android.
Тестирование проводится в виде модульных Robolectric или инструментальных тестов в среде Android. Это позволяет разработчикам всесторонне тестировать свое приложение, эмулируя фактическое поведение приложения. Для тестирования BII, пользовательских намерений или выполнения глубоких ссылок можно использовать любую инструментальную среду тестирования (UI Automator, Espresso, JUnit4, Appium, Detox, Calabash).
Если приложение является многоязычным, разработчики могут проверить правильность работы функций приложения в разных языковых стандартах.
Как это работает
Чтобы интегрировать библиотеку тестов App Actions в среду тестирования приложения, разработчикам следует создать новые или обновить существующие 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
Добавление зависимостей библиотеки тестов App Actions
Добавьте репозиторий 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
:Котлин
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…") }
Ява
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
:Котлин
ActivityScenario.launch<MainActivity>(intentResult.intent); Espresso.onView(ViewMatchers.withId(R.id.startActivityTitle)) .check(ViewAssertions.matches(ViewMatchers.withText("Launching…")))
Ява
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
):- Архитектура приложения с одним модулем:
Котлин
private lateinit var aatl: AppActionsTestManager @Before fun init() { val appContext = ApplicationProvider.getApplicationContext() aatl = AppActionsTestManager(appContext) }
Ява
private AppActionsTestManager aatl; @Before public void init() { Context appContext = ApplicationProvider.getApplicationContext(); aatl = new AppActionsTestManager(appContext); }
- Многомодульная архитектура приложения:
Котлин
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) }
Ява
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 API и получите объектAppActionsFulfillmentResult
.
Выполнение утверждений
Рекомендуемый способ утверждения библиотеки тестов действий приложения:
- Укажите тип выполнения
AppActionsFulfillmentResult
. Это должен бытьFulfillmentType.INTENT
илиFulfillmentType.UNFULFILLED
, чтобы проверить, как приложение ведет себя в случае неожиданных запросов BII. - Существует два варианта выполнения: выполнение
INTENT
иDEEPLINK
.- Обычно разработчик может различать выполнение
INTENT
иDEEPLINK
, просматривая тег намерения вshortcuts.xml
, который они выполняют, запуская библиотеку. - Если под тегом намерения есть тег шаблона URL-адреса, это означает, что
DEEPLINK
выполняет это намерение. - Если метод
getData()
результирующего намерения возвращает ненулевой объект, это также указывает на выполнениеDEEPLINK
. Аналогично, еслиgetData
возвращаетnull
это означает, что это выполнениеINTENT
.
- Обычно разработчик может различать выполнение
- В случае
INTENT
введитеAppActionsFulfillmentResult
вAppActionsIntentFulfillmentResult
, получите намерение Android, вызвав методgetIntent
, и выполните одно из следующих действий:- Утвердите отдельные поля Android Intent.
- Укажите uri намерения, доступ к которому осуществляется с помощью метода Intent.getData.getHost.
- В случае
DEEPLINK
введитеAppActionsFulfillmentResult
вAppActionsIntentFulfillmentResult
(так же, как и для сценарияINTENT
выше), получите намерение Android, вызвав методgetIntent
, и утвердите URL-адрес глубокой ссылки (доступ к которому осуществляется черезintent.getData.getHost
). - Как для
INTENT
, так иDEEPLINK
вы можете использовать полученное намерение для запуска активности с выбранной платформой тестирования Android.
Интернационализация
Если ваше приложение имеет несколько языковых стандартов, вы можете настроить тесты для запуска определенного тестируемого языкового стандарта. Альтернативно вы можете напрямую изменить локаль:
Котлин
import android.content.res.Configuration import java.util.Locale ... val newLocale = Locale("es") val conf = context.resources.configuration conf = Configuration(conf) conf.setLocale(newLocale)
Ява
Locale newLocale = new Locale("es"); Configuration conf = context.getResources().getConfiguration(); conf = new Configuration(conf); conf.setLocale(newLocale);
Вот пример теста AATL, настроенного для испанского языка (ES):
Котлин
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") } }
Ява
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) и новее.
Библиотека тестирования действий приложения (AATL) предоставляет разработчикам возможность программно тестировать выполнение действий приложения, автоматизируя тестирование, которое обычно выполняется с использованием реальных голосовых запросов или инструмента тестирования действий приложения.
Библиотека помогает убедиться в правильности конфигурации shortcut.xml
и успешности описанного вызова намерения Android. Библиотека тестирования действий приложения предоставляет механизм для проверки способности вашего приложения выполнять заданные намерения и параметры Google Ассистента путем преобразования их в глубокую ссылку Android или намерение Android, которые можно утверждать и использовать для создания экземпляра действия Android.
Тестирование проводится в виде модульных Robolectric или инструментальных тестов в среде Android. Это позволяет разработчикам всесторонне тестировать свое приложение, эмулируя фактическое поведение приложения. Для тестирования BII, пользовательских намерений или выполнения глубоких ссылок можно использовать любую инструментальную среду тестирования (UI Automator, Espresso, JUnit4, Appium, Detox, Calabash).
Если приложение является многоязычным, разработчики могут проверить правильность работы функций приложения в разных языковых стандартах.
Как это работает
Чтобы интегрировать библиотеку тестов App Actions в среду тестирования приложения, разработчикам следует создать новые или обновить существующие 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
Добавление зависимостей библиотеки тестов App Actions
Добавьте репозиторий 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
:Котлин
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…") }
Ява
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
:Котлин
ActivityScenario.launch<MainActivity>(intentResult.intent); Espresso.onView(ViewMatchers.withId(R.id.startActivityTitle)) .check(ViewAssertions.matches(ViewMatchers.withText("Launching…")))
Ява
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
):- Архитектура приложения с одним модулем:
Котлин
private lateinit var aatl: AppActionsTestManager @Before fun init() { val appContext = ApplicationProvider.getApplicationContext() aatl = AppActionsTestManager(appContext) }
Ява
private AppActionsTestManager aatl; @Before public void init() { Context appContext = ApplicationProvider.getApplicationContext(); aatl = new AppActionsTestManager(appContext); }
- Многомодульная архитектура приложения:
Котлин
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) }
Ява
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 API и получите объектAppActionsFulfillmentResult
.
Выполнение утверждений
Рекомендуемый способ утверждения библиотеки тестов действий приложения:
- Укажите тип выполнения
AppActionsFulfillmentResult
. Это должен бытьFulfillmentType.INTENT
илиFulfillmentType.UNFULFILLED
, чтобы проверить, как приложение ведет себя в случае неожиданных запросов BII. - Существует два варианта выполнения: выполнение
INTENT
иDEEPLINK
.- Обычно разработчик может различать выполнение
INTENT
иDEEPLINK
, просматривая тег намерения вshortcuts.xml
, который они выполняют, запуская библиотеку. - Если под тегом намерения есть тег шаблона URL-адреса, это означает, что
DEEPLINK
выполняет это намерение. - Если метод
getData()
результирующего намерения возвращает ненулевой объект, это также указывает на выполнениеDEEPLINK
. Аналогично, еслиgetData
возвращаетnull
это означает, что это выполнениеINTENT
.
- Обычно разработчик может различать выполнение
- В случае
INTENT
введитеAppActionsFulfillmentResult
вAppActionsIntentFulfillmentResult
, получите намерение Android, вызвав методgetIntent
, и выполните одно из следующих действий:- Утвердите отдельные поля Android Intent.
- Укажите uri намерения, доступ к которому осуществляется с помощью метода Intent.getData.getHost.
- В случае
DEEPLINK
введитеAppActionsFulfillmentResult
вAppActionsIntentFulfillmentResult
(так же, как и для сценарияINTENT
выше), получите намерение Android, вызвав методgetIntent
, и утвердите URL-адрес глубокой ссылки (доступ к которому осуществляется черезintent.getData.getHost
). - Как для
INTENT
, так иDEEPLINK
вы можете использовать полученное намерение для запуска активности с выбранной платформой тестирования Android.
Интернационализация
Если ваше приложение имеет несколько языковых стандартов, вы можете настроить тесты для запуска определенного тестируемого языкового стандарта. Альтернативно вы можете напрямую изменить локаль:
Котлин
import android.content.res.Configuration import java.util.Locale ... val newLocale = Locale("es") val conf = context.resources.configuration conf = Configuration(conf) conf.setLocale(newLocale)
Ява
Locale newLocale = new Locale("es"); Configuration conf = context.getResources().getConfiguration(); conf = new Configuration(conf); conf.setLocale(newLocale);
Вот пример теста AATL, настроенного для испанского языка (ES):
Котлин
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") } }
Ява
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) и новее.