Detox и Appium: автоматизированный тест интерфейса в React Native
Незнакомая мобильная среда
Я, возможно, также как и вы, пришел к 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 и сам тест.
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