Espresso — какво е, принципи на работа и как да се използва

Автор: IT Sectr Публикувано: 2026-04-08 Време за четене: 8 мин

Espresso е рамка за автоматизирано UI тестване на Android приложения, разработена от екипа на Google и част от AndroidX Test. За разлика от инструменталните тестове, които проверяват изолирани компоненти, Espresso взаимодейства с истинския UI: натиска бутони, въвежда текст, проверява показването на елементи. Според Google Android Developers, Espresso осигурява автоматична синхронизация с UI нишката, което елиминира нуждата от ръчно Thread.sleep().

Основни поинти

  • Espresso — рамка за UI тестване на Android с автоматична синхронизация на нишките.
  • ViewMatcher — търсене на View елемент на екрана по ID, текст, родителска йерархия.
  • ViewAction — действие над елемента: клик, въвеждане на текст, свийп.
  • ViewAssertion — проверка на състоянието на елемента: показва се, съдържа текст, активен е.
  • Idling Resource — механизъм за изчакване завършването на асинхронни операции преди проверка на UI.

Какво е Espresso?

Espresso е библиотека за писане на автоматизирани UI тестове за Android, която е част от Google AndroidX Test. Тя предоставя API за намиране на View елементи на екрана, извършване на действия върху тях (клик, въвеждане, свийп) и проверка на тяхното състояние (показва се, съдържа текст, активен е).

Ключовата характеристика на Espresso е автоматичната синхронизация с главната нишка на приложението. Рамката изчаква завършването на всички асинхронни задачи (корутини, AsyncTask, Handler) преди да извърши следващата проверка. Това елиминира flaky тестовете, свързани с race condition, и прави UI тестовете стабилни и надежди — нитоедин тест няма Thread.sleep() или цикъли на изчакване.

Espresso следва принципа Three-Legged Dog — тестът се състои от три стъпки: намерете елемента (ViewMatcher), извършете действието (ViewAction), проверете резултата (ViewAssertion). И трите стъпки се записват в верига от повикания onView().perform().check(). Тази концепция прави тестовете предвидими и лесно четими — всеки тест ясно описва какво търси, какво прави и какво проверява.

Как работи Espresso

Архитектурата на Espresso се базира на три компонента: Espresso (входна точка — статични методи onView и onData), ViewMatchers (търсене на елементи), ViewActions (действия) и ViewAssertions (проверки). Вътрешно, рамката използва Idling Resource за синхронизация с UI нишката.

Базов Espresso тест

Най-простият тест намира бутон по ID, извършва клик и проверява дали се появява текстът „Готово“. Всички операции се извършват синхронно от гледна точка на теста — Espresso гарантира, че UI нишката е приключила обработката на събитието, преди тестът да продължи изпълнението си. Това се постига чрез вграден механизъм на изчакване: onView блокира изпълнението на теста, докато UI не стане стабилен.

kotlin
@Test
fun buttonClick_showsSuccessText() {
    // Намиране на бутон по ID и кликане
    onView(withId(R.id.button_submit))
        .perform(click())

    // Проверка дали се показва текстът „Готово“
    onView(withText("Готово"))
        .check(matches(isDisplayed()))
}

Правило ActivityScenario

За стартиране на Espresso тест се използва ActivityScenario (AndroidX Test), който създава Activity в желаното състояние — работещо, паузирано, унищожено. ActivityScenario позволява тестване на жизнения цикъл на Activity наред с чисто UI. Например, може да се провери, че данните се запазват при завъртане на екрана (пресъздаване на Activity) и се възстановяват след унищожение.

ViewMatchers са набор от методи от класа Espresso.onView, които позволяват намиране на View на екрана по различни критерии: идентификатор на ресурс (R.id), текст, hint-указание, родителски елемент и йерархия. Ако един matcher не дава уникален резултат, matcher-ите се комбинират чрез allOf().

MatcherПредназначение
withId(R.id.name)Търсене по ID на ресурс
withText(„текст“)Търсене по показан текст
withHint(„указание“)Търсене по hint атрибут на EditText
isDisplayed()Проверка дали елементът е видим на екрана
hasSibling(matcher)Търсене по съседен елемент
allOf(m1, m2)Комбинация от няколко matcher-а

Комбинация на matcher-и

Ако на екрана има няколко еднакви елемента (например, два TextView с различен текст), удобно е да се комбинират matcher-ите чрез allOf: onView(allOf(withId(R.id.title), withText(„Здравей“))). Това гарантира избор на единствен елемент. Обратният оператор — not() — изключва елементи от търсенето, а hasSibling() търси елемент до познат елемент.

ViewActions: взаимодействие с UI

ViewActions са действия, които Espresso извършва над намереното View: click(), typeText(), clearText(), scrollTo(), swipeLeft() и други. Действията се предават на метода perform(), който може да приеме няколко действия подред.

Верига от действия

Методът perform() приема vararg ViewAction, което позволява извършване на последователност от действия върху един елемент: изчистване на полето, въвеждане на нов текст, затваряне на клавиатурата и натискане на бутона. Всички действия се извършват в реда, в който са изброени, и Espresso гарантира, че предишното действие е приключено преди започването на следващото.

kotlin
// Въвеждане на текст в EditText и натискане на бутон
onView(withId(R.id.edit_email))
    .perform(
        clearText(),
        typeText("user@example.com"),
        closeSoftKeyboard()
    )

onView(withId(R.id.button_login))
    .perform(click())

Проверка чрез onData

За елементи в AdapterView (ListView, RecyclerView) се използва методът onData() вместо onView. Той работи с данните на адаптера, а не с View — намира елемента по съдържанието на модела и връща съответното View за по-нататъшни действия. onData използва hamcrest matcher-и за намиране на елемента по полета на модела на данните.

ViewAssertions: проверка на състоянието

ViewAssertions проверяват дали View се намира в определено състояние. Основният метод — matches(matcher) — проверява дали елементът съвпада с дадения matcher. Допълнително, Espresso предлага doesNotExist() (елементът не съществува) и selectedDescendantsMatch() (проверка на вложени елементи).

Типични проверки

Най-често срещаните проверки в UI тестове: елементът се показва (isDisplayed), елементът съдържа определен текст (withText), елементът е активен (isEnabled), елементът не е избран (isNotChecked). Всяка проверка хвърля подробно изключение при неуспех — с посочване на View йерархията на екрана. Това опрощава отлавянето: в съобщението за грешка се вижда кои елементи реално са били на екрана в момента на проверката.

Персонализирани ViewAssertions

Ако стандартните проверки не са достатъчни, може да създадете собствена чрез интерфейса ViewAssertion. Персонализираният assertion получава View и може да провери неговото състояние програмен — например, цвят на текста, полета или състояние на персонализиран компонент, който не е изложен чрез стандартните matcher-и.

kotlin
// Проверка: TextView се показва и съдържа текст
onView(withId(R.id.text_welcome))
    .check(matches(isDisplayed()))
    .check(matches(withText("Добре дошли")))

// Проверка: елементът не се показва
onView(withId(R.id.progress_bar))
    .check(doesNotExist())

Idling Resources за асинхронни операции

Idling Resource е механизъм на Espresso за синхронизиране на теста с асинхронни операции. По подразбиране, Espresso изчаква завършването на Handler, AsyncTask и корутини (чрез coroutinesIdlingResource). Ако приложението извършва фонова работа чрез собствени нишки или Callback услуги, трябва да регистрирате персонализиран Idling Resource.

Пример с корутини

От AndroidX Test 1.4.0 нататък, Espresso поддържа корутини чрез CoroutinesIdlingResource. Тестът автоматично изчаква завършването на всички стартирани корутини, преди да извърши UI проверки. За по-сложни сценарии се използва CountingIdlingResource — брояч, който се увеличава при стартиране на задача и намалява при завършване.

kotlin
// Регистрация на IdlingResource за OkHttp
class OkHttpIdlingResource(
    private val client: OkHttpClient
) : IdlingResource {

    private var isIdle = true
    private var watcher: IdlingResource.ResourceCallback? = null

    override fun getName() = "OkHttp"

    override fun isIdleNow() = isIdle

    override fun registerIdleTransitionCallback(
        callback: IdlingResource.ResourceCallback
    ) {
        watcher = callback
    }
}

