- PVSM.RU - https://www.pvsm.ru -
Тестирование является важной составляющей процесса разработки приложения. Для Android тестирование особенно важно, так как устройства сильно отличаются друг от друга:
Поэтому тестировать приложение приходится на множестве устройств.
В процесс тестирования входят различные виды тестирования. Рассмотрим, как происходит процесс функционального тестирования приложения вручную. Тестировщик устанавливает на устройство приложение, вдумчиво проверяет всю функциональность, затем возвращает устройство в первоначальное состояние. И так для каждого приложения и каждого устройства. Очевидный недостаток такого способа – большие затраты времени для регулярного тестирования.
Очевидный плюс автоматизированного тестирования – его можно регулярно проводить без особых затрат. Например, каждую ночь тестировать свежий билд приложения на всем множестве имеющихся устройств, а утром анализировать результаты и исправлять ошибки.
В данной заметке будут рассмотрены средства реализации автоматического тестирования. Рассматриваются только инструменты, входящие в Android SDK или распространяющиеся под Open Source лицензией.
Задача — с наибольшей точностью автоматизировать действия, которые выполняет тестировщик. Давайте их рассмотрим. В наличии есть несколько приложений и несколько Android устройств. Для каждого приложения и каждого устройства выполняются следующие шаги:
На каждом шаге нужно собрать и проанализировать данные, например логи и скриншоты. Затем на основе этих данных сформировать результат тестирования.
Далее рассматриваются средства, позволяющие автоматизировать перечисленные шаги.
Для начала нужно выделить компьютер на котором будет запускаться автоматическое тестирование и настроить на нем Android SDK [1]. Примеры приводятся для компьютера с установленной ОС Linux.
На всех тестируемых устройствах нужно отключить экран блокировки и максимально увеличить время ожидания. Для некоторых методов тестирования нужно отключить смену ориентации экрана.
В Android SDK имеются две утилиты для управления устройствами: adb и MonkeyRunner.
Я постараюсь подробно описать автоматизацию действий, использующихся при тестировании. Тем, кто знаком с ADB и MonkeyRunner имеет смысл сразу переходить к разделу «Способы автоматизированного тестирования [2]».
ADB (Android Debug Bridge) – утилита для управления Android устройствами из командной строки. Официальная документация по ADB: developer.android.com/tools/help/adb.html [3]
Утилита adb находится в директории <android_sdk>/platform-tools/
. Путь к данной директории рекомендуется прописать в переменной окружения PATH
.
Устанавливаем и настраиваем Android SDK, подключаем к компьютеру Android устройства и выполняем команду:
adb devices
Команда выдаст список всех подключенных устройств. Если список устройств не пуст, значит ADB настроен и работает.
Чтобы указать ADB с каким устройством нужно работать, следует прописать серийный номер устройства после ключа -s
:
adb -s <serial_number> <command>
Например:
adb -s <serial_number> logcat
Серийный номер устройства можно посмотреть командой adb devices
. Ключ -s
позволяет работать одновременно с несколькими подключенными устройствами. В дальнейшем ключ -s
в командах я указывать не буду.
Открыть консоль на устройстве:
adb shell
Запустить команду на устройстве:
adb shell <command>
В Android присутствуют многие стандартные утилиты Linux: ls, cat, dmesg,…
Установить приложение из apk файла:
adb install example.apk
Удалить приложение:
adb uninstall <package>
Название package можно получить из apk файла командой:
aapt dump badging example.apk | grep "package"
Загрузить файл с устройства на компьютер:
adb pull <path-on-device> <file>
Загрузить файл с компьютера на устройство:
adb push <file> <path-on-device>
Примечание:
В большинство директорий на устройстве разрешен доступ только на чтение. Доступ на запись разрешен в директорию /sdcard
(из нее нельзя запускать программы) и /data/local/tmp/
.
Запуск приложения:
adb shell am start -n <package>/<activity>
Запускает указанную activity. Название activity, которая запускается при выборе приложения в меню можно получить из apk файла командой:
aapt dump badging example.apk | grep "launchable-activity"
Чтение логов в Android производится утилитой logcat.
Домашняя страница утилиты logcat: developer.android.com/tools/help/logcat.html [4]
Считать логи с устройства (блокируется до нажатия Ctrl-C):
adb logcat
Очистить буфер логов на устройстве:
adb logcat -c
Считать буфер логов на устройстве (выдает текущее содержимое буфера, не блокируется):
adb logcat -d
Пример:
adb logcat -c # очищаем буфер логов
# выполняем действие
adb logcat -d > file.log # сохраняем текущее содержимое буфера логов в file.log
Утилита screencap сохраняет текущее содержимое экрана в графический файл:
adb shell screencap /sdcard/screen.png
adb pull /sdcard/screen.png screen.png
adb shell rm /sdcard/screen.png
Утилита screencap
имеется на телефонах с Android 4.x и выше. На предыдущих версиях Android снятие скриншотов можно производить с помощью MonkeyRunner.
#!/bin/bash
#-------------------------------------------------------------------------------
# Пример BASH скрипта для автоматического тестирования приложения c помощью ADB
#
# Скрипт:
# 1. Устанавливает приложение
# 2. Запускает приложение
# 3. Тестирует приложение с помощью monkey
# 4. Удаляет приложение
#
# На каждом шаге собираются и сохраняются log-файлы.
#-------------------------------------------------------------------------------
APK="example.apk"
PACKAGE="com.example.package"
ACTIVITY="com.example.package.activity"
rm -rf log
mkdir log
# 1. Устанавливаем приложение
adb uninstall $PACKAGE # удаляем приложение
adb logcat -c # очищаем буфер логов
adb install $APK # устанавливаем приложение
adb logcat -d > log/install.log # записываем логи установки приложения
# 2. Запускаем приложение
adb logcat -c
adb shell am start -n $PACKAGE/$ACTIVITY # запускаем приложение
sleep 10 # ожидаем 10 сек чтобы приложение полностью загрузилось
adb logcat -d > log/start.log
# 3. Тестируем приложение
adb logcat -c
# тестируем приложение с помощью monkey
adb shell monkey --pct-touch 70 -p $PACKAGE -v 1000 --throttle 500
adb logcat -d > log/test.log
# 4. Удаляем приложение
adb logcat -c
adb uninstall $PACKAGE
adb logcat -d > log/uninstall.log
Утилита MonkeyRunner предоставляет API для написания скриптов, которые управляют Android устройстами. С помощью MonkeyRunner можно написать скрипт на языке Python, который устанавливает Android приложение, запускает его, имитирует действия пользователя, снимает скриншоты и сохраняет их на компьютер. Утилита MonkeyRunner использует Jython [5] для выполнения скриптов.
Домашняя страница утилиты MonkeyRunner и описание API: developer.android.com/tools/help/monkeyrunner_concepts.html [6]
Файл log.py:
# coding: utf-8
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice
def log(fn, device):
msg = device.shell('logcat -d')
f_log = open(fn, 'at')
if msg is None:
msg = 'None'
f_log.write(msg.encode('utf-8'))
f_log.close()
device.shell('logcat -c')
if __name__ == '__main__':
device = MonkeyRunner.waitForConnection()
device.shell('logcat -c') # Очищаем буфер логов
# ...
log('example.log', device) # Записываем логи
Запуск:
monkeyrunner log.py
Скрипт запишет логи в файл example.log
в текущей директории.
Файл screen.py:
# coding: utf-8
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice
if __name__ == '__main__':
device = MonkeyRunner.waitForConnection()
image = device.takeSnapshot()
image.writeToFile('screenshot.png','png')
Запуск:
monkeyrunner screen.py
Скрипт снимает скриншот и сохраняет его в файл screenshot.png
в текущей директории.
# coding: utf-8
import time
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice
APK = "example.apk"
PACKAGE = "com.example.package"
ACTIVITY = "com.example.package.activity"
def log(fn, device):
msg = device.shell('logcat -d')
f_log = open(fn, 'at')
if msg is None:
msg = 'None'
f_log.write(msg.encode('utf-8'))
f_log.close()
device.shell('logcat -c')
if __name__ == '__main__':
device = MonkeyRunner.waitForConnection()
device.removePackage(PACKAGE) # Удаляем пакет, если он уже установлен
device.shell('logcat -c') # Очищаем буфер логов
device.installPackage(APK) # Устанавливаем приложение
log('install.log', device) # Записываем логи установки приложения
run_component = PACKAGE + '/' + ACTIVITY
device.startActivity(component=run_component) # Запускаем activity
time.sleep(10) # Ждем 10 сек
log('start.log', device) # Записываем логи запуска приложения
device.press('KEYCODE_MENU', MonkeyDevice.DOWN_AND_UP) # Открываем меню
screen = device.takeSnapshot() # Снимаем скриншот
screen.writeToFile('screenshot.png', 'png') # Сохраняем в screenshot.png
log('run.log', device) # Записываем логи тестирования приложения
device.removePackage(PACKAGE) # Удаляем пакет
log('uninstall.log', device) # Записываем логи удаление приложения
Запуск:
monkeyrunner monkeyrunner_test.py
Представьте, что устройство попало в цепкие лапы очень активной и творческой обезьяны – утилита monkey призвана имитировать подобную ситуацию.
Утилита monkey входит в состав Android SDK. Утилита отправляет на устройство поток псевдо-случайных действий пользователя. Параметры командной строки задают количество действий пользователя, соотношение их типов и имя тестируемого пакета, чтобы, например, обезьяна не вышла за пределы тестируемого приложения и не начала рассылать SMS по всем контактам из адресной книги.
Примеры использования и перечень параметров приведены на домашней странице: developer.android.com/tools/help/monkey.html [7]
Главное достоинство monkey – отсутствие затрат на поддержку. Кроме того, стресс-тестирование приложения потоком произвольных событий может обнаружить нетривиальные ошибки.
Недостатки тестирования утилитой monkey:
С помощью утилиты monkey можно без усилий протестировать любое приложение – это неплохая отправная точка. Возможно, что этот способ покажет адекватные результаты для конкретного приложения. Если же качество тестирования неудовлетворительное, то следует воспользоваться другими способами тестирования.
При помощи скриптов использующих MonkeyRunner API можно не только разработать основу для тестирующей системы, но и написать скрипты для тестирования конкретного приложения на конкретном устройстве.
Достоинства:
Недостатки:
Как правило, этот способ не оправдан – написание скриптов занимает много времени. Однако в частных случаях этот способ может сработать.
Утилиты getevent и sendevent позволяют записать последовательность действий пользователя, а затем воспроизвести эту последовательность. Утилиты находятся на самом Android-устройстве и не требуют для работы root-доступа.
Достоинства:
Недостатки:
Запись последовательности действий:
# Записываем последовательность событий
# выполняем действия на устройстве, по окончанию нажимаем Ctrl-C
adb shell getevent -t > events.txt
# Преобразуем последовательность в исполняемый скрипт
./decode_events.py events.txt > events.sh
# Загружаем скрипт на устройство
adb push events.sh /data/local/tmp/
# Устанавливаем права на запуск
adb shell chmod 755 /data/local/tmp/events.sh
# Запускаем скрипт
adb shell sh /data/local/tmp/events.sh
#!/usr/bin/python
# coding: utf-8
USAGE = """Скрипт преобразует вывод команды getevent в исполняемый shell-скрипт,
воспроизводящий записанные действия с помощью команд sendevent и sleep.
Использование:
./decode_events.py input.txt > output.sh
"""
import re
import sys
# [ 43319.628481] /dev/input/event1: 0003 0039 ffffffff
# 48470-342082: /dev/input/event1: 0000 0000 00000000
_re = re.compile(r'[^d]*(?P<sec>d+)[.-](?P<msec>d+)[:]] (?P<device>[^:]+):'
' (?P<class>[0-9a-f]+) (?P<event>[0-9a-f]+) (?P<params>[0-9a-f]+)')
T_FIX = 0.1
last_time = None
if __name__ == '__main__':
if len(sys.argv) < 2:
print USAGE
sys.exit(1)
print '#!/bin/sh'
input_fn = sys.argv[1]
for line in open(input_fn, 'rt'):
m = _re.match(line)
if m is not None:
d = m.groupdict()
cur_time = float(d['sec']) + float(d['msec'][:2])/100
if last_time is not None:
diff_time = (cur_time - last_time)
if diff_time > 0.2:
print 'sleep %.2f' % (diff_time-T_FIX,)
last_time = cur_time
print 'sendevent', d['device'], int(d['class'], 16),
int(d['event'], 16), int(d['params'], 16)
else:
print '#', line.strip('nrt ')
На устройстве должны воспроизвестись записанные действия.
В отличии от рассмотренных ранее способов Robotium не входит в состав Android SDK, а распространяется под Open Source лицензией.
Домашняя страница Robotium: code.google.com/p/robotium/ [8]
Главное отличие Robotium в том, что тестовые действия описываются на уровне интерфейса приложения. В рассмотренных ранее способах тестовые действия явно или неявно описывались на уровне устройств ввода.
Например, в приложении нужно нажать кнопку «OK». С помощью скрипта MonkeyRunner нажатие на кнопку реализуется как: «Коснуться точки экрана с координатами (x0, y0)». С помощью Robotium это реализуется как: «Нажать кнопку с текстом «OK»».
Когда действия описываются на уровне интерфейса приложения их можно сделать независимыми от расположения элементов интерфейса, разрешения экрана и положения устройства.
Кроме того, Robotium позволяет проверять реакцию приложения на действие.
Например, после нажатия на кнопку «OK» в приложении должен появиться список с элементом «Item 1». С помощью Robotium можно проверить, появился ли список с таким элементом.
Если выполнять проверки после каждого действия, то легко обнаружить, на каком шаге произошла ошибка.
Недостатки:
В целом, Robotium позволяет разрабатывать наиболее качественные сценарии тестирования при адекватных затратах.
Способ тестирования | Достоинства | Недостатки |
---|---|---|
Monkey – поток случайных действий пользователя. | Отсутствуют затраты на сопровождение. Не зависит от устройства. Стресс-тестирование позволяет обнаружить нетривиальные ошибки. |
Качество тестирования варьируется от приложения к приложению. Найденные ошибки сложно воспроизвести. Нет проверки состояния приложения. |
MonkeyRunner – скрипт управления устройством. | Гибкость. | Сложность написания и поддержки скриптов даже для простых приложений. |
getevent/sendevent – запись/воспроизведение действий пользователя. | Для записи последовательности действий не требуются навыки программирования. | Записанная последовательность действий подходит только к одному устройству при фиксированной ориентации. При изменении интерфейса приложения необходимо заново записать последовательность действий. Нет проверки состояния приложения. |
Robotium – сценарий тестирования интерфейса приложения с проверкой состояния. | Действия описываются на уровне интерфейса приложения. Сценарий может быть независимым от разрешения экрана и ориентации устройства. После совершения действия можно проверять состояние приложения. |
Сложность написания сценариев на языке Java. При изменении интерфейса приложения сценарий придется модифицировать. |
В результате тестирования приложения перечисленными выше способами мы получили логи и скриншоты. Теперь их нужно проанализировать на наличие ошибок.
Для начала можно сделать поиск по подстрокам:
Список можно дополнять по мере выявления ошибок в ходе ручного тестирования.
В процессе тестирования вручную можно подготовить серию скриншотов в ключевых моментах тестирования, а затем сравнивать их с содержимым экрана в процессе автоматизированного тестирования. Это позволит определить, правильно ли идет процесс автоматизированного тестирования и выявлять ошибки.
Также полезно сравнивать скриншот до и после запуска приложения – это позволяет определять случаи, когда приложение аварийно завершается без сообщений на экране и в логах.
MonkeyRunner позволяет сравнить два скриншота с заданным допуском в процентах:
image1 = device.takeSnapshot()
# ...
image2 = device.takeSnapshot()
if image2.sameAs(image1, 0.1):
print 'image1 and image2 are the same (10%)'
К сожалению, в API MonkeyImage не предусмотрена функция загрузки из файла. Поэтому для сравнения сохраненных скриншотов придется писать свою функцию, например с помощью Python Imaging Library [9].
После тестирования приложения устройство нужно вернуть в первоначальное состояние.
Этого можно достичь несколькими путями:
Рассмотрим первый вариант, как наиболее адекватный.
Нажимаем кнопку «Назад» используя MonkeyRunner:
for i in xrange(0, 10):
device.press('KEYCODE_BACK', MonkeyDevice.DOWN_AND_UP)
time.sleep(0.5)
На практике этот вариант оптимален, так как имитирует поведение реального пользователя.
В заметке были рассмотрены некоторые способы автоматического тестирования Android приложений, их достоинства и недостатки. Кроме того, рассмотрены инструменты, входящие в Android SDK или распространяющиеся под Open Source лицензией.
Хочется отметить, что автоматическое тестирование не является панацеей и не заменяет другие виды тестирования. Качественный продукт получается при грамотно построенном процессе тестирования, сочетающем различные способы.
Автор: rkhatko
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/testirovanie/16005
Ссылки в тексте:
[1] Android SDK: http://developer.android.com/sdk/index.html
[2] Способы автоматизированного тестирования: #testing_methods
[3] developer.android.com/tools/help/adb.html: http://developer.android.com/tools/help/adb.html
[4] developer.android.com/tools/help/logcat.html: http://developer.android.com/tools/help/logcat.html
[5] Jython: http://www.jython.org/
[6] developer.android.com/tools/help/monkeyrunner_concepts.html: http://developer.android.com/tools/help/monkeyrunner_concepts.html
[7] developer.android.com/tools/help/monkey.html: http://developer.android.com/tools/help/monkey.html
[8] code.google.com/p/robotium/: http://code.google.com/p/robotium/
[9] Python Imaging Library: http://www.pythonware.com/products/pil/
Нажмите здесь для печати.