Detox и Appium: автоматизированный тест интерфейса в React Native

xxgvpps9vbr5q2jkamchgmd-quk.jpeg

Незнакомая мобильная среда


Я, возможно, также как и вы, пришел к React Native как разработчик JavaScript нежели как разработчик нативных мобильных приложений. Абсолютно новый мир со своими нюансами и хитростями.

Одной из самых важных тем для изучения станет тестирование. Когда все более или менее понятно с модульными тестами (unit), что делать с тестами интерфейса и сквозными тестами (end-to-end)? iOS. Android. На рынке смесь разных типов устройств.

Несмотря на то, что сама технология сравнительно новая, это все еще мобильная среда и многому приходится заимствовать и учиться у нативной стороны.

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

Appium


Использующая за кулисами Selenium WebDriver, Appium это мощный фреймворк с огромным сообществом разработчиков нативных мобильных приложений. Вышедший еще до React.js, это лидер и равных ему нет.

Начать работу с Appium довольно легко. С помощью npm устанавливаем пакеты «appium» и «appium-doctor», можем глобально, можем как часть проекта. Команда «appium-doctor» расскажет нам, что еще нужно установить и настроить прежде чем приступать к работе, и, если возможно, поможет исправить недочеты. Когда все решено, пакеты установлены и конфигурация Jest на месте, можем запускать сервер Appium и тесты.

Не буду углубляться в подробности настройки, но вот как выглядит простой тест с конфигурацией (добавлены комментарии):

/* клиент selenium webdriver для node
*/
import wd from 'wd'

/* 60 секунд таймаут, после которых тест остановится, если застрянет
 */
jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000

/* адрес сервера Appium. Запускаем с нашего компьютера, поэтому localhost
*/
const URL = 'localhost'
const PORT = 4723

/* создаем объект webdriver
*/
const driver = wd.promiseChainRemote(URL, PORT)

/* Вожможности сервера.
* инструкция для сервера Appium,
* как запускать тесты, другими словами настройки.
*/
const capabilities = {
 platformName: 'iOS', // или Android
 platformVersion: '12.1', // версия ОС
 deviceName: 'iPhone 8', // или "Android Emulator” или точное название устройства
 automationName: 'XCUITest', // фреймворк платформы (UIAutomator2 для Android)
 app: '/path/to/.app' // расположение файла .app (для Android это .apk)
}

beforeAll(async () => {
 try { // до того, как запустить тест
   await driver.init(capabilities) // запускаем драйвер
   await driver.sleep(4000) // да уж, вручную ставим таймер и ждем загрузку приложения, вот она хрупкость!
 } catch(err) {
   console.log(err) // если что, мы хотим знать, что не так
 }
})

afterAll(async () => {
 try {
   await driver.quit() // конец сессии
 } catch(err) {
   console.error(err)
 }
});

/* Jest, делаем что хотим, что позволяет Appium!
* в данном примере мы проверяем, соответствует ли текст
* 'topLabel' и 'subLabel' заданному
* Рекомендую ознакомиться с документацией на сайте Appium
*/
describe("Home Screen landing", () => {
 test("render search screen", async () => {
    let topLabel = await driver.elementById('topLabel')
    let subLabel = await driver.elementById('subLabel')
    expect(await topLabel.text()).toBe("OK")
    expect(await subLabel.text()).toBe("главный экран")
 })
})


Сам тест, это последние несколько строк, которые проверяют, если на экране текст «OK» и «главный экран». Как видите, в тесте ничего особенного, тот же самый Jest. Документация на сайте Appium описывает все возможности фреймворка включая также примеры на JavaScript.

Неприязнь только к строке await driver.sleep(4000). К сожалению, тесты понятия не имеют, что происходит в приложении. Так называемый «черный ящик» или Blackbox. Представьте, если бы вы писали код на Node, и перед запросом http, вы бы ставили таймер вместо использования promise или callback. Вот она, хрупкость UI тестов.

В этом простом тесте мы ждем 4 секунды для запуска приложения. Со временем и с увеличением количества тестов, мы будем устанавливать таймеры чаще — запросы http, анимация, сам React Native — мост между нативным кодом и JavaScript только усложняет ситуацию.

Что нравится в Appium

  • 7+ лет в индустрии.
  • Широкие возможности API.
  • Легко найти помощь (это также минус, список ниже)
  • Поддержка разных языком, в том числе JavaScript.
  • Знакомая для разработчика JavaScript среда Jest.
  • Используется для сквозных тестов в MS AppCenter, BrowserStack и AWS DeviceFarm.
  • Возможность теста на настоящих устройствах.


