Espresso-Intents

Espresso-Intents – это расширение для Espresso, которое позволяет проверять и заменять заглушками намерения, отправляемые тестируемым приложением. Он похож на Mockito, но предназначен для Android Intents.

Если ваше приложение делегирует функции другим приложениям или платформе, вы можете использовать Espresso-Intents, чтобы сосредоточиться на логике собственного приложения, предполагая, что другие приложения или платформа будут работать правильно. С помощью Espresso-Intents вы можете сопоставлять и проверять исходящие намерения или даже предоставлять заглушки вместо фактических ответов на намерения.

Как включить Espresso-Intents в проект

В файле app/build.gradle приложения добавьте следующую строку в dependencies:

Яркий

androidTestImplementation 'androidx.test.espresso:espresso-intents:3.6.1'

Kotlin

androidTestImplementation('androidx.test.espresso:espresso-intents:3.6.1')

Espresso-Intents совместим только с Espresso 2.1+ и версией 0.3+ библиотек тестирования Android, поэтому обязательно обновите и эти строки:

Яркий

androidTestImplementation 'androidx.test:runner:1.6.1'
androidTestImplementation 'androidx.test:rules:1.6.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'

Kotlin

androidTestImplementation('androidx.test:runner:1.6.1')
androidTestImplementation('androidx.test:rules:1.6.1')
androidTestImplementation('androidx.test.espresso:espresso-core:3.6.1')

Как написать правила тестирования

Прежде чем писать тест Espresso-Intents, настройте IntentsTestRule. Это расширение класса ActivityTestRule, которое упрощает использование API Espresso-Intents в функциональных тестах пользовательского интерфейса. IntentsTestRule инициализирует Espresso-Intents перед каждым тестом, помеченным @Test, и выпускает Espresso-Intents после каждого запуска теста.

Ниже приведен пример фрагмента кода IntentsTestRule.

Kotlin

@get:Rule
val intentsTestRule = IntentsTestRule(MyActivity::class.java)

Java

@Rule
public IntentsTestRule<MyActivity> intentsTestRule =
    new IntentsTestRule<>(MyActivity.class);

Поиск совпадений

Espresso-Intents позволяет перехватывать исходящие намерения на основе определенных критериев соответствия, которые задаются с помощью сопоставителей Hamcrest. Hamcrest позволяет:

  • Использовать существующий сопоставитель намерений. Это самый простой вариант, который подходит почти всегда.
  • Реализуйте собственный сопоставитель намерений. Это самый гибкий вариант. Подробную информацию можно найти в разделе "Writing custom matchers" (Написание собственных сопоставителей) руководства по Hamcrest.

Espresso-Intents предлагает методы intended() и intending() для проверки и заглушки намерений соответственно. Оба метода принимают в качестве аргумента объект Hamcrest Matcher<Intent>.

В следующем фрагменте кода показана проверка намерения, которая использует существующие сопоставители намерений, соответствующие исходящему намерению, запускающему браузер:

Kotlin

assertThat(intent).hasAction(Intent.ACTION_VIEW)
assertThat(intent).categories().containsExactly(Intent.CATEGORY_BROWSABLE)
assertThat(intent).hasData(Uri.parse("www.google.com"))
assertThat(intent).extras().containsKey("key1")
assertThat(intent).extras().string("key1").isEqualTo("value1")
assertThat(intent).extras().containsKey("key2")
assertThat(intent).extras().string("key2").isEqualTo("value2")

Java

assertThat(intent).hasAction(Intent.ACTION_VIEW);
assertThat(intent).categories().containsExactly(Intent.CATEGORY_BROWSABLE);
assertThat(intent).hasData(Uri.parse("www.google.com"));
assertThat(intent).extras().containsKey("key1");
assertThat(intent).extras().string("key1").isEqualTo("value1");
assertThat(intent).extras().containsKey("key2");
assertThat(intent).extras().string("key2").isEqualTo("value2");

Проверка намерений

Espresso-Intents записывает все намерения, которые пытаются запустить действия из тестируемого приложения. С помощью метода intended(), который похож на Mockito.verify(), можно подтвердить, что определенное намерение было зарегистрировано. Однако Espresso-Intents не создает заглушки для ответов на намерения, если вы не настроите его для этого.

В следующем фрагменте кода показан пример теста, который проверяет, но не заменяет ответы на исходящее намерение, запускающее внешнее действие "телефон":

Kotlin

