SlideShare a Scribd company logo
Домрачев Михаил
iOS developer Improve Digital
Новосибирск
UI тесты в iOS проекте
Есть ли профит и для чего их вообще внедряют?
А ты
пишешь
UI
тесты ?
Как мы пришли к
этому?
• Проект активно живет и 

развивается 2 года
• Команда разработчиков

увеличилась
• Проект состоит 

не из одного приложения
• Core framework
Finance application
Skeleton screen
Item
- background color
- imageName
Item
- title
- title color
- background color
Core framework
App
30%
Core framework
70%
Core framework AppCore framework Application
• Screen module
• Any services
• Utils
• Design elements
- xib
- cell
- view model
• Override
screen module
• New screen
modules
• Override services
• xib
Design like Lego
• Берем ячейки из Core framework
• Настраиваем их через View-Model’s
• Заполняем таблицу экрана
Помоги
Мише
найти 10
отличий
1 1
2 2
3 3
4 4
Screen from
Core framework
Screen from 

Core framework
Screen from
Core framework
Override screen from
Core framework
Нельзя просто так взять
и написать код идеально
Источники проблем
• Новые разработчики
• Общие ресурсы
• Дизайнер забыл про
единый стиль
приложений
UI testing
Инструменты
iOS UI testing
UI testing
Стоимость
UI testing
Стоимость Free Free Free
UI testing
Стоимость Free Free Free
Кроссплатфор-
менный
UI testing
Стоимость Free Free Free
Кроссплатфор-
менный
iOS, Android iOS, Android
UI testing
Стоимость Free Free Free
Кроссплатфор-
менный
iOS, Android iOS, Android iOS
UI testing
Стоимость Free Free Free
Кроссплатфор-
менный
iOS, Android iOS, Android iOS
Кодогенерация
UI testing
Стоимость Free Free Free
Кроссплатфор-
менный
iOS, Android iOS, Android iOS
Кодогенерация + +
UI testing
Стоимость Free Free Free
Кроссплатфор-
менный
iOS, Android iOS, Android iOS
Кодогенерация + - +
UI testing
Стоимость Free Free Free
Кроссплатфор-
менный
iOS, Android iOS, Android iOS
Кодогенерация + - +
UI testing
Стоимость Free Free Free
Кроссплатфор-
менный
iOS, Android iOS, Android iOS
Кодогенерация + - +
Опыт

использования
UI testing
Стоимость Free Free Free
Кроссплатфор-
менный
iOS, Android iOS, Android iOS
Кодогенерация + - +
Опыт

