Основы тестирования 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()))

Интерфейс создания

// 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 в ViewModels .
  • Упростите замену зависимостей. Например, используйте интерфейсы вместо конкретных реализаций. Используйте внедрение зависимостей, даже если вы не используете фреймворк DI.

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

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

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