Настройка на Espresso в Android проект

Свързване На Espresso в Android проект се осъществява чрез добавяне на зависимости в build.gradle на ниво модул. Espresso е част от AndroidX Test, така че е достатъчно да посочите зависимости за ядрото на Espresso, разширенията и JUnit интеграцията. Тестовете се поставят в директория назована src/androidTest и се пускат на физическо устройство или емулатор чрез AndroidJUnitRunner.

Gradle конфигурация

Минималният набор от зависимости включва espresso-core (ядро), espresso-contrib (допълнителни matcher-и за RecyclerView, Drawer, Picker) и runner (тестов раннер на AndroidX). Всички тестове се пускат на емулатор или физическо устройство чрез Android Test Orchestrator.

kotlin
// build.gradle.kts (androidTest dependencies)
android {
    defaultConfig {
        testInstrumentationRunner =
            "androidx.test.runner.AndroidJUnitRunner"
    }
}

dependencies {
    androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")
    androidTestImplementation("androidx.test.espresso:espresso-contrib:3.6.1")
    androidTestImplementation("androidx.test:runner:1.6.1")
    androidTestImplementation("androidx.test:rules:1.6.1")
}

Пускане на тестовете на CI

Espresso тестовете могат да се пускат чрез Google Android Test Orchestrator, който изолира всяка проба в отделен процес и изчиства състоянието между пусканията. Това елиминира flaky тестовете, свързани с остатъчни данни от предишни тестове, и повишава стабилността на CI сървърите. За паралелно пускане се използва sharding — разпределяне на тестовете между няколко емулатора.

Често задавани въпроси

С какво Espresso се различава от UI Automator?

Espresso работи в процеса на приложението и използва автоматична синхронизация с UI нишката. UI Automator работи на ниво система, може да взаимодейства с други приложения, но изисква ръчно управление на изчакването.

Защо Espresso се нарича рамка с „трикракое куче“?

Това е метафора от презентацията на Google: тестът на Espresso стои на три стълба — ViewMatcher (търсене), ViewAction(действие) и ViewAssertion(проверка). Ако премахнете която и да е от тях, тестът губи стабилност, като трикрако куче.

Как да тестваме RecyclerView чрез Espresso?

За RecyclerView се използва библиотеката espresso-contrib и методите onView(withId(R.id.recycler)).perform(actionOnItemAtPosition(0, click())). Алтернатива — onData() за AdapterView или персонализиран ViewAction за търсене на елемент по текст в RecyclerView. Допълнително може да се използва RecyclerViewActions от espresso-contrib за превъртане към елемента и действия върху него.

Какво е flaky тест и как Espresso се бори с него?

Flaky тест е тест, който понякога се провалява без промяна на кода, поради race condition или асинхронност. Espresso решава този проблем чрез Idling Resource — изчакване завършването на всички фонови задачи преди извършване на проверката.

Може ли да се използва Espresso за скриншот тестване?

Самото Espresso не е предназначено за скриншот тестове, но може да се комбинира с библиотеки като Shot или Paparazzi. Espresso подготвя UI в желаното състояние, а библиотеката за сравнение прави снимка и го сравнява с референца. Този подход се нарича визуално регресионно тестване и помага за откриване на неочаквани промени в интерфейса.

Обобщение

  • Espresso — рамка за UI тестване на Android от Google с автоматична синхронизация.
  • ViewMatchers — API за търсене на елементи по ID, текст, йерархия и комбинации.
  • ViewActions — click, typeText, scrollTo, swipe за взаимодействие с UI.
  • ViewAssertions — matches, doesNotExist за проверка на състоянието на елементите.
  • Idling Resource — синхронизиране на теста с асинхронни операции и корутини.
  • Три стъпки — onView().perform().check() = намери, направи, провери.
  • AndroidX Test — библиотеки за пускане на инструментални тестове на емулатор или устройство.

Ще разработим мобилно приложение под ключ

IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също