использования - - +
iOS UI testing
Accessibility
+
XCTest
UI-тесты базируются на трех
классах:
• XCUIApplication
• XCUIElement
• XCUIElementQuery
UI test recording
UI-тесты в iOS-проекте / Михаил Домрачев (Improve Digital)
UI test recording
XCUIApplication *app = app2;
[app.buttons[@"start"] tap];
XCUIElement *element = [[[[app.otherElements
containingType:XCUIElementTypeNavigationBar identifier:@“UIView”]
childrenMatchingType:XCUIElementTypeOther].element
childrenMatchingType:XCUIElementTypeOther].element
childrenMatchingType:XCUIElementTypeOther].element;
[element tap];
XCUIApplication *app2 = app;
[app2.keys[@"t"] tap];
[app typeText:@“t"];
. . .
[app typeText:@"c"];
[app2.keys[@“o"]
[element tap];
UI test recording
[app.buttons[@"start"] tap];
XCUIElement *element = [[[[app.otherElements
containingType:XCUIElementTypeNavigationBar identifier:@“UIView”]
childrenMatchingType:XCUIElementTypeOther].element
childrenMatchingType:XCUIElementTypeOther].element
childrenMatchingType:XCUIElementTypeOther].element;
[element tap];
XCUIApplication *app = app2;
XCUIApplication *app = app2;
[app2.keys[@"t"] tap];
[app typeText:@“t"];
. . .
[app typeText:@"c"];
[app2.keys[@“o"]
[element tap];
UI test recording
XCUIElement *element = [[[[app.otherElements
containingType:XCUIElementTypeNavigationBar identifier:@“UIView”]
childrenMatchingType:XCUIElementTypeOther].element
childrenMatchingType:XCUIElementTypeOther].element
childrenMatchingType:XCUIElementTypeOther].element;
XCUIApplication *app = app2;

[app.buttons[@"start"] tap];
XCUIApplication *app = app2;
[app2.keys[@"t"] tap];
[app typeText:@“t"];
. . .
[app typeText:@"c"];
[app2.keys[@“o"]
[element tap];
[element tap];
UI test recording
• Не всегда читаемый код
• Не всегда работающий код
Есть минусы:
• Много кода
• Переиспользование функционала
От теории к
практике
• Stub manager
• Page object pattern
• Snapshot
Stub manager
class NSURLProtocol -  позволяет предопределить работу
системы загрузки URL для iOS
1.  Создать свой класс
2.  Зарегистрировать его
Делается в два действия:
Stub manager
+ (BOOL)canInitWithRequest:(NSURLRequest *)request
class MyNSURLProtocol
Stub manager
+ (BOOL)canInitWithRequest:(NSURLRequest *)request
class MyNSURLProtocol
- (void)startLoading
Stub manager
+ (BOOL)canInitWithRequest:(NSURLRequest *)request
class MyNSURLProtocol
- (void)startLoading
- (void)stopLoading
}
Stub manager
NSData *cachedData = берем данные из кэша
if (cachedData) {
[self.client URLProtocol: self
didFailWithError: создаем ошибку
- (void)startLoading
NSHTTPURLResponse *response = создаем свой response

[self.client URLProtocol: didReceiveResponse: cacheStoragePolicy:];
[self.client URLProtocol:self didLoadData: cachedData];
[self.client URLProtocolDidFinishLoading: self];
} else {
Stub manager
class MyStubManager
NSURLSessionConfiguration setProtocolClasses: @[[MyNSURLProtocol class]]
Page object pattern
Page object pattern
Page object pattern
Profit
• Читабельность кода
• Переиспользование функционала
• Централизация интерфейса пользователя
XCTestUtils
@interface FFElements : NSObject
- (XCUIElement *)objectForKeyedSubscript:(NSString *)key;
- (XCUIElement *)objectAtIndexedSubscript:(NSUInteger)index;
@end
XCTestUtils@interface FFElements : NSObject
- (XCUIElement *)objectForKeyedSubscript:(NSString *)key;
- (XCUIElement *)objectAtIndexedSubscript:(NSUInteger)index;
@end
@interface XCTestCase (Elements)
@property (nonatomic,readonly) FFElements *textFields;
@property (nonatomic,readonly) FFElements *buttons;
@property (nonatomic,readonly) FFElements *labels;
@property (nonatomic,readonly) FFElements *cells;
- (void)wait:(NSTimeInterval)interval;
@end
XCTestUtils@interface FFElements : NSObject
- (XCUIElement *)objectForKeyedSubscript:(NSString *)key;
- (XCUIElement *)objectAtIndexedSubscript:(NSUInteger)index;
@end
@interface XCTestCase (Elements)
@property (nonatomic,readonly) FFElements *textFields;
@property (nonatomic,readonly) FFElements *buttons;
@property (nonatomic,readonly) FFElements *labels;
@property (nonatomic,readonly) FFElements *cells;
- (void)wait:(NSTimeInterval)interval;
@end
@interface XCUIElement (Utils)
@property (nonatomic) NSString *pasteText;
+ (void)forceTap;
@end
XCTestUtils
@interface FFElements : NSObject
- (XCUIElement *)objectForKeyedSubscript:(NSString *)key;
- (XCUIElement *)objectAtIndexedSubscript:(NSUInteger)index;
@end
@interface XCTestCase (Elements)
@property (nonatomic,readonly) FFElements *textFields;
@property (nonatomic,readonly) FFElements *buttons;
@property (nonatomic,readonly) FFElements *labels;
@property (nonatomic,readonly) FFElements *cells;
- (void)wait:(NSTimeInterval)interval;
@end
@interface XCUIElement (Utils)
@property (nonatomic) NSString *pasteText;
+(void)forceTap;
@end
UI-тесты в iOS-проекте / Михаил Домрачев (Improve Digital)
Тесты готовы
А что с ними делать то?
Fastlane
Snapshot
Какая от него польза?
• Делает скриншоты
• Прогоняет тесты
• Легко интегрируется с CI
Snapshot
Как его внедрить?
• fastlane snapshot init
• Настроить Snapfile
• В тестах указать места, где бы вы хотели
получить скриншот
Snapshot
Snapfile
devices ([
"iPhone 6s"
])
Snapshot
Snapfile
devices ([
"iPhone 6s"
])
scheme: “our scheme”
Snapshot
Snapfile
devices ([
"iPhone 6s"
])
scheme: “our scheme”
output_directory: “./path/.”
Snapshot
Snapfile
devices ([
"iPhone 6s"
])
scheme: “our scheme”
output_directory: “./path/.”
stop_after_first_error: Bool
Snapshot
Snapfile
devices ([
"iPhone 6s"
])
scheme: “our scheme”
output_directory: “./path/.”
reinstall_app: Bool
stop_after_first_error: Bool
Snapshot
Snapfile
devices ([
"iPhone 6s"
])
scheme: “our scheme”
output_directory: “./path/.”
reinstall_app: Bool
clear_previous_screenshots: Bool
stop_after_first_error: Bool
Snapshot
Snapfile
devices ([
"iPhone 6s"
])
scheme: “our scheme”
output_directory: “./path/.”
reinstall_app: Bool
clear_previous_screenshots: Bool
erase_simulator: Bool
stop_after_first_error: Bool
Snapshot
Snapfile
devices ([
"iPhone 6s"
])
scheme: “our scheme”
output_directory: “./path/.”
reinstall_app: Bool
clear_previous_screenshots: Bool
languages ([
“en-US”
])
stop_after_first_error: Bool
erase_simulator: Bool
Time for screenshot
• Добавить SnaphotHelper.swift в таргет с тестами
• Вызвать внутри метода setup(): [Snapshot setupSnapshot:app]
• [Snapshot snapshot:@“Name screen" waitForLoadingIndicator:YES];
Snapshot
Snapshot
Обрати
внимание!
• Stub manager
• Page object pattern
• Snapshot
Мы получили
• Уменьшили количество багов с дизайном почти до 0
• Появилась проверка правильного роутинга в приложении
• Внедрили инструмент для быстрой генерации всех
скриншотов приложения и интегрировали тесты с CI
Минусы
• Время на внедрение UI тестов
• Поддержка тестов при рефакторинге
Использовать тесты стоит
• Если у вас долгосрочный проект
• Постоянный диалог по поводу пиксель перфект
• Сложная логика навигации в приложении
СПАСИБО
Домрачев Михаил
iOS developer Improve Digital
Новосибирск
domrachev@improveitgroup.com
misha.domrachev

More Related Content

PPTX
XPath локаторы в Selenium WebDriver
PDF
QA Fes 2016. Алексей Виноградов. Page Objects: лучше проще, да лучшe
PPTX
Modul №2. OOP C++
PPTX
Автоматизация и Selenium IDE
PPTX
Selenium: начало работы
PPTX
Создание графического интерфейса пользователя мобильных Android приложений (ч...
PDF
Школа-студия разработки приложений для iOS. 2 лекция. MVC, View, Controllers
PPS
объекты Word
XPath локаторы в Selenium WebDriver
QA Fes 2016. Алексей Виноградов. Page Objects: лучше проще, да лучшe
Modul №2. OOP C++
Автоматизация и Selenium IDE
Selenium: начало работы
Создание графического интерфейса пользователя мобильных Android приложений (ч...
Школа-студия разработки приложений для iOS. 2 лекция. MVC, View, Controllers
объекты Word

What's hot (8)

PPTX
Самодельная параметризация и параллелизация тестов на Webdriver (JS)
PPTX
Selenium vs AJAX
PPTX
HasValue and AsyncFilter
PDF
JavaScript Базовый. Занятие 09.
PPT
Шаблоны разработки ПО. Часть 3. Шаблоны GoF
KEY
занятие 2
ODP
Entity framework
PDF
Rambler.iOS #3: Test-Driven Development в iOS
Самодельная параметризация и параллелизация тестов на Webdriver (JS)
Selenium vs AJAX
HasValue and AsyncFilter
JavaScript Базовый. Занятие 09.
Шаблоны разработки ПО. Часть 3. Шаблоны GoF
занятие 2
Entity framework
Rambler.iOS #3: Test-Driven Development в iOS
Ad

Similar to UI-тесты в iOS-проекте / Михаил Домрачев (Improve Digital) (20)

PDF
SECON'2017, Мухаметов Андрей, XCTest. UI и Unit тестирование для iOS.
PDF
И снова разработка под iOS. Павел Тайкало
PDF
iOS 7. Новые концепции и новые средства
PDF
Фундаментальные основы разработки под iOS. Павел Тайкало
PPTX
PDF
iOS-05_2-UIKit
PPTX
Автоматизация тестирования iOS приложений: от идеи к готовому решению
PDF
msumobi2. Лекция 1
PPT
CodeFest 2011. Бусыгин Р. — Создание кастомных интерфейсов для iOS
PPTX
новые технологии при разработке нативного I os приложения в рамках проекта ст...
PDF
Избавляемся от старья и переходим на SwiftUI / Руслан Кавецкий (Agora)
PPTX
Прокачиваем WebDriverAgent или как тестировать iOS-приложения после ядерного ...
PDF
Podlodka i os crew 8
PDF
UI+unit testing in iOS
PDF
Fun with core graphics
PDF
UICollectionView — Александр Зимин
PDF
Школа-студия разработки приложений для iOS. Лекция 1. Objective-C
PDF
Прокачиваем WebDriverAgent, или Как тестировать iOS-приложения после ядерного...
PDF
iOS-05_1-UIKit
PDF
E2E-тестирование мобильных приложений
SECON'2017, Мухаметов Андрей, XCTest. UI и Unit тестирование для iOS.
И снова разработка под iOS. Павел Тайкало
iOS 7. Новые концепции и новые средства
Фундаментальные основы разработки под iOS. Павел Тайкало
iOS-05_2-UIKit
Автоматизация тестирования iOS приложений: от идеи к готовому решению
msumobi2. Лекция 1
CodeFest 2011. Бусыгин Р. — Создание кастомных интерфейсов для iOS
новые технологии при разработке нативного I os приложения в рамках проекта ст...
Избавляемся от старья и переходим на SwiftUI / Руслан Кавецкий (Agora)
Прокачиваем WebDriverAgent или как тестировать iOS-приложения после ядерного ...
Podlodka i os crew 8
UI+unit testing in iOS
Fun with core graphics
UICollectionView — Александр Зимин
Школа-студия разработки приложений для iOS. Лекция 1. Objective-C
Прокачиваем WebDriverAgent, или Как тестировать iOS-приложения после ядерного...
iOS-05_1-UIKit
E2E-тестирование мобильных приложений
Ad

More from Ontico (20)

PDF
One-cloud — система управления дата-центром в Одноклассниках / Олег Анастасье...
PDF
Масштабируя DNS / Артем Гавриченков (Qrator Labs)
PPTX
Создание BigData-платформы для ФГУП Почта России / Андрей Бащенко (Luxoft)
PDF
Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...
PDF
Новые технологии репликации данных в PostgreSQL / Александр Алексеев (Postgre...
PDF
PostgreSQL Configuration for Humans / Alvaro Hernandez (OnGres)
PDF
Inexpensive Datamasking for MySQL with ProxySQL — Data Anonymization for Deve...
PDF
Опыт разработки модуля межсетевого экранирования для MySQL / Олег Брославский...
PPTX
ProxySQL Use Case Scenarios / Alkin Tezuysal (Percona)
PPTX
MySQL Replication — Advanced Features / Петр Зайцев (Percona)
PDF
Внутренний open-source. Как разрабатывать мобильное приложение большим количе...
PPTX
Подробно о том, как Causal Consistency реализовано в MongoDB / Михаил Тюленев...
PPTX
Балансировка на скорости проводов. Без ASIC, без ограничений. Решения NFWare ...
PDF
Перехват трафика — мифы и реальность / Евгений Усков (Qrator Labs)
PPT
И тогда наверняка вдруг запляшут облака! / Алексей Сушков (ПЕТЕР-СЕРВИС)
PPTX
Как мы заставили Druid работать в Одноклассниках / Юрий Невиницин (OK.RU)
PPTX
Разгоняем ASP.NET Core / Илья Вербицкий (WebStoating s.r.o.)
PPTX
100500 способов кэширования в Oracle Database или как достичь максимальной ск...
PPTX
Apache Ignite Persistence: зачем Persistence для In-Memory, и как он работает...
PDF
Механизмы мониторинга баз данных: взгляд изнутри / Дмитрий Еманов (Firebird P...
One-cloud — система управления дата-центром в Одноклассниках / Олег Анастасье...
Масштабируя DNS / Артем Гавриченков (Qrator Labs)
Создание BigData-платформы для ФГУП Почта России / Андрей Бащенко (Luxoft)
Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...
Новые технологии репликации данных в PostgreSQL / Александр Алексеев (Postgre...
PostgreSQL Configuration for Humans / Alvaro Hernandez (OnGres)
Inexpensive Datamasking for MySQL with ProxySQL — Data Anonymization for Deve...
Опыт разработки модуля межсетевого экранирования для MySQL / Олег Брославский...
ProxySQL Use Case Scenarios / Alkin Tezuysal (Percona)
MySQL Replication — Advanced Features / Петр Зайцев (Percona)
Внутренний open-source. Как разрабатывать мобильное приложение большим количе...
Подробно о том, как Causal Consistency реализовано в MongoDB / Михаил Тюленев...
Балансировка на скорости проводов. Без ASIC, без ограничений. Решения NFWare ...
Перехват трафика — мифы и реальность / Евгений Усков (Qrator Labs)
И тогда наверняка вдруг запляшут облака! / Алексей Сушков (ПЕТЕР-СЕРВИС)
Как мы заставили Druid работать в Одноклассниках / Юрий Невиницин (OK.RU)
Разгоняем ASP.NET Core / Илья Вербицкий (WebStoating s.r.o.)
100500 способов кэширования в Oracle Database или как достичь максимальной ск...
Apache Ignite Persistence: зачем Persistence для In-Memory, и как он работает...
Механизмы мониторинга баз данных: взгляд изнутри / Дмитрий Еманов (Firebird P...

UI-тесты в iOS-проекте / Михаил Домрачев (Improve Digital)