Тестирование Activity


Тестирование Activity в основном зависит от instrumentation фреймворка Android (Android instrumentation framework). В отличие от других компонентов, activities имеют сложный жизненный цикл на основе методов обратного вызова, которые не могут быть вызваны напрямую, за исключением вызова с помощью instrumentation. Кроме того, единственным способом отправки событий пользовательскому интерфейсу из программы является отправка через instrumentation.

Этот документ описывает, как тестировать activities с помощью instrumentation и других средств тестирования. Документ предполагает, что вы уже прочитали Основы тестирования Android приложений – введение в тестирование Android и instrumentation фреймворк.

API тестирования Activity

API тестирования Activity базируется на классе InstrumentationTestCase, который предоставляет instrumentation для подклассов теста, которые вы используете для тестирования Activities.

Для тестирования activity этот базовый класс предоставляет следующие функции:

  • Контроль жизненного цикла: при помощи instrumentation, вы можете запускать activity во время тестирования, приостанавливать и уничтожать ее, используя методы, предоставляемые классом теста.
  • Внесение зависимостей: instrumentation позволяют создавать mock объекты системы, такие как Contexts или Applications и использовать их для выполнения activity во время тестирования. Это помогает вам контролировать тестовую среду и изолировать ее от рабочей системы. Вы также можете настроить свои Intents и запускать activity с ними.
  • Взаимодействие с пользовательским интерфейсом: вы можете использовать instrumentation для отправки событий (нажатий клавиш, прикосновений) непосредственно в пользовательский интерфейс activity во время тестирования.

Классы тестирования activity также поддерживают фреймворк JUnit, расширяя TestCase и Assert.

Два основных подкласса тестирования – это ActivityInstrumentationTestCase2 и ActivityUnitTestCase. Для тестирования activity, которая запускается в режиме, отличном от стандартного, можно использовать SingleLaunchActivityTestCase.

ActivityInstrumentationTestCase2

Класс тестовых случаев ActivityInstrumentationTestCase2 разработан для функционального тестирования одного или более Activities в приложении, используя нормальную инфраструктуру системы. Он запускает Activities в обычном экземпляре приложения во время тестирования, используя стандартный системный Context. Он позволяет отправлять mock Intents в activity во время тестирования, так что вы можете использовать его для проверки activity, которая отвечает на несколько типов intents, или activity, которая ожидает определенный тип данных в intent, или обеих сразу. Обратите внимание на то, что он не позволяет использовать mock объекты Contexts или Applications, поэтому вы не сможете изолировать тест от остальной части рабочей системы.

ActivityUnitTestCase

Класс тестовых случаев ActivityUnitTestCase – это класс тестов отдельной изолированной activity. Перед стартом activity, вы можете внедрить mock объект Context или Application, или оба сразу. Класс используется для выполнения тестов activity в изоляции и для модульного тестирования методов, которые не взаимодействуют с Android. Вы не можете отправлять mock Intents в деятельность во время тестирования, хотя вы можете вызвать Activity.startActivity(Intent) и посмотреть на аргументы, которые будут получены.

SingleLaunchActivityTestCase

Класс SingleLaunchActivityTestCase – это вспомогательный класс для тестирования одной activity в среде, которая не изменяется от теста к тесту. Он вызывает setUp() и tearDown() только один раз, вместо вызова в каждом методе, что не позволяет внедрять любые mock объекты.

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

Mock объекты и тестирование activity

Этот раздел содержит примечания об использовании mock объектов, определенных в android.test.mock при тестировании activity.

Mock объект MockApplication доступен для тестирования activity только, если вы используете тестовый классActivityUnitTestCase. По умолчанию ActivityUnitTestCase создает скрытый объект MockApplication, который используется в качестве тестируемого приложения. Вы можете внедрить ваш собственный объект, используя setApplication().

Assertions для тестирования activity

ViewAsserts определяет assertions для Views. Используется для проверки выравнивания и положения объектов View, и просмотра состояния объектов ViewGroup.

Что тестировать

  • Проверка ввода: проверка того, что activity отвечает корректно на входные значения в EditText View. Настраивает последовательность клавиш, отправляет ее activity, а затем используeт findViewById(int) для проверки состояния View. Вы можете проверить что последовательность клавиш правильная путем включения кнопки ОК, если она неправильна – кнопка отключена. Вы также можете проверить, что Activity, в ответ на неверный ввод, устанавливает сообщения об ошибках в View.
  • Жизненный цикл событий: тест, который проверяет корректность обработчиков событий жизненного цикла каждой activity вашего приложения. В общем, события жизненного цикла являются действиями системы или пользователя, которые выполняют методы обратного вызова, такие как OnCreate() или OnClick(). Например, activity должна реагировать на события паузы или уничтожения, сохранением своего состояния. Помните, что каждое изменение ориентации экрана является причиной для уничтожения текущей activity, поэтому вы должны проверить, что случайные движения устройства не приведут к потере состояния приложения.
  • Intents: тестирует корректность обработки каждого вида intent перечисленного в intent filter, который указан в манифесте. Вы можете использовать ActivityInstrumentationTestCase2 отправляя mock intents к каждой тестируемой activity.
  • Изменение конфигурации во время выполнения: тест того, что каждый вид activity корректно отвечает на возможные изменения в конфигурации устройства во время работы приложения. К ним относятся изменение ориентации устройства, изменение текущего языка и так далее. Обработка этих изменений подробно описана в разделе Handling Runtime Changes.
  • Размер экрана и разрешение: перед публикацией вашего приложения, протестируйте его на всех размерах и плотности экрана, на которых вы хотите запускать приложение. Вы можете протестировать приложение на нескольких размерах и плотностях при помощи AVD, или вы можете проверить ваше приложение непосредственно на устройствах, на которые вы ориентируетесь. Для получения дополнительной информации см. раздел Supporting Multiple Screens.

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

