CodeFest 2019. Артём Разинов (Avito) — E2E UI-тесты: много, зелено и на Pull Request

16b6c87229eaf58768d25ed7b2bbbf52?s=47 CodeFest
April 06, 2019

CodeFest 2019. Артём Разинов (Avito) — E2E UI-тесты: много, зелено и на Pull Request

Расскажу, как начать писать функциональные UI-тесты в iOS, сократить время регрессионного тестирования большого приложения с дней до часов, получить стабильный и зеленый на 95% test suite, запуск тестов на каждый Pull Request, как прийти в дальнейшем к 100% зеленым UI-тестам. Расскажу про техники, приемы, алгоритмы — они универсальны и будут полезны каждому. Доклад посвящен iOS, тем не менее, большинство практик применимы к Android и Web.

16b6c87229eaf58768d25ed7b2bbbf52?s=128

CodeFest

April 06, 2019
Tweet

Transcript

  1. iOS E2E UI-тесты много, зелено и на Pull Request !1

    Артём Разинов arazinov@avito.ru
  2. Вводное Как плохо было Как хорошо стало О тестах Хардкорное

    Как обойтись без автотестов Перезапуски Trusted тесты Импакт анализ Сравнение с таргет веткой Заключение Заключение !2
  3. Как плохо было ветка разработки ветка фичи !3 ветка релиза

    ф и ч и
  4. Как плохо было • 10 дней на первую итерацию "регресса"

    • Много ручного тестирования • О проблемах узнавали только на регрессе • Большое время от бранчката до раскатки на 100% • Релиз (хорошо если) раз в месяц !4
  5. Как хорошо стало !5

  6. Количество автотестов !6

  7. Сроки выполнения первой итерации ? !7 ⬤ основные релизы ⬤

    автотесты ⬤ объем обязательных тестов ⬤ минорные релизы
  8. ? Время выполнения первой итерации !8 ⬤ потрачено времени на

    ручную работу ⬤ автотесты ⬤ объем обязательных тестов
  9. Время между релизами ⬤ 1 итерация регресса ⬤ остальное по

    релизу ⬤ остальное !9
  10. О тестах !10

  11. !11

  12. О тестах PR Регресс Всего девайсов 1 3 Всего тестов

    247 2313 Всего запусков 255 3285 Среднее время запуска 37.549с 59.998с Сумма длительностей 2ч 39м 35с (9575с) 54ч 44м 54с (197094с) Реальное время тестов 4м 41с (281с) 1ч 33м 31с (5611с) Реальное время сборки 10м 36с (636с) 1ч 37м 0с (5820с) Параллелизация 34,07 35,13 Накладные расходы 5м 55с (355с) 3м 29с (209с) !12
  13. О тестах PR Регресс Всего девайсов 1 3 Всего тестов

    247 2313 Всего запусков 255 3285 Среднее время запуска 37.549с 59.998с Сумма длительностей 2ч 39м 35с (9575с) 54ч 44м 54с (197094с) Реальное время тестов 4м 41с (281с) 1ч 33м 31с (5611с) Реальное время сборки 10м 36с (636с) 1ч 37м 0с (5820с) Параллелизация 34,07 35,13 Накладные расходы 5м 55с (355с) 3м 29с (209с) !13
  14. Практики !14

  15. Как обойтись без автотестов !15

  16. Масштабировать ресурсы Ручной импакт анализ !16 ф и ч и

  17. Автотесты !17

  18. Зеленость полного суита Сломались тесты Начали активно писать тесты Нагрузка

    на CI Улучшение
 раннера Фиксы
 фрейморка Trusted tests Рестарты Тесты, на которые плевать !18
  19. Виды тестов по красноте Вид Как лечить Полный суит PR

    Стабильные ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ - - Иногда флакующие ✔ ✔ ✔ ✔ ✔ ✘ ✔ ✔ ✔ Перезапуски Перезапуски Очень нестабильные ✘ ✔ ✘ ✘ ✘ ✔ ✘ ✘ ✘ Перезапуски Trusted tests Нестабильная инфра ✔ ✔ ✔ ✘ ✘ ✘ ✔ ✔ ✔ Перезапуски Target Branch Сломанные ✔ ✔ ✔ ✔ ✘ ✘ ✘ ✘ ✘ Pull Request Trusted tests Изначально нерабочие ✘ ✘ ✘ ✘ ✘ Pull Request Импакт анализ Брошенные ✘ ✘ ✘ ✘ ✘ ✘ ✘ ✘ ✘ Уведомления Trusted tests !19
  20. Виды тестов по красноте Вид Как лечить Полный суит PR

    Стабильные ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ - - Иногда флакующие ✔ ✔ ✔ ✔ ✔ ✘ ✔ ✔ ✔ Перезапуски Перезапуски Очень нестабильные ✘ ✔ ✘ ✘ ✘ ✔ ✘ ✘ ✘ Перезапуски Trusted tests Нестабильная инфра ✔ ✔ ✔ ✘ ✘ ✘ ✔ ✔ ✔ Перезапуски Target Branch Сломанные ✔ ✔ ✔ ✔ ✘ ✘ ✘ ✘ ✘ Pull Request Trusted tests Изначально нерабочие ✘ ✘ ✘ ✘ ✘ Pull Request Импакт анализ Брошенные ✘ ✘ ✘ ✘ ✘ ✘ ✘ ✘ ✘ Уведомления Trusted tests !20
  21. Мигание тестов !21

  22. Мигание тестов !22

  23. Перезапуски Запуск 1 Запуск 2 Запуск 3 Результат ✔ ✔

    ✘ ✔ ✔ ✘ ✘ ✔ ✔ ✘ ✘ ✘ ✘ !23
  24. Перезапуски Success Rate 1 2 3 4 5 6 50

    % 50 % 75 % 87,5 % 93,75 % 96,875 % 98,4375 % 80 % 80 % 96 % 99,2 % 99,84 % 99,968 % 99,9936 % 95 % 95 % 99,75 % 99,9875 % 99,9994 % 100 % 100 % 99 % 99 % 99,99 % 99,9999 % 100 % 100 % 100 % !24
  25. Перезапуски Success Rate 1 2 3 4 5 6 50

    % 50 % 75 % 87,5 % 93,75 % 96,875 % 98,4375 % 80 % 80 % 96 % 99,2 % 99,84 % 99,968 % 99,9936 % 95 % 95 % 99,75 % 99,9875 % 99,9994 % 100 % 100 % 99 % 99 % 99,99 % 99,9999 % 100 % 100 % 100 % !25
  26. Перезапуски Success Rate 1 2 3 4 5 6 50

    % 50 % 75 % 87,5 % 93,75 % 96,875 % 98,4375 % 80 % 80 % 96 % 99,2 % 99,84 % 99,968 % 99,9936 % 95 % 95 % 99,75 % 99,9875 % 99,9994 % 100 % 100 % 99 % 99 % 99,99 % 99,9999 % 100 % 100 % 100 % !26
  27. Перезапуски Success Rate 1 2 3 4 5 6 50

    % 50 % 75 % 87,5 % 93,75 % 96,875 % 98,4375 % 80 % 80 % 96 % 99,2 % 99,84 % 99,968 % 99,9936 % 95 % 95 % 99,75 % 99,9875 % 99,9994 % 100 % 100 % 99 % 99 % 99,99 % 99,9999 % 100 % 100 % 100 % !27
  28. Перезапуски Success Rate 1 2 3 4 5 6 50

    % 50 % 75 % 87,5 % 93,75 % 96,875 % 98,4375 % 80 % 80 % 96 % 99,2 % 99,84 % 99,968 % 99,9936 % 95 % 95 % 99,75 % 99,9875 % 99,9994 % 100 % 100 % 99 % 99 % 99,99 % 99,9999 % 100 % 100 % 100 % !28
  29. Когда лежит инфраструктура !29

  30. Когда лежит инфраструктура Test 1 ✘ ✘ ✘ Infra 1

    Test 2 ✔ Infra 2 !30
  31. Когда лежит инфраструктура Test 1 ✘ ✘ ✘ ✔ Infra

    1 Test 2 ✔ Infra 2 Ждем часик-другой !31
  32. Профит Минимум 0,34 % Среднее 2,72 % Максимум 11,92 %

    !32
  33. Профит

  34. Ломающиеся тесты !34

  35. Ломающиеся тесты ✔ !35 ✘ ✔

  36. ✔ ✘ Ломающиеся тесты ✔ !36 ✔

  37. Профит !37

  38. Чеки на пулреквесте !38

  39. !39

  40. Trusted tests !40

  41. Перезапуски (1 тест) Success Rate 1 2 3 4 5

    6 50 % 50 % 75 % 87,5 % 93,75 % 96,875 % 98,4375 % 80 % 80 % 96 % 99,2 % 99,84 % 99,968 % 99,9936 % 95 % 95 % 99,75 % 99,9875 % 99,9994 % 100 % 100 % 99 % 99 % 99,99 % 99,9999 % 100 % 100 % 100 % !41
  42. Перезапуски (1 тест) Success Rate 1 2 3 4 5

    6 50 % 50 % 75 % 87,5 % 93,75 % 96,875 % 98,4375 % 80 % 80 % 96 % 99,2 % 99,84 % 99,968 % 99,9936 % 95 % 95 % 99,75 % 99,9875 % 99,9994 % 100 % 100 % 99 % 99 % 99,99 % 99,9999 % 100 % 100 % 100 % !42
  43. Перезапуски (250 тестов) Success Rate 1 2 3 4 5

    6 50 % 0 % 0 % 0 % 0 % 0,0357 % 1,9505 % 80 % 0 % 0,0037 % 13,4251 % 67,0105 % 92,3105 % 98,4127 % 95 % 0,0003 % 53,4843 % 96,9231 % 99,8439 % 99,9922 % 99,9996 % 99 % 8,1059 % 97,5309 % 99,975 % 99,9998 % 100 % 100 % !43
  44. Перезапуски (500 тестов) Success Rate 1 2 3 4 5

    6 50 % 0 % 0 % 0 % 0 % 0 % 0,038 % 80 % 0 % 0 % 1,8023 % 44,9041 % 85,2122 % 96,8506 % 95 % 0 % 28,6057 % 93,9409 % 99,688 % 99,9844 % 99,9992 % 99 % 0,657 % 95,1227 % 99,95 % 99,9995 % 100 % 100 % !44
  45. Перезапуски (1000 тестов) Success Rate 1 2 3 4 5

    6 50 % 0 % 0 % 0 % 0 % 0 % 0 % 80 % 0 % 0 % 0,0325 % 20,1638 % 72,6112 % 93,8003 % 95 % 0 % 8,1828 % 88,249 % 99,3769 % 99,9688 % 99,9984 % 99 % 0,0043 % 90,4833 % 99,9 % 99,999 % 100 % 100 % !45
  46. Success Rate 1 2 3 4 5 6 50 %

    0 % 0 % 0 % 0 % 0 % 0 % 80 % 0 % 0 % 0,0325 % 20,1638 % 72,6112 % 93,8003 % 95 % 0 % 8,1828 % 88,249 % 99,3769 % 99,9688 % 99,9984 % 99 % 0,0043 % 90,4833 % 99,9 % 99,999 % 100 % 100 % Перезапуски (1000 тестов) !46
  47. Success Rate 1 2 3 4 5 6 50 %

    0 % 0 % 0 % 0 % 0 % 0 % 80 % 0 % 0 % 0,0325 % 20,1638 % 72,6112 % 93,8003 % 95 % 0 % 8,1828 % 88,249 % 99,3769 % 99,9688 % 99,9984 % 99 % 0,0043 % 90,4833 % 99,9 % 99,999 % 100 % 100 % Перезапуски (1000 тестов) !47
  48. Trusted Tests Build 997 Build 998 Build 999 Build 1000

    Trusted? ✘ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✘ ✘ ✘ ✘ ✘✔ ✔ ✔ ✘ ✔ ✘ размер окна: 3 билда минимально билдов: 2 !48
  49. Build 997 Build 998 Build 999 Build 1000 Trusted? ✘

    ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✘ ✘ ✘ ✘ ✘✔ ✔ ✔ ✘ ✔ ✘ Trusted Tests размер окна: 3 билда минимально билдов: 2 !49
  50. Build 997 Build 998 Build 999 Build 1000 Trusted? ✘

    ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✘ ✘ ✘ ✘ ✘✔ ✔ ✔ ✘ ✔ ✘ Trusted Tests размер окна: 3 билда минимально билдов: 2 !50
  51. Build 997 Build 998 Build 999 Build 1000 Trusted? ✘

    ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✘ ✘ ✘ ✘ ✘✔ ✔ ✔ ✘ ✔ ✘ Trusted Tests размер окна: 3 билда минимально билдов: 2 !51
  52. Trusted Tests !52

  53. Trusted Tests !53

  54. Увеличиваем количество данных ночь ночь ночь ночь ночь ночь iPhone

    7 iPhone SE iPhone X iPhone 7 iPhone SE iPhone X Trusted? ✔ ✔ ✔ ✔ ✔ ✔ !54 ночь ночь ночь ночь ночь ночь iPhone 7 iPhone SE iPhone X iPhone 7 iPhone SE iPhone X Trusted? ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✘ ✔ ✔ ✘ ✔ ✘ Используем запуски на всех девайсах:
  55. Улучшаем стабильность ночь ночь ночь ночь ночь ночь iPhone 7

    iPhone SE iPhone X iPhone 7 iPhone SE iPhone X Trusted? ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ !55 ночь ночь ночь день день день iPhone 7 iPhone SE iPhone X iPhone 7 iPhone SE iPhone X Trusted? ✔ ✔ ✔ ✘ ✔ ✘ ✘ ✔ ✔ ✔ ✔ ✘ ✘ ✘ Делаем запуски в течение рабочего дня:
  56. Фейл теста Фейл симулятора Фейл нагрузки Trusted? ✔ ✔ SKIP

    ✔ ✔ SKIP ✔ ✔ Фейл теста Фейл симулятора Фейл нагрузки Trusted? ✔ ✔ ✘ ✘ ✔ ✘ ✔ ✘ Увеличиваем количество трастед тестов !56 Игнорируем "шум":
  57. Импакт анализ !57

  58. git diff | get_tests !58

  59. Если падает инфраструктура !59

  60. Если падает инфраструктура !60 Ветка PR ✘ ✘ ✘ Инфра

  61. Сравнение с таргет веткой Ветка PR ✘ ✘ ✘ Инфра

    Целевая ветка ✘ !61 Из этого следует, что статус теста не зависит от изменений в коде
  62. Сравнение с таргет веткой Source * 5 Target Final ✔

    ✔ ✘ ✔ ✘ ✘ ✘ SKIP ✔ SKIP ✔ ✘ SKIP ✘ !62
  63. Сравнение с таргет веткой Source * 5 Target Final ✔

    ✔ ✘ ✔ ✘ ✘ ✘ SKIP ✔ SKIP ✔ ✘ SKIP ✘ !63
  64. Сравнение с таргет веткой Source * 5 Target Final ✔

    ✔ ✘ ✔ ✘ ✘ ✘ SKIP ✔ SKIP ✔ ✘ SKIP ✘ !64
  65. Сравнение с таргет веткой Source * 5 Target Final ✔

    ✔ ✘ ✔ ✘ ✘ ✘ SKIP ✔ SKIP ✔ ✘ SKIP ✘ !65
  66. Сравнение с таргет веткой Source * 5 Target Final ✔

    ✔ ✘ ✔ ✘ ✘ ✘ SKIP ✔ SKIP ✔ ✘ SKIP ✘ !66
  67. Сравнение с таргет веткой % вылеченных тестов на упавших билдах

    !67
  68. Сравнение с таргет веткой Ветка PR ✘ ✘ ✘ ✘

    ✘ Инфра Целевая ветка ✔ Ветка PR ✘ ✘ ✘ ✔ Инфра Целевая ветка ✔ !68 Как стало:
  69. Сравнение с таргет веткой Source * 3 Target Source *

    2 Final ✔ ✔ ✘ ✔ ✔ ✔ ✘ ✔ ✘ ✘ ✘ ✘ SKIP ✘ SKIP ✔ ✔ ✘ SKIP ✘ ✘ !69
  70. Сравнение с таргет веткой Source * 2 Target Source *

    3 Final ✔ ✔ ✘ ✔ ✔ ✔ ✘ ✔ ✘ ✘ ✘ ✘ SKIP ✘ SKIP ✔ ✔ ✘ SKIP ✘ ✘ !70
  71. Сравнение с таргет веткой % вылеченных тестов на упавших билдах

    !71
  72. Брошенные тесты !72

  73. Оповещения и отчеты !73

  74. Оповещения и отчеты !74

  75. Оповещения и отчеты !75

  76. Оповещения и отчеты !76

  77. Оповещения и отчеты !77

  78. Что еще нужно для зеленых тестов • Качественный код тестов,

    как если бы вы писали продакшен код: идеальный, хороший, чистый код • Фреймворк, толерантный к изменениям в UI • Раннер, толерантный к различным неприятностям • CI, идеальный, хороший, чистый • Стабильная инфраструктура
  79. Заключение !79

  80. Польза • 10 дней на регрессионное тестирование => 1 день

    • Нерегулярные релизы раз в месяц => регулярные раз в 2 недели • Много ручного тестирования => все пишут автотесты • Поломанные фичи не мержатся в общую ветку • Можно после больших рефакторингов за 1.5 часа получить результаты автотестов !80
  81. Цена • 2 человекогода на iOS специфичный CI и инструментарий

    • Уже готовый сервис отчетов, интеграционное API, ручки к интеграционному API, вся инфраструктура для этого • И еще много работы, которую я забыл упомянуть (типа Test Analyzer) • Будьте готовы к тому, что тесты не будут 100% зелеными • Пожары на CI и массовая блокировка пулреквестов обязательно будут !81
  82. !82 На pastebin ссылки на другие доклады по теме и

    опенсорс https://pastebin.com/m0m35Et8
  83. !83 Спасибо за внимание! Skype: artyom.razinov Telegram: artyom_razinov https://pastebin.com/m0m35Et8

  84. Q&A

  85. Инструменты Код тестов Swift (84000 строк) Код CI Bash, Python,

    Swift Фреймворк тестов Mixbox (на основе XCTest/XCUI) Раннер Emcee (на основе fbxtest) CI Teamcity !85
  86. Интеграционное API Описание инструментрария. Swift, CI, Python, Mixbox Про нестабильную

    инфраструктуру. Мы люди простые Не хотим лезть в 250 сервисов. Подсветить то, о чем говорю. Сказать: Видео будет доступно. Презентация будет доступна. !86 let пользователь2 = интеграционноеАпи.пользователь { фильтр in фильтр.пользователь.город = .москва фильтр.объявление.город = .краснодар фильтр.объявление.категория = .вакансии фильтр.объявление.цена = 100000 фильтр.объявление.статус = .активно } мессенджер .сессия(пользователь1) .чат(пользователь2.объявление.первое) .отправитьСообщение("Актуально?") .отправитьПропущенныйВызов()
  87. Параметризация func test_dataSet0() { // ... }
 
 func test_dataSet1()

    { // ... }
 
 func test_dataSet2() { // ... }
 
 func test_dataSet3() { // ... } !87
  88. Параметризация func test_dataSet3() { parametrizedTest( dataSet: PublishParametersDataSetItem( menuSteps: PublishMenuSteps(.job, .cv,

    nil, .adminJob, nil), parameters: PublishParametersDataSetItem.Parameters( title: "Водитель дивана", description: "Закончить первую повесть Достоевскому мешал её герой, не желав price: "5", displayedPrice: "5", city: "Икряное", educationField: "Среднее", workSchedule: "Сменный график", workExperience: "10", gender: "Женский", businessTrip: "Не готов", relocation: "Возможен", national: "Казахстан", age: "99" ) ) ) } !88
  89. Кто пишет Строк кода Людей !89

  90. !90 Page Object Element public var anonymousNumberSwitch: ViewElement { return

    element("переключатель анонимного номера") { element in element.type == .switch && element.isSubviewOf { element in element.id == "anonymousNumber" } } }
  91. !91 Page Object if pageObjects.paparazzoScreen.confirmLibraryButton.isDisplayed() { pageObjects.paparazzoScreen.confirmLibraryButton.tap() } else {

    pageObjects.paparazzoScreen.nextButton.tap() } pageObjects.publishStepScreen.titleField.setText("Клавиатура") pageObjects.publishStepScreen.nextButton.tap() pageObjects.publishStepScreen.categoryCell(title: "Клавиатуры и мыши").tap() pageObjects.publishStepScreen.categoryCell(title: "Продаю своё").tap() pageObjects.publishStepScreen.nextButton.tap()
  92. Оптимизации • Запуск глубоких экранов по диплинкам • Скип начальных

    алертов, если есть • Ускорение анимаций !92
  93. Причины флаки !93

  94. !94

  95. None
  96. !96

  97. !Q|!A