@Test fun validateIntentSentToPackage() {
    // User action that results in an external "phone" activity being launched.
    user.clickOnView(system.getView(R.id.callButton))

    // Using a canned RecordedIntentMatcher to validate that an intent resolving
    // to the "phone" activity has been sent.
    intended(toPackage("com.android.phone"))
}

Java

@Test
public void validateIntentSentToPackage() {
    // User action that results in an external "phone" activity being launched.
    user.clickOnView(system.getView(R.id.callButton));

    // Using a canned RecordedIntentMatcher to validate that an intent resolving
    // to the "phone" activity has been sent.
    intended(toPackage("com.android.phone"));
}

Заглушка

С помощью метода intending(), который похож на Mockito.when(), вы можете предоставить ответ-заглушку для действий, запущенных с помощью startActivityForResult(). Это особенно полезно для внешних действий, поскольку вы не можете управлять пользовательским интерфейсом внешнего действия или контролировать ActivityResult, возвращаемый тестируемому действию.

В приведенных ниже фрагментах кода показан пример теста activityResult_DisplaysContactsPhoneNumber(), который проверяет, что при запуске действия "контакт" в тестируемом приложении отображается номер телефона контакта.

  1. Создайте результат, который будет возвращаться при запуске определенного действия. В примере теста перехватываются все интенты, отправленные в приложение "Контакты", и заменяются их ответы на действительный объект ActivityResult с кодом результата RESULT_OK.

    Kotlin

    val resultData = Intent()
    val phoneNumber = "123-345-6789"
    resultData.putExtra("phone", phoneNumber)
    val result = Instrumentation.ActivityResult(Activity.RESULT_OK, resultData)

    Java

    Intent resultData = new Intent();
    String phoneNumber = "123-345-6789";
    resultData.putExtra("phone", phoneNumber);
    ActivityResult result =
        new ActivityResult(Activity.RESULT_OK, resultData);
  2. Укажите Espresso, что нужно предоставлять объект-заглушку в ответ на все вызовы намерения contacts:

    Kotlin

    intending(toPackage("com.android.contacts")).respondWith(result)

    Java

    intending(toPackage("com.android.contacts")).respondWith(result);
  3. Убедитесь, что действие, используемое для запуска объекта activity, дает ожидаемый результат-заглушку. В этом случае пример теста проверяет, что номер телефона 123-345-6789 возвращается и отображается при запуске действия с контактами:

    Kotlin

    onView(withId(R.id.pickButton)).perform(click())
    onView(withId(R.id.phoneNumber)).check(matches(withText(phoneNumber)))

    Java

    onView(withId(R.id.pickButton)).perform(click());
    onView(withId(R.id.phoneNumber)).check(matches(withText(phoneNumber)));

Вот полный тест activityResult_DisplaysContactsPhoneNumber():

Kotlin

@Test fun activityResult_DisplaysContactsPhoneNumber() {
    // Build the result to return when the activity is launched.
    val resultData = Intent()
    val phoneNumber = "123-345-6789"
    resultData.putExtra("phone", phoneNumber)
    val result = Instrumentation.ActivityResult(Activity.RESULT_OK, resultData)

    // Set up result stubbing when an intent sent to "contacts" is seen.
    intending(toPackage("com.android.contacts")).respondWith(result)

    // User action that results in "contacts" activity being launched.
    // Launching activity expects phoneNumber to be returned and displayed.
    onView(withId(R.id.pickButton)).perform(click())

    // Assert that the data we set up above is shown.
    onView(withId(R.id.phoneNumber)).check(matches(withText(phoneNumber)))
}

Java

@Test
public void activityResult_DisplaysContactsPhoneNumber() {
    // Build the result to return when the activity is launched.
    Intent resultData = new Intent();
    String phoneNumber = "123-345-6789";
    resultData.putExtra("phone", phoneNumber);
    ActivityResult result =
        new ActivityResult(Activity.RESULT_OK, resultData);

    // Set up result stubbing when an intent sent to "contacts" is seen.
    intending(toPackage("com.android.contacts")).respondWith(result);

    // User action that results in "contacts" activity being launched.
    // Launching activity expects phoneNumber to be returned and displayed.
    onView(withId(R.id.pickButton)).perform(click());

    // Assert that the data we set up above is shown.
    onView(withId(R.id.phoneNumber)).check(matches(withText(phoneNumber)));
}

Дополнительные ресурсы

Дополнительную информацию об использовании Espresso-Intents в тестах Android можно найти в следующих ресурсах.

Образцы

  • IntentsBasicSample – базовое использование intended() и intending().
  • IntentsAdvancedSample – имитирует получение пользователем растрового изображения с помощью камеры.