Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Где и как прогонять UI тесты

Alexey Bykov
December 04, 2021

Где и как прогонять UI тесты

UI-тестирование никогда не было простым. Конечно, с фреймворками Kaspresso и Kakao жизнь с каждым годом становится проще, но прогон UI-тестов всё ещё вызывает много вопросов. Например, какой тест-раннер использовать, как быть с сетью, использовать эмулятор или реальное устройство, как чистить стейт и почему. Непонятно и то, как сделать тесты стабильными и показывать хороший репорт. Об этом и поговорим. Глубоко погрузимся в тест-раннеры и эмуляторы, узнаем, почему ADB — не самая лучшая опция для коммуникации с устройством во время прогона, а также постараемся найти наиболее прагматичный подход к UI-тестам для вашей команды.

Alexey Bykov

December 04, 2021
Tweet

More Decks by Alexey Bykov

Other Decks in Programming

Transcript

  1. 2 Алексей Быков Как сделать маркированный или нумерованный список @NoNewsss

    Android-разработчик @Revolut 5 лет в Android-е ПК: AppsConf, Podlodka Crew Огранизатор: AndroidAcademy
  2. Вопрос 8 «BoJack Horseman» © Netflix, 2014 – 2020 А

    можно ли на нём ездить?
  3. 17 Каждый баг в продукте: Как сделать маркированный или нумерованный

    список Fix, PR, Review, Merge Test it Загрузить в GooglePlay/AppGallery Ждать ревью… Ждать раскатку Ждать, пока пользователь обновится
  4. 24 Writing Espresso UiAutomator Google provided Community KAutomator Kakao Kaspresso

    Running Community Spoon Marathon AvitoRunner Composer Fork Flank AndroidJUnitRunner Orchestrator Google provided
  5. 25 Writing Espresso UiAutomator Google provided Community KAutomator Kakao Kaspresso

    Running Community Spoon Marathon AvitoRunner Composer Fork Flank AndroidJUnitRunner Orchestrator Google provided Whereto run Emulator Real device Docker container Device Device condition Real network Mock network
  6. 26 Writing Espresso UiAutomator Google provided Community KAutomator Kakao Kaspresso

    Running Community Spoon Marathon AvitoRunner Composer Fork Flank AndroidJUnitRunner Orchestrator Google provided Whereto run Emulator Real device Docker container Device Device condition Real network Mock network Infrastructure Own Server Firebase GCloud Amazon Kubernetes Cloud
  7. 27 Writing Espresso UiAutomator Google provided Community KAutomator Kakao Kaspresso

    Running Community Spoon Marathon AvitoRunner Composer Fork Flank AndroidJUnitRunner Orchestrator Google provided Whereto run Emulator Real device Docker container Device Device condition Real network Mock network Infrastructure Own Server Firebase GCloud Amazon Kubernetes Cloud Processes CI/CD Release pipeline Validation on PR When to write?
  8. 28 Writing Espresso UiAutomator Google provided Community KAutomator Kakao Kaspresso

    Running Community Spoon Marathon AvitoRunner Composer Fork Flank AndroidJUnitRunner Orchestrator Google provided Whereto run Emulator Real device Docker container Device Device condition Real network Mock network Infrastructure Own Server Firebase GCloud Amazon Kubernetes Cloud Processes CI/CD Release pipeline Validation on PR When to write? Analytics Test report Allure Influx db Grafana Found bugs dynamics
  9. 29 Writing Espresso UiAutomator Google provided Community KAutomator Kakao Kaspresso

    Running Community Spoon Marathon AvitoRunner Composer Fork Flank AndroidJUnitRunner Orchestrator Google provided Whereto run Emulator Real device Docker container Device Device condition Real network Mock network Infrastructure Own Server Firebase GCloud Amazon Kubernetes Cloud Processes CI/CD Release pipeline Validation on PR When to write? Analytics Test report Allure Influx db Grafana Found bugs dynamics
  10. 30 Writing Espresso UiAutomator Google provided Community KAutomator Kakao Kaspresso

    Running Community Spoon Marathon AvitoRunner Composer Fork Flank AndroidJUnitRunner Orchestrator Google provided Whereto run Emulator Real device Docker container Device Device condition Real network Mock network Infrastructure Own Server Firebase GCloud Amazon Kubernetes Cloud Processes CI/CD Release pipeline Validation on PR When to write? Analytics Test report Allure Influx db Grafana Found bugs dynamics Должно работать идеально
  11. 31 Writing Espresso UiAutomator Google provided Community KAutomator Kakao Kaspresso

    Running Community Spoon Marathon AvitoRunner Composer Fork Flank AndroidJUnitRunner Orchestrator Google provided Whereto run Emulator Real device Docker container Device Device condition Real network Mock network Infrastructure Own Server Firebase GCloud Amazon Kubernetes Cloud Processes CI/CD Release pipeline Validation on PR When to write? Analytics Test report Allure Influx db Grafana Found bugs dynamics
  12. 32 Writing Espresso UiAutomator Google provided Community KAutomator Kakao Kaspresso

    Running Community Spoon Marathon AvitoRunner Composer Fork Flank AndroidJUnitRunner Orchestrator Google provided Whereto run Emulator Real device Docker container Device Device condition Real network Mock network Infrastructure Own Server Firebase GCloud Amazon Kubernetes Cloud Processes CI/CD Release pipeline Validation on PR When to write? Analytics Test report Allure Influx db Grafana Found bugs dynamics
  13. 33 Writing Espresso UiAutomator Google provided Community KAutomator Kakao Kaspresso

    Running Community Spoon Marathon AvitoRunner Composer Fork Flank AndroidJUnitRunner Orchestrator Google provided Whereto run Emulator Real device Docker container Device Device condition Real network Mock network Infrastructure Own Server Firebase GCloud Amazon Kubernetes Cloud Processes CI/CD Release pipeline Validation on PR When to write? Analytics Test report Allure Influx db Grafana Found bugs dynamics
  14. Запуск тестов 44 adb shell am instrument -w -m -e

    debug false -e class 'com.alexbykov.myapplication.ExampleInstrumentedTest#myTest' com.alexbykov.myapplication.test/ androidx.test.runner.AndroidJUnitRunner
  15. Запуск тестов 45 adb shell am instrument -w -m -e

    debug false -e class 'com.alexbykov.myapplication.ExampleInstrumentedTest#myTest' com.alexbykov.myapplication.test/ androidx.test.runner.AndroidJUnitRunner
  16. Полная картина 48 // build ./gradlew assembleDebug ./gradlew assembleDebugAndroidTest //

    install adb install debug.apk adb install instrumented.apk // run adb shell am instrument -w -m -e debug false -e package 'com.alexbykov.myapplication' com.alexbykov.myapplication.test/ androidx.test.runner.AndroidJUnitRunner
  17. 63 А как же internal storage? All db saved: /data/data/packagename/databases/

    @get:Rule val clearDatabasesRule = ClearDatabasesRule() @get:Rule val clearFilesRule = ClearFilesRule() @get:Rule val clearPreferencesRule = ClearPreferencesRule()
  18. 64 А как же internal storage? All db saved: /data/data/packagename/databases/

    @get:Rule val clearDatabasesRule = ClearDatabasesRule() @get:Rule val clearFilesRule = ClearFilesRule() @get:Rule val clearPreferencesRule = ClearPreferencesRule() github.com/AdevintaSpain/Barista
  19. Это не решит все проблемы 67 У вас может быть

    Runtime cache Процесс может быть убит ¯\_(ツ)_/¯
  20. 71 Первая мысль adb shell am instrument -w -m -e

    debug false -e class ‘….ExampleInstrumentedTest#test1,….ExampleInstrumentedTest#test2’ com.alexbykov.myapplication.test/androidx.test.runner.AndroidJUnitRunner
  21. 74 Запускаем второй тест adb shell am instrument …. ExampleInstrumentedTest#test2’

    adb shell pm clear … adb shell am instrument …. ExampleInstrumentedTest#test2
  22. 75 Опять чистим adb shell am instrument …. ExampleInstrumentedTest#test2’ adb

    shell pm clear … adb shell am instrument …. ExampleInstrumentedTest#test2 adb shell pm clear …
  23. 112 Что у нас есть Marathon Avito Runner Flank, Fladle

    Fork Spoon Composer Deprecated / Not maintained
  24. Test1: 50% Flaky //0.5 — вероятность прохождения Мы хотим: 80%

    //0.8 — вероятность прохождения Пример 123
  25. Test1: 50% Flaky //0.5 — вероятность прохождения Мы хотим: 80%

    //0.8 — вероятность прохождения Параллельные ретраи: 3 // зависит от инфраструктуры Пример 124
  26. Test1: 50% Flaky //0,5 — вероятность прохождения Мы хотим: 80%

    //0,8 — вероятность прохождения Параллельные ретраи: 3 // зависит от инфраструктуры 0,53 = 0,125 // вероятность, что все 3 сфейлятся Пример 125
  27. Test1: 50% Flaky Мы хотим: 80% Параллельные ретраи: 3 0,53

    = 0,125 // вероятность, что все 3 сфейлятся 1 − 0,125 = 0,875 > 0,8 // +30% вероятность прохождения Пример 126
  28. 130

  29. Но можем сделать это одной строчкой 133 allure generate report

    marathon_output/allure-results -o marathon_output/allure-report --clean
  30. 140

  31. Adb vs Adam 143 ADB: 300 tests T: 32 min

    I/O: 22% CPU: 48% Adam: 300 tests T: 26 min I/O: 19% CPU: 47 %
  32. 144 Marathon Retries Flakiness strategies Хороший тест-репорт, поддержка Allur Изолированное

    окружение Полностью свой adb клиент Валидация флаки-тестов shardingStrategy: type: "count" count: 100
  33. 145 Marathon Retries Flakiness strategies Хороший тест-репорт, поддержка Allur Изолированное

    окружение Полностью свой adb клиент Валидация флаки-тестов Кросс-платформенный
  34. 146 Marathon Retries Flakiness strategies Хороший тест-репорт, поддержка Allur Изолированное

    окружение Полностью свой adb клиент Валидация флаки-тестов Кросс-платформенный marathonlabs.github.io/marathon/
  35. Масштабирование 151 Marathon «Ну я ж сказал, всё что тебе

    надо — подсоединить к adb, остальное я сам».
  36. Масштабирование 157 Avito-runner Adam Только гредл плагин Нет поддержки iOS

    Не очень готов к open-source Marathon Автоматическое масштабирование
  37. 164 Вам нужно решить самим Marathon // Легко интегрировать в

    любую команду Avito Runner // Прагматичный выбор, если нужно гонять тысячи тестов со скейлингом Flank, Fladle // Если компания готова платить за него
  38. Реальное устройство 167 Оно реально :) Не требует CI ресурсов

    Требует спец. условий хранения Часто ломается
  39. Работает быстрее? 169 До: После: Реальное устройство 50 секунд на

    успешный тест Эмулятор 30 секунд на успешный тест
  40. Конфигурация 173 PlayStore.enabled=false abi.type=x86_64 avd.ini.encoding=UTF-8 hw.cpu.arch=x86_64 hw.cpu.ncore=2 hw.ramSize=2048 hw.lcd.density=120 hw.lcd.width=320

    hw.lcd.height=480 hw.audioInput=no hw.audioOutput=no hw.accelerometer=no hw.gyroscope=no hw.dPad=no hw.mainKeys=yes hw.keyboard=no hw.sensors.proximity=no hw.sensors.magnetic_field=no hw.sensors.orientation=no hw.sensors.temperature=no hw.sensors.light=no hw.sensors.pressure=no hw.sensors.humidity=no hw.sensors.magnetic_field_uncalibrated=no hw.sensors.gyroscope_uncalibrated=no image.sysdir.1=system-images/android-29/google_apis/x86_64/ tag.display=Google APIs tag.id=google_apis skin.dynamic=yes skin.name=320x480 disk.dataPartition.size=8G
  41. Конфигурация 174 PlayStore.enabled=false abi.type=x86_64 avd.ini.encoding=UTF-8 hw.cpu.arch=x86_64 hw.cpu.ncore=2 hw.ramSize=2048 hw.lcd.density=120 hw.lcd.width=320

    hw.lcd.height=480 hw.audioInput=no hw.audioOutput=no hw.accelerometer=no hw.gyroscope=no hw.dPad=no hw.mainKeys=yes hw.keyboard=no hw.sensors.proximity=no hw.sensors.magnetic_field=no hw.sensors.orientation=no hw.sensors.temperature=no hw.sensors.light=no hw.sensors.pressure=no hw.sensors.humidity=no hw.sensors.magnetic_field_uncalibrated=no hw.sensors.gyroscope_uncalibrated=no image.sysdir.1=system-images/android-29/google_apis/x86_64/ tag.display=Google APIs tag.id=google_apis skin.dynamic=yes skin.name=320x480 disk.dataPartition.size=8G
  42. Конфигурация 175 PlayStore.enabled=false abi.type=x86_64 avd.ini.encoding=UTF-8 hw.cpu.arch=x86_64 hw.cpu.ncore=2 hw.ramSize=2048 hw.lcd.density=120 hw.lcd.width=320

    hw.lcd.height=480 hw.audioInput=no hw.audioOutput=no hw.accelerometer=no hw.gyroscope=no hw.dPad=no hw.mainKeys=yes hw.keyboard=no hw.sensors.proximity=no hw.sensors.magnetic_field=no hw.sensors.orientation=no hw.sensors.temperature=no hw.sensors.light=no hw.sensors.pressure=no hw.sensors.humidity=no hw.sensors.magnetic_field_uncalibrated=no hw.sensors.gyroscope_uncalibrated=no image.sysdir.1=system-images/android-29/google_apis/x86_64/ tag.display=Google APIs tag.id=google_apis skin.dynamic=yes skin.name=320x480 disk.dataPartition.size=8G
  43. Avito emulator 181 Запуск (headless) docker run -d -p 5555:5555

    -p 5554:5554 -p 8554:8554 
 --privileged avitotech/android-emulator-29:915c1f20be
  44. Avito emulator 182 Запуск (headless) docker run -d -p 5555:5555

    -p 5554:5554 -p 8554:8554 
 --privileged avitotech/android-emulator-29:915c1f20be Connect to adb adb connect localhost:5555
  45. Avito emulator 183 Запуск (headless) docker run -d -p 5555:5555

    -p 5554:5554 -p 8554:8554 
 --privileged avitotech/android-emulator-29:915c1f20be Connect to adb adb connect localhost:5555 Kill (после прогона) docker kill $(docker ps -q)
 docker rm $(docker ps -a -q)
  46. Выделенный тест-сервер 189 Немного стабильнее Сервер упал Интернет Не то

    же самое что и реальный сервер А кто поддерживать его будет?
  47. 193 Не заработало у нас нормально MockWebServer Custom interceptor DI:

    Dagger2/Hilt/Toothpick/Koin/etc Service locator Отдельный src
  48. Yaml 201 - recorded: 2021-10-13T14:30:23.507Z request: method: GET uri: https://api.server.com/inbox

    headers: response: status: 200 headers: date: Wed, 13 Oct 2021 14:30:26 GMT request-id: 9JAJH8Y9JMRU server: MyServer body: '{"messages":[]}'
  49. OkReplay 209 Yaml Android-friendly Обычный interceptor Поддержка скольких угодно хостов

    Индексация Время запроса Ручное мокирование
  50. 215 До того как вы начали Не пробуйте это «по

    фану» Должна быть чёткая цель
  51. Спасибо 217 Alexey Tvorogov Kaspresso adb server Eugene Matsyuk Kaspresso

    creator Dmitriy Voronin Avito runner creator Dmitry Movchan Kaspresso adb server & a lot of researches Anton Malinskiy Marathon creator
  52. 218 Ресурсы 1. https://github.com/KasperskyLab/Kaspresso 2. https:/ /proandroiddev.com/autotests-on-android-the-entire-picture-51c07995fc2f (Р. 3. https:/

    /github.com/MarathonLabs/marathon 4. https:/ /github.com/avito-tech/avito-android 5. https:/ /github.com/Flank/flank 6. https:/ /github.com/airbnb/okreplay 7. https:/ /github.com/wiremock/wiremock