Основы тестирования Android-приложений

На этой странице изложены основные принципы тестирования приложений для Android, включая ключевые рекомендации и их преимущества.

Преимущества тестирования

Тестирование является неотъемлемой частью процесса разработки приложений. Регулярно запуская тесты для своего приложения, вы можете проверить его корректность, функциональность и удобство использования до публичного выпуска.

Вы можете протестировать свое приложение вручную , пройдясь по нему. Можно использовать разные устройства и эмуляторы, изменить язык системы и попытаться сгенерировать все ошибки пользователя или пройти все сценарии взаимодействия с пользователем.

Однако ручное тестирование плохо масштабируется, и легко упустить из виду регрессии в поведении вашего приложения. Автоматизированное тестирование предполагает использование инструментов, которые выполняют тесты за вас, что быстрее, обеспечивает большую воспроизводимость и, как правило, позволяет получить более полезную обратную связь о вашем приложении на ранних этапах разработки.

Типы тестов в Android

Мобильные приложения — сложные разработки, требующие хорошей работы в самых разных средах. Поэтому существует множество типов тестирования.

Предмет

Например, существуют разные типы тестов в зависимости от предмета :

  • Функциональное тестирование : делает ли мое приложение то, что от него ожидается?
  • Тестирование производительности : выполняется ли оно быстро и эффективно?
  • Тестирование доступности : насколько хорошо оно работает с сервисами обеспечения доступности?
  • Тестирование на совместимость : хорошо ли оно работает на всех устройствах и на всех уровнях API?

Объем

Тесты также различаются в зависимости от размера или степени изоляции :

  • Модульные или небольшие тесты проверяют лишь очень малую часть приложения, например, метод или класс.
  • Сквозные тесты или масштабные тесты проверяют одновременно большие части приложения, например, весь экран или пользовательский сценарий.
  • Промежуточные тесты проверяют интеграцию между двумя или более модулями.
Тесты могут быть небольшими, средними или большими.
Рисунок 1 : Осциллографы в типичном приложении.

Существует множество способов классификации тестов. Однако для разработчиков приложений наиболее важным является то, где выполняются тесты.

Инструментальные и локальные тесты

Вы можете запускать тесты на устройстве Android или на другом компьютере:

  • Инструментальные тесты запускаются на устройстве Android, как физическом, так и эмулированном. Приложение собирается и устанавливается вместе с тестовым приложением , которое внедряет команды и считывает состояние. Инструментальные тесты обычно представляют собой тесты пользовательского интерфейса, запускающие приложение и последующее взаимодействие с ним.
  • Локальные тесты выполняются на вашей машине разработчика или сервере, поэтому их также называют тестами на стороне хоста . Обычно они небольшие и быстрые, изолируя тестируемый объект от остальной части приложения.
Тесты могут выполняться как инструментальные тесты на устройстве, так и локальные тесты на вашей машине разработчика.
Рисунок 2 : Различные типы тестов в зависимости от места их проведения.

Не все модульные тесты выполняются локально, и не все сквозные тесты запускаются на устройстве. Например:

  • Для масштабного локального тестирования можно использовать Android-симулятор, работающий локально, например, Robolectric .
  • Небольшой инструментальный тест : Вы можете проверить, хорошо ли ваш код работает с той или иной функцией фреймворка, например, с базой данных SQLite. Вы можете запустить этот тест на нескольких устройствах, чтобы проверить интеграцию с различными версиями SQLite.

Примеры

Следующие фрагменты кода демонстрируют, как взаимодействовать с пользовательским интерфейсом в инструментальном тесте пользовательского интерфейса , который при щелчке по элементу проверяет отображение другого элемента.

Эспрессо

// When the Continue button is clicked
onView(withText("Continue"))
    .perform(click())

// Then the Welcome screen is displayed
onView(withText("Welcome"))
    .check(matches(isDisplayed()))

Compose UI

// When the Continue button is clicked
composeTestRule.onNodeWithText("Continue").performClick()

// Then the Welcome screen is displayed
composeTestRule.onNodeWithText("Welcome").assertIsDisplayed()

Этот фрагмент кода демонстрирует часть модульного теста для ViewModel (локальный тест на стороне хоста):

// Given an instance of MyViewModel
val viewModel = MyViewModel(myFakeDataRepository)

// When data is loaded
viewModel.loadData()

// Then it should be exposing data
assertTrue(viewModel.data != null)

Тестируемая архитектура

При тестируемой архитектуре приложения код следует структуре, которая позволяет легко тестировать различные его части изолированно. Тестируемые архитектуры имеют и другие преимущества, такие как лучшая читаемость, удобство сопровождения, масштабируемость и повторное использование.

Архитектура, которую невозможно протестировать, приводит к следующему результату:

  • Более масштабные, медленные и нестабильные тесты. Классы, которые невозможно протестировать с помощью модульных тестов, возможно, придётся покрывать более масштабными интеграционными тестами или тестами пользовательского интерфейса.
  • Меньше возможностей для тестирования различных сценариев. Более масштабные тесты выполняются медленнее, поэтому тестирование всех возможных состояний приложения может оказаться нереалистичным.

Чтобы узнать больше о рекомендациях по архитектуре, ознакомьтесь с руководством по архитектуре приложений .

Подходы к разделению

Если вы можете выделить часть функции, класса или модуля из остальной части кода, тестирование становится проще и эффективнее. Эта практика известна как декомпозиция, и это концепция, наиболее важная для тестируемой архитектуры.

К распространенным методам разделения относятся следующие:

  • Разделите приложение на слои , такие как «Презентация», «Домен» и «Данные». Вы также можете разделить приложение на модули , по одному на каждую функцию.
  • Избегайте добавления логики к сущностям с большими зависимостями, таким как активности и фрагменты. Используйте эти классы в качестве точек входа во фреймворк, а логику пользовательского интерфейса и бизнес-логику перенесите в другое место, например, в Composable, ViewModel или слой предметной области.
  • Избегайте прямых зависимостей от фреймворков в классах, содержащих бизнес-логику. Например, не используйте Android Contexts в ViewModels .
  • Сделайте зависимости легко заменяемыми . Например, используйте интерфейсы вместо конкретных реализаций. Используйте внедрение зависимостей , даже если вы не используете фреймворк для внедрения зависимостей.

Следующие шаги

Теперь, когда вы знаете, почему нужно тестировать, и два основных типа тестов, вы можете прочитать статью «Что тестировать» или узнать о стратегиях тестирования.

В качестве альтернативы, если вы хотите создать свой первый тест и учиться на практике, ознакомьтесь с учебными материалами по тестированию .