Чтобы узнать, как настроить и запустить тесты в Eclipse, пожалуйста, обратитесь к Testing in Eclipse, with ADT. Если вы не работаете в Eclipse, обратитесь к Testing in Other IDEs.

Если вам нужно пошаговое введение в тестирование Android, изучите один из учебников по тестированию или пример пакета теста:

  • В учебнике Hello, Testing рассматриваются основные понятия и процедуры тестирования в контексте приложения Hello, World.
  • Учебник Activity Testing является отличным дополнением учебника Hello, Testing. Он проведет вас через более комплексное тестирование сценариев, которые можно разрабатывать в отношении более реалистичного приложения.

Приложение: Заметки по тестированию пользовательского интерфейса

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

Тестирование в потоке пользовательского интерфейса

Activities приложения работают в потоке пользовательского интерфейса приложения (UI thread). После создания экземпляра UI, например методом OnCreate(), все взаимодействия с UI должны обрабатываться в потоке пользовательского интерфейса. Обычно при запуске приложение имеет доступ к этому потоку.

Все меняется, когда вы запускаете тесты приложения. С классами, основанными на instrumentation, вы можете вызывать методы пользовательского интерфейса тестируемого приложения. Другие классы тестов не позволяют это сделать. Чтобы запустить тестовый метод в потоке пользовательского интерфейса, вы можете аннотировать поток при помощи@UIThreadTest. Обратите внимание, что все заявленные методы будут работать в потоке пользовательского интерфейса. Методы, которые не взаимодействуют с UI не допускаются, например, вы не можете вызватьInstrumentation.waitForIdleSync().

Для запуска подмножества тестового метода в потоке пользовательского интерфейса, создайте анонимный класс типаRunnable, поместите нужные вам операторы в метод Run(), и создайте новый экземпляр класса в качестве параметра метода appActivity.runOnUiThread(), где appActivity является экземпляром тестируемого приложения.

Например, следующий код создает экземпляр activity для теста, получает фокус (действие UI) для Spinner отображаемого activity, затем отправляет событие нажатия клавиши к нему. Обратите внимание, что вызовы waitForIdleSync и SendKeys не разрешается запускать в потоке пользовательского интерфейса:

Отключение сенсорного режима

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

Чтобы отключить сенсорный режим, нужно вызвать ActivityInstrumentationTestCase2.setActivityTouchMode(false), прежде чем вызывать getActivity() для выполнения activity. Этот метод нужно вызывать из тестового метода, который не работает в потоке пользовательского интерфейса. По этой причине, вы не можете вызывать методы сенсорного режима из тестовых методов с аннотацией @UIThread. Вместо этого методы сенсорного режима вызываются из setUp().

Разблокирование эмулятора или устройства

Вы можете обнаружить, что тесты пользовательского интерфейса не работают, если эмулятор или домашний экран устройства заблокирован с помощью ключа блокировки. Это потому, что тестируемое приложение не может получить события нажатий клавиш присланные SendKeys(). Лучший способ избежать этого – это запустить эмулятор или устройство, а затем отключить ключ блокировки для домашнего экрана.

Также можно явно отключить ключ блокировки. Для этого необходимо добавить permission в файл манифеста (AndroidManifest.xml) в тестируемом приложении, а затем отключить ключ блокировки. Отметим, что вы должны либо удалить это до публикации вашего приложения, либо отключить в коде публикуемого приложения.

Чтобы добавить permission, добавьте элемент <uses-permission android:name="android.permission.DISABLE_KEYGUARD"/> в элемент <manifest>. Для отключения ключа блокировки, добавьте следующий код в метод OnCreate() каждой activity, которую нужно тестировать:

где activity_classname это имя класса activity.

Проблемы при тестировании пользовательского интерфейса

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

WrongThreadException

Проблема:
Для неудавшегося теста, Failure Trace содержит следующее сообщение об ошибке:android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
Вероятная причина:
Эта ошибка часто случается, если вы пытаетесь послать событие интерфейса в поток пользовательского интерфейса извне потока пользовательского интерфейса. Это обычно происходит, если вы отправляете события интерфейса из тестового приложения и не используете аннотацию @UIThread или метод runOnUiThread(). Т.е. метод теста пытается взаимодействовать с пользовательским интерфейсом вне потока пользовательского интерфейса.
Предлагаемое решение:
Выполнять взаимодействия в потоке пользовательского интерфейса. Использовать класс теста, который обеспечивает instrumentation. См. предыдущий раздел Тестирование в потоке пользовательского интерфейса для более подробной информации.

java.lang.RuntimeException

Проблема:
Для неудавшегося теста, Failure Trace содержит следующее сообщение об ошибке: java.lang.RuntimeException: This method can not be called from the main application thread
Вероятная причина:
Эта ошибка часто случается, если ваш тестовый метод с аннотацией @UiThreadTest но пытается сделать что-то вне потока пользовательского интерфейса или пытается вызвать runOnUiThread().
Предлагаемое решение:
Удалить аннотацию @UiThreadTest, удалить вызов runOnUiThread(), или сделайте рефакторинг тестов.

Источник

Перевод  kraY

Оставьте комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *