##TDD и VIPER
##Кратко о том что такое TDD
TDD - разработка через тестирование. Предполагается, что в начале пишутся тесты, потом реализация. В случае, если мы закрываем реальные классы протоколами, они идут первыми. После того, как все компоненты написаны - они могут быть интегрированы.
Благодаря такому подходу достигается полное описание ожидаемого поведения класса в тестах. Тесты могут служить в качестве примеров использования класса. Также TDD позволяет нам непредвзято посмотреть на класс с точки зрения пользователя данного класса до его написания.
Более подробно тема TDD была разобрана в статье Андрея Резанова.
##VIPER Обычно разделения на основные слои приложения достаточно для того, чтобы довольно неплохо протестировать сервисный и Core слой, но при наличии "толстого" VC возникают проблемы в тестировании Presentation слоя, и потому многие оставляют его без тестов. Давайте разберемся как VIPER-модули могут помочь нам в покрытии View тестами.
Общим подходом для тестирования является следующий: Окружаем объект тестируемого класса протокол-моками зависимостей. Вызываем методы интерфейса/манипулируем свойствами, проверяем вызовы методов моков.
###Тестирование View Существует некоторое количество библиотек, помогающих в тестировании UI слоя, а с недавних пор у нас появились еще и UI-тесты. Достаточно ли этого для полноценного покрытия View? На мой взгляд - нет.
UI-тесты могут служить неплохим способом написания acceptance, или приемочных тестов. В роли черного ящика выступает все боевое приложение, и мы через интерфейс приложения пытаемся получить тот или иной результат, опять же на интерфейсе.
Проблема с UI-тестами в том, что в случае перегруженного VC весь View является для нас черным ящиком с множеством состояний, и для тестирования необходимо слишком большое количество тестов.
Чем нам тут может помочь VIPER? Из VC выносится логика по подготовке и представлению данных в Presenter. Соответственно на View ложится ответственность лишь за обработку и прокидывание событий в Presenter, а также за отображение UI. Отдельно необходимо заострить внимание на том, что View является не обязательно UI, это класс через который происходит взаимодействие внешнего мира с модулем. Что это означает для нас? Это означает, что IBOutlet и IBAction необходимо делать публичными. Как итог мы получаем возможность протестировать всевозможные нажатия, заполнение полей и прочее без симуляции нажатий, поиска нужных кнопочек по тексту на них и прочих ненадежных вещей.
Отдельно замечу, что Presenter общается с View через протокол.
Подытожим, выделив 2 основных вида тестов:
- Взаимодействуем с IBOutlet/вызываем IBAction -> проверяем, что были вызваны соответствующием методы мока Presenter
- Вызываем методы протокола, через который общается Presenter -> проверяем, что меняются IBOutlet/View
Отдельно можно выделить тестирование методов жизненного цикла VC/V, на которые нам так или иначе необходимо ориентироваться, т.к. зачастую Presenter не может начинать настройку View до viewDidLoad
или viewWillAppear
.
###Тестирование Router Методы роутера вызываются когда необходимо совершить переход из текущего VC. Соответственно тестами покрываются методы переходов/закрытия текущего контроллера. Тестируем вызовы всевозможных аниматоров переходов.
###Тестирование Interactor'ов Interactor является связующим звеном в работе с всевозможными сервисами. Именно через него работа идет работа со Storage, в нем создаются PONSO-объекты.
Но большинство тестов касаются проверки вызовов одних сервисов в зависимости от ответов других.
###Тестирование Presenter Presenter можно назвать связающим звеном модуля, т.к. в ним происходит проксирование запросов от одной части модуля к другой. Тесты на подобную передачу составляют львиную долю от тестов Presenter.
Отдельно замечу, что Presenter является входной точкой для модуля, именно в него передаются данные с предыдущего контроллера. На это опять же необходимо писать тесты.
Presenter является местом, где скорее всего будет максимальное число свитчей и ветвлений. Это также необходимо учитывать, и на вход подавать все возможные принципиально отличающиеся друг от друга комбинации значений.
###Тестирование Assembly Assembly настраивает зависимости компонентов модуля. Его тесты ответственны за то, чтобы проверять, что модуль состоит из правильных частей и все зависимости заполнены.
К счастью, при строгой структуре модуля, данные тесты могут быть созданы автоматически.