Что не нравится в Appium

  • Поиск в сети выдает результаты для разных языков программирования, большинство из них это Java.
  • Тестирование «чёрного ящика» (тесты не знают о процессах внутри приложения).
  • Нет синхронности с приложением, хрупкость, еще больше проблем создает React Native.
  • testID по какой-то причине не работает на Android.

Заметьте три таба: логи сервера Appium, пакет metro bundler и сам тест.
apn-pmr1nkmzno2m728ljq39tb8.png

Detox


Detox от компании Wix работает схоже с Appium. Главное отличие, это тестирование по стратегии «серого ящика». Одной из задач разработчиков Detox было решение проблем с хрупкостью — задача в приложении не будет начата, пока не закончилась предыдущая и пока приложение не будет свободно. Это стало возможно благодаря другому фреймворку созданному под названием EarlGrey.

Так же как и с Appium, устанавливаем настройки.

/* Дополнительная настройка в файле package.json, ниже пример
*/
const detox = require("detox");
const config = require("./package.json").detox;

/* адаптер Jest
*/
const adapter = require("detox/runners/jest/adapter");

/* Таймаут,
 * использование адаптера Jest
 */
jest.setTimeout(120000);
jasmine.getEnv().addReporter(adapter);

beforeAll(async () => {
 /* Запускаем сервер
 */
 await detox.init(config);
});

 /* beforeEach и afterEach для тестов Detox, 
  * используем от Jest
  * чистим после тестов
  */
beforeEach(async function() {
 await adapter.beforeEach();
});

afterAll(async () => {
 await adapter.afterAll();
 await detox.cleanup();
});


И настройка в package.json:

"detox": {
   "configurations": {
     "ios.detox": { // настройки для iOS (запускается командой detox test -c ios.detox)
       "binaryPath": "path/to/.app",
       "build": "xcodebuild -workspace ios/app.xcworkspace -scheme scheme -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build", // файл workspace или project. В данном случае создаем пакет debug вместо production (release).
       "type": "ios.simulator",
       "name": "iPhone 8" // название симулятора
     },
     "android.detox": { // настройки для Android (запускается командой detox test -c android.detox)
       "binaryPath": "path/to/.apk",
       "build": "cd android && ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug && cd ..", // В данном случае создаем пакет debug вместо production (release).
       "type": "android.emulator",
       "name": "Pixel_2_API_28" // название симулятора. "adb devices” покажет список доступных устройств Android
     }
   },
   "test-runner": "jest",
   "runner-config": {
    "setupTestFrameworkScriptFile" : "./detox.init.js", // пример выше   
    "testEnvironment": "node",
    "testRegex": "(.*|\\.(ui))\\.(ts|tsx)$" // регулярное выражение, где искать тесты интерфейса
 }
   "specs": "./__tests__/" // расположение тестов интерфейса
 }



Тесты писать также легко, как и для Appium, но с использованием возможностей и ограничений Detox.

Что мне нравится в Detox

  • Создан Wix для React Native.
  • Сфокусирован на JavaScript.
  • Тест по стратегии «серого ящика».
  • Работает синхронно с приложением.


Что не нравится в Detox

  • Возможности не такие широкие как у Appium.
  • Маленькое сообщество.

Хрупкость


Несмотря на то, что Detox использует принцип «серого ящика», хрупкость все еще присутствует. Тест с вводом текста и свайпом не срабатывал как надо в 1 случае из 10. Нельзя быть уверенным на 100% в тестах интерфейса.

Скорость


Appium «тормозит» таймеры ».sleep» установленные в ручную, Detox в этом случае выигрывает, так как все синхронно. В целом я бы не делал еще каких-либо выводов со своей стороны, так как не писал большого кол-ва одинаковых тестов на обеих платформах. В 30-секундных тестах и простом тесте созданном для этой статьи, Detox справился на секунды быстрее. Если смотреть на две разные платформы, iOS и Android, тесты заняли ± одно и то же время. Главное, следует помнить, что тесты интерфейса занимают значительно больше времени модульных тестов.

Что выбрать


Я по прежнему изучаю оба фреймворка и понадобится какое-то время, чтобы понять все их преимущества, но на данный момент, как разработчик JavaScript, я выбираю Detox.

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

Тесты интерфейса в команде разработчиков — для разработчиков, пробуйте Detox. Более сложные сквозные тесты — возможно, лучше присмотреться к Appium с его богатыми возможностями API и поддержкой на платформах BrowserStack, MS AppCenter и AWS DeviceFarm.

Ссылки


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

Appium
http://appium.io

Detox
https://github.com/wix/Detox

© Habrahabr.ru