Версия для разработчиков

Совершенно новая мобильная среда

Вероятно, как и вы, я пришел к React Native из другого опыта JavaScript, а не как нативный мобильный разработчик. Это совершенно новая среда со своими уловками и хитростями.

Одна из важных новых областей, которые вам предстоит изучить, - это тестирование. Когда в модульных тестах более или менее ясно, как мы выполняем сквозные тесты пользовательского интерфейса? Есть iOS, есть Android. Рынок с множеством устройств на выбор.

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

Вот два фреймворка, которые я решил использовать, чтобы облегчить себе жизнь как разработчика React Native.

Аппиум

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

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

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

/* selenium webdriver client for node
*/
import wd from 'wd'
/* default timeout
*/
jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000
/* localhost because we run Appium server from our machine + port
*/
const URL = 'localhost'
const PORT = 4723
/* creates webdriver object
*/
const driver = wd.promiseChainRemote(URL, PORT)
/* Server capabilities.
* This is how you tell Appium Server,
* how to run the test, in other words config.
* You probably will want to move this out of here.
*/
const capabilities = {
  platformName: 'iOS', // or Android
  platformVersion: '12.1', // version of the OS
  deviceName: 'iPhone 8', // or Android Emulator or specific device
  automationName: 'XCUITest', // platform specific framework (UIAutomator2 for Android)
  app: '/path/to/.app' // path to app (in case of Android it's .apk)
}
beforeAll(async () => {
  try { // before running our test
    await driver.init(capabilities) // initialise webdriver
    await driver.sleep(4000) // yes, we need to wait for launch screen finish his work before running test, hint of flaky stuff!
  } catch(err) {
    console.log(err) // just in case something goes wrong
  }
})
afterAll(async () => {
  try {
    await driver.quit() // end testing session after test
  } catch(err) {
    console.error(err)
  }
});
/* Jest, now do whatever you want!
* in this case we check if elements with testIDs 
* 'topLabel' and 'subLabel' contain the text we want
* Check Appium documentation
*/
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("Home Screen")
  })
})

Фактическая часть теста - это последние несколько строк Jest, которые проверяют, есть ли на экране текст «ОК» и «Главный экран». Как видите, это похоже на типичный Jest-тест, поэтому нет никаких проблем с его написанием. Страница документации Appium дает вам обзор возможностей и примеры.

Не нравится строка `await driver.sleep (4000)`. Нам это нужно, потому что тесты не знают, что, черт возьми, на самом деле происходит в приложении. Черный ящик. Представьте, что вы напишете код узла с HTTP-вызовом и установите тайм-аут перед ним вместо использования обещания или обратного вызова. Шаткость.

В этой базовой настройке мы говорим Appium (webdriver) подождать 4 секунды перед запуском теста, так как нам нужно запустить приложение и пройти мимо «LaunchScreen», но по мере того, как приложение становится более сложным, вам нужно будет использовать его чаще - http вызовы или анимации, само реагирование-native - мост между JavaScript и собственным кодом вызовет задержки.

Существуют альтернативы, такие как неявное ожидание, но это не меняет модель черного ящика.

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

  • 7+ лет в индустрии.
  • Возможности API, палец вверх.
  • Легко найти помощь и поддержку в Интернете (также не нравится, см. Ниже)
  • Для написания тестов поддерживаются различные языки, включая JavaScript.
  • Обычная для JS-разработчика среда для написания тестов с использованием Jest.
  • Используется для сквозных тестов в MS AppCenter, BrowserStack и AWS Device Farm.
  • Тесты на реальных устройствах.

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

  • Поиск помощи в Интернете дает результаты на всех языках, в основном на Java.
  • Тестирование черного ящика (тесты не знают о внутреннем процессе)
  • Не синхронизируется с приложением. Нестабильный, даже более нестабильный на реакции родного.
  • Свойство testID игнорируется в случае Android.

Детокс

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

Так же, как и в Appium, мы сначала устанавливаем конфигурацию.

/* Our Device config is in package file, see below
*/
const detox = require("detox");
const config = require("./package.json").detox;
/* Jest adapter
*/
const adapter = require("detox/runners/jest/adapter");
/* Set the default timeout
 * and use Jest adapter
 */
jest.setTimeout(120000);
jasmine.getEnv().addReporter(adapter);
beforeAll(async () => {
  /* Initialise and start the server
  */
  await detox.init(config);
});
/* beforeEach and afterEach detox test
 * we run beforeEach of the Jest and
 * do cleanup
 */
beforeEach(async function() {
  await adapter.beforeEach();
});
afterAll(async () => {
  await adapter.afterAll();
  await detox.cleanup();
});

И дополнительная конфигурация в файле пакета.

"detox": {
  "configurations": {
    "ios.detox": { // configuration for iOS (run by 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 or project file. In this case we’re building debug package rather than production (release).
      "type": "ios.simulator",
      "name": "iPhone 8"
    },
    "android.detox": { // configuration for Android (run by detox test -c android.detox)
      "binaryPath": "path/to/.apk",
      "build": "cd android && ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug && cd ..", // In this case we’re building debug package rather than production.
      "type": "android.emulator",
      "name": "Pixel_2_API_28" // name of the simulator. “adb devices” command will list available attached devices
    }
  },
  "test-runner": "jest",
  "runner-config": {
    "setupTestFrameworkScriptFile" : "./detox.init.js", // our configuration above
    "testEnvironment": "node",
    "testRegex": "(.*|\\.(ui))\\.(ts|tsx)$" // test regex for UI tests
  }
  "specs": "./__tests__/" // location of UI tests
}

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

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

  • Сделано Wix для React Native.
  • Сосредоточен на JavaScript.
  • Тестирование серого ящика (есть связь между тестами и внутренними процессами).
  • Работает синхронно с приложением. Не так уж и плохо.

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

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

Слоистый, хлопьевидный, шелушащийся

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

Скорость

Appium будет работать медленнее из-за ручных команд «сна», Detox в этом случае выигрывает, поскольку он автоматически продолжает действие, как только оно будет завершено. В целом, пока не буду делать никаких выводов, пока не проведу большое количество тестов. В небольших 30-секундных тестах и ​​базовой настройке для этой статьи Детокс работал на несколько секунд быстрее. Что касается iOS и Android, я попробовал несколько тестов на обеих платформах на обеих платформах, для выполнения тестов потребовалось + - одинаковое количество времени. Только будьте готовы, что на это уходит гораздо больше времени, чем на обычные модульные тесты.

Что выбрать

Я все еще изучаю обе эти платформы, и потребуется время, чтобы полностью понять обе, но пока как разработчик JavaScript я выбираю Detox.

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

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

Полезные ссылки

Сайт Appium. Вы найдете то, что вам нужно, в верхнем меню.
http://appium.io

Документы Detox.
https://github.com/wix/Detox/tree/master/docs

Detox: Gray Box End to End Testing Framework для мобильных приложений от Ротема Мизрахи-Мейдана.
https://hackernoon.com/detox-gray-box-end-to-end-testing-framework-for-mobile -apps-196ccd9564ce

Презентация Detox от разработчика Wix Ротема Мизрахи-Мейдана.
https://www.youtube.com/watch?v=GgFFeI70PWw

Детокс: начало работы
https://github.com/wix/Detox/blob/master/docs/Introduction.GettingStarted.md

Если вы не знали, в React Native есть свойство testID.
https://facebook.github.io/react-native/docs/view#testid