Тестирование интерфейса с Espresso
Пишите автоматизированные тесты интерфейса с Espresso. Находите представления через onView(), взаимодействуйте с ними через perform(), проверяйте состояние с помощью check() и тестируйте взаимодействия с RecyclerView.
«Тестирование интерфейса с Espresso» — бесплатный урок Android Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Android Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Android Academy содержит 4 уроков всего.
Что такое Espresso?
Espresso — официальный фреймворк Android для тестирования интерфейса. Он позволяет писать тесты, которые взаимодействуют с интерфейсом приложения: нажимают кнопки, вводят текст, прокручивают списки — и проверяют отображаемое на экране.
Espresso выполняется на устройстве или эмуляторе (инструментальный тест) и автоматически синхронизируется с потоком интерфейса — вызовы sleep() с ненадёжными задержками не нужны.
Настройка
Espresso входит в набор инструментов тестирования Android. Добавьте эти зависимости в app/build.gradle:
// app/build.gradle:
android {
defaultConfig {
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
}
dependencies {
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.5.1' // RecyclerView
}ActivityScenarioRule
Используйте ActivityScenarioRule, чтобы запускать Activity перед каждым тестом и закрывать её после:
@RunWith(AndroidJUnit4::class)
class LoginActivityTest {
@get:Rule
val activityRule = ActivityScenarioRule(LoginActivity::class.java)
@Test
fun `login button is displayed`() {
onView(withId(R.id.btnLogin))
.check(matches(isDisplayed()))
}
}onView() и ViewMatchers
onView(matcher) находит представление в текущей иерархии. Для точности объединяйте сопоставители:
// Match by ID:
onView(withId(R.id.tvTitle))
// Match by text:
onView(withText("Submit"))
// Match by content description (for accessibility):
onView(withContentDescription("Close dialog"))
// Combine matchers:
onView(allOf(withId(R.id.btnSave), isEnabled()))
// Inside a specific parent:
onView(withId(R.id.btnSave)).inRoot(isDialog())ViewActions — взаимодействие с представлениями
Найдя представление, выполните действие с помощью .perform():
// Tap a button:
onView(withId(R.id.btnLogin)).perform(click())
// Type into an EditText:
onView(withId(R.id.etEmail))
.perform(typeText("alice@example.com"), closeSoftKeyboard())
// Clear text and retype:
onView(withId(R.id.etPassword))
.perform(clearText(), typeText("secret123"), closeSoftKeyboard())
// Scroll to a view:
onView(withId(R.id.btnSubmit)).perform(scrollTo(), click())
// Long press:
onView(withId(R.id.ivImage)).perform(longClick())ViewAssertions — проверка состояния
Проверьте отображаемое на экране с помощью .check():
// View is displayed:
onView(withId(R.id.tvError)).check(matches(isDisplayed()))
// View has specific text:
onView(withId(R.id.tvTitle)).check(matches(withText("Welcome!")))
// View is not displayed (GONE or INVISIBLE):
onView(withId(R.id.progressBar)).check(matches(not(isDisplayed())))
// View is enabled:
onView(withId(R.id.btnSave)).check(matches(isEnabled()))
// View does not exist:
onView(withId(R.id.tvError)).check(doesNotExist())Полный тест входа
Полный тест, который вводит учётные данные и нажимает кнопку входа:
@Test
fun `successful login shows home screen`() {
// Type email
onView(withId(R.id.etEmail))
.perform(typeText("alice@example.com"), closeSoftKeyboard())
// Type password
onView(withId(R.id.etPassword))
.perform(typeText("password123"), closeSoftKeyboard())
// Tap login button
onView(withId(R.id.btnLogin)).perform(click())
// Assert welcome message is shown
onView(withId(R.id.tvWelcome))
.check(matches(withText("Welcome, Alice!")))
}Тестирование RecyclerView
Используйте RecyclerViewActions из espresso-contrib, чтобы взаимодействовать с элементами списка:
import androidx.test.espresso.contrib.RecyclerViewActions
@Test
fun `clicking item opens detail screen`() {
// Scroll to position 5 and click:
onView(withId(R.id.recyclerView))
.perform(RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(
5, click()
))
// Assert detail screen is shown:
onView(withId(R.id.tvDetailTitle)).check(matches(isDisplayed()))
}Тестирование проверки ввода
Проверьте, что при недопустимом вводе появляются сообщения об ошибке:
@Test
fun `empty email shows error message`() {
// Leave email blank, tap login
onView(withId(R.id.btnLogin)).perform(click())
// Assert error is shown
onView(withId(R.id.tilEmail))
.check(matches(hasDescendant(withText("Email is required"))))
}
@Test
fun `short password shows error`() {
onView(withId(R.id.etPassword))
.perform(typeText("123"), closeSoftKeyboard())
onView(withId(R.id.btnLogin)).perform(click())
onView(withId(R.id.tilPassword))
.check(matches(hasDescendant(withText("Minimum 6 characters"))))
}Ресурсы ожидания
Espresso автоматически ждёт освобождения потока интерфейса, но не ждёт завершения сетевых вызовов или сопрограмм. Используйте IdlingResource, чтобы сообщить Espresso, что нужно дождаться асинхронной работы:
// CountingIdlingResource: increment before async work, decrement when done
val idlingResource = CountingIdlingResource("NetworkCall")
// In your ViewModel/Repository:
idlingResource.increment()
viewModelScope.launch {
loadData()
idlingResource.decrement()
}
// In test setUp:
@Before
fun setUp() {
IdlingRegistry.getInstance().register(idlingResource)
}
@After
fun tearDown() {
IdlingRegistry.getInstance().unregister(idlingResource)
}Запуск тестов Espresso
Запускайте инструментальные тесты на подключённом устройстве или эмуляторе:
- В Android Studio: щёлкните тестовый класс правой кнопкой мыши → «Запустить»
- В терминале:
./gradlew connectedAndroidTest - Результаты появятся в
app/build/reports/androidTests/
Используйте эмулятор Android с API 28+ для стабильного и быстрого выполнения тестов. Отключите анимации в настройках разработчика, чтобы предотвратить нестабильность.
Быстрая проверка
Каков правильный шаблон Espresso для поиска представления и проверки его текста?
Итоги: тестирование интерфейса с Espresso
Автоматизированное тестирование интерфейса обнаруживает регрессии раньше пользователей:
onView(matcher)— найти представление.perform(action)— нажать, ввести текст, прокрутить.check(matches(...))— проверить видимость, текст и состояниеRecyclerViewActions— для взаимодействия со спискамиIdlingResource— для асинхронных операций- Отключайте системные анимации, чтобы предотвратить нестабильность тестов
Далее: отладка и профилирование приложения на профессиональном уровне.
Часто задаваемые вопросы
Урок «Тестирование интерфейса с Espresso» бесплатный?
Да — полный текст урока «Тестирование интерфейса с Espresso» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Android Academy, подпишись на CoddyKit PRO. Курс Android Academy содержит 4 уроков всего.
Чему я научусь в уроке «Тестирование интерфейса с Espresso»?
Пишите автоматизированные тесты интерфейса с Espresso. Находите представления через onView(), взаимодействуйте с ними через perform(), проверяйте состояние с помощью check() и тестируйте взаимодейств… Ты практикуешь Android Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Android Academy?
Предыдущий опыт не требуется. Android Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Тестирование интерфейса с Espresso»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Android Academy?
Да. Каждый урок Android Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Модульное тестирование с JUnit
- Имитация объектов с Mockito
- Тестирование интерфейса с Espresso
- Отладка и профилирование