enter image description here


Appium и Calabash — одни из самых популярных фреймворков для автоматизации тестирования Android-приложений. У каждого, конечно, есть свои преимущества и недостатки. Их основные ограничения:


  • Calabash: может управлять только пользовательским интерфейсом, который является частью тестового приложения, в частности, нет поддержки тестирования уведомлений;


  • Appium: не может вызывать backdoor-методы в приложениях наподобие Calabash (эти методы очень полезны для настройки состояния тестируемого приложения).

Мы в Badoo пользовались Calabash для автоматизации тестирования, когда Appium только начинал развиваться. Это очень стабильный инструмент, и он до сих пор работает быстрее Appium, так что мы не собираемся мигрировать. Но чтобы автоматизировать такое многофункциональное приложение, как Badoo, нам пришлось обойти ограничение Calabash на работу только с интерфейсом тестового приложения.


Когда-то мы пришли к такому решению. И хотя оно ещё работает, его надёжность снижается из-за множества вариаций устройств с разной диагональю, разными версиями Android и так далее.


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


Осознание проблемы


Давайте посмотрим на высокоуровневую архитектуру Calabash-Android:


enter image description here


Calabash-Android-Server использует фреймворк Robotium, который в свою очередь для управления приложением использует Android-фреймворк Instrumentation. Instrumentation даёт Robotium (а следовательно, и Calabash) доступ к среде исполнения, что позволяет тому управлять интерфейсом приложения и осуществлять вызов методов извне.


Но это также означает, что Robotium может управлять лишь пользовательским интерфейсом, являющимся частью кода приложения. В Appium нет такого ограничения, поскольку он использует UIAutomator.


Решение проблемы


Фреймворк Google Instrumentation является частью вспомогательной Android-библиотеки для тестирования. Он работает в контексте приложения, показывает все взаимодействия системы с приложением и, значит, может управлять ими. На базе Instrumentation построены такие популярные фреймворки для тестирования, как Robotium и Espresso.


Кроме того, Robotium используется в серверной части Calabash-Android и поэтому имеет доступ к информации Instrumentation. Также частью Instrumentation в своё время стал UIAutomator 2.0, что даёт возможность его использования внутри сервера Calabash-Android.


С помощью CalabashInstrumentationTestRunner Ruby-клиент Calabash запускает Instrumentation через ADB. В сервере Calabash CalabashInstrumentationTestRunner является расширением Android-класса Instrumentation. Это объект Instrumentation, передаваемый в Robotium Solo. Благодаря UIAutomator 2, он может быть использован для создания нового объекта UIDevice, который способен управлять всем устройством.


enter image description here


Вот как я пришёл к решению проблемы:


1) Добавил библиотеку UIAutomator в сервер Calabash-Android


Я клонировал проект Сalabash-Android-Server и добавил JAR uiautomator2 в папку lib.


2) Инстанцировал объект UIDevice


В файле InstrumentationBackend.java я создал метод для инстанцирования объекта UIDevice из UIAutomator.


public static UiDevice getUiDevice() {
    if (instrumentation.getUiAutomation() == null) {
        throw new NullPointerException("uiAutomation==null: did you forget to set '-w' flag for 'am instrument'?");
    }
    if(uiDevice == null) {
        uiDevice = UiDevice.getInstance(instrumentation);
    }
    return uiDevice;
}

3) Добавил новую команду с помощью API UIAutomator2


Совсем несложно добавить в Calabash-Android-Server новую команду. Все команды, которые вы используете в коде Ruby, мапятся в интерфейс Actions:


sh.calaba.instrumentationbackend.actions

Давайте реализуем действие для открытия панели уведомлений:


public class PullNotification implements Action {
    @Override
    public Result execute(String... args) {
        InstrumentationBackend.getUiDevice().openNotification();
        return new Result(true);
    }

    @Override
    public String key() {
        return "pull_notification";
    }
}

В этом примере метод key() использован для наименования команды, которая будет использоваться Ruby-клиентом Calabash. При вызове этой команды клиентом она запускает метод execute().


4) Запустил измерение (Instrumentation) с флагом -w


Клонировал Ruby-клиент из https://github.com/calabash/calabash-android. Пропатчил lib/calabash-android/operations.rb и добавил флаг -w в запуск измерения с использованием команды ADB. Как это сделать, можно посмотреть в этом коммите.


Вышеописанные примеры можно посмотреть в моём форке:



Работающий пример:


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


  • Клонируйте оба репозитория из вышеупомянутого форка в каталог того же уровня.
    git clone https://github.com/rajdeepv/calabash-android
    git clone https://github.com/rajdeepv/calabash-android-server


  • В обоих репозиториях переключитесь на ветку ‘uiautomator’.


  • Перейдите в папку ruby-gem в репозитории calabash-android и соберите Ruby Gem с помощью команды bundle exec rake build.


  • Включите этот Gem в свой проект.


  • Измените start_test_server_in_background на start_test_server_in_background(with_uiautomator: true).


  • Команда вытягивания панели уведомлений: perform_action('pull_notification').


  • Чтобы «коснуться» нотификации с известным фрагментом текста, используйте perform_action('uiautomator_touch_partial_text', ‘my partial text')

Готовый к использованию Ruby Gem:


Если не хотите всё это делать, можете скачать готовый gem и просто следовать трём последним пунктам.


Заключение


Мне потребовалось приложить некоторые усилия, чтобы углубиться в код Calabash-Android-Server, понять, как он работает, и исследовать возможность решения проблемы. С первой попытки это сделать не удалось, но в процессе работы я узнал некоторые секреты Instrumentation. Когда-нибудь я ими поделюсь с вами.


Хотя этот пример посвящён автоматизации push-уведомлений с помощью Calabash, тот же подход можно применить к любой задаче, с которой вы столкнётесь в автоматизационных фреймворках на базе Calabash:


  • тестирование виджетов вашего приложения для домашнего экрана;


  • обработка намерений (Intent) с помощью диалоговых блоков Complete action using в Android-приложениях;


  • тестирование взаимодействия со сторонними приложениями, запущенными из вашего приложения.

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

Поделиться с друзьями
-->

Комментарии (2)


  1. Leshrac
    03.02.2017 15:37

    Как вы с calabash решаете проблему одновременного запуска тестов на нескольких девайсах (Selenium Grid для appium)?


    1. bayandin
      03.02.2017 16:04
      +2

      Сейчас мы используем badoo/parallel_cucumber для параллельного запуска cucumber-тестов (не только с calabash). Можете взглянуть на rajdeepv/parallel_calabash им мы пользовались ранее, а идеи по параллелизации calabash-тестов у этих инструментов одинаковые.