Skip to content

Latest commit

 

History

History
50 lines (29 loc) · 7.64 KB

testing.md

File metadata and controls

50 lines (29 loc) · 7.64 KB

TDD и VIPER

Кратко о том что такое TDD

TDD - разработка через тестирование. Предполагается, что в начале пишутся тесты, потом реализация. В случае, если мы закрываем реальные классы протоколами, они идут первыми. После того, как все компоненты написаны - они могут быть интегрированы.

Благодаря такому подходу достигается полное описание ожидаемого поведения класса в тестах. Тесты могут служить в качестве примеров использования класса. Также TDD позволяет нам непредвзято посмотреть на класс с точки зрения пользователя данного класса до его написания.

Более подробно тема TDD в iOS была разобрана в статье Андрея Резанова.

VIPER

Обычно разделения на основные слои приложения достаточно для того, чтобы довольно неплохо протестировать сервисный и Core слой, но при наличии "толстого" ViewController возникают проблемы в тестировании Presentation слоя. Поэтому многие оставляют его без достаточного покрытия тестами. Давайте разберемся, как VIPER-модули могут помочь нам в покрытии View тестами.

Общим подходом для тестирования является следующий: окружаем объект тестируемого класса протокол-моками зависимостей. Вызываем методы интерфейса/манипулируем свойствами, проверяем вызовы методов моков.

Тестирование View

Существует некоторое количество библиотек, помогающих в тестировании UI слоя, а с недавних пор у нас появились еще и UI-тесты. Достаточно ли этого для полноценного покрытия View? На наш взгляд - нет.

UI-тесты могут служить неплохим способом написания acceptance, или приемочных тестов. В роли черного ящика выступает все боевое приложение, и мы через интерфейс приложения пытаемся получить тот или иной результат.

Проблема с UI-тестами в том, что в случае перегруженного VC весь View является для нас черным ящиком с множеством состояний, и для тестирования необходимо слишком большое количество тестов.

Чем нам тут может помочь VIPER? Из ViewController выносится логика по подготовке и представлению данных в Presenter. Соответственно на View ложится ответственность лишь за обработку и прокидывание событий в Presenter, а также за отображение UI. Отдельно необходимо заострить внимание на том, что View - это не обязательно UI, а класс, через который происходит взаимодействие внешнего мира с модулем. Что это означает для нас? IBOutlet и IBAction необходимо делать публичными. Как итог мы получаем возможность протестировать всевозможные нажатия, заполнение полей и прочее без симуляции нажатий, поиска нужных кнопочек по тексту на них и прочих ненадежных вещей.

Подытожим, выделив 2 основных вида тестов:

  • Взаимодействуем с IBOutlet/вызываем IBAction -> проверяем, что были вызваны соответствующием методы мока Presenter
  • Вызываем методы протокола, через который общается Presenter -> проверяем, что меняются IBOutlet/View

Отдельно можно выделить тестирование методов жизненного цикла ViewController/View, на которые нам так или иначе необходимо ориентироваться, так как зачастую Presenter не может начинать настройку View до -viewDidLoad или -viewWillAppear.

Тестирование Router

Методы роутера вызываются, когда необходимо совершить переход из текущего ViewController. Соответственно тестами покрываются методы переходов/закрытия текущего контроллера. Тестируем вызовы всевозможных аниматоров переходов.

Тестирование Interactor

Interactor является связующим звеном в работе с всевозможными сервисами. Именно через него идет работа со Storage, в нем создаются PONSO-объекты.

Большинство тестов касаются проверки вызовов одних сервисов в зависимости от ответов других.

Тестирование Presenter

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

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

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

Тестирование Assembly

Assembly настраивает зависимости компонентов модуля. Ее тесты ответственны за то, чтобы проверять, что модуль состоит из правильных частей и все зависимости заполнены.

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