Прежде всего давайте проясним, что такое живой поиск. Вкратце, мы могли бы сказать, что это поиск, который позволяет непрерывно вводить данные, всегда сохраняя в качестве искомого слова самый последний из них.

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

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

На тестирование у меня ушло несколько часов, чтобы понять, как мы тестируем метод cancel для URLSessionDataTask, когда он действительно вызывается во время какого-то потока или даже лучше (или хуже), как он почти недоступен из-за некоторые наложили ограничения на видимость со стороны Apple.

Вот и все, что мы хотим протестировать.

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

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

Первый подход - theVolatile

Первый и интуитивно понятный подход будет в основном:

  • Утвердите, что количество задач сеанса данных соответствует количеству созданных задач данных;
  • Вызвать метод sut, чтобы отменить все ранее созданные задачи;
  • Подтвердите, что количество задач сеанса dataTasks для подсчета совпадений равно нулю, поскольку мы отменили все задачи;

Некоторые опасения по поводу текущего подхода

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

Не имея никакого контроля над потоком данных в наших тестах и, кроме того, привязывая их к экранированным блокам, мы просто попадаем в изменчивый контекст, предоставляя все средства для проведения нестабильных тестов на CI, каким бы стабильным он ни казался локально.

Второй подход - разочаровывающий

Мы стремимся добиться прекрасной стабильности теста.

Идея заключается в создании тестового двойника для URLSession, чтобы заглушить метод сеанса getAllTasks ().

Мы могли бы создать двойник для URLSessionDataTask и шпионского метода dataTask cancel, чтобы гарантировать, что мы определенно вызвали его.

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

Большой! Не так ли?

Выполнение теста не дает нам сбоев по обоим утверждениям, но на самом деле тест вообще не дает. Да сбивает с толку. Давайте проверим журнал.

Task <D6E1DFDB-D7FA-4CCE-B75E-A76223D61FB3>.<5> finished with error [-1001] Error Domain=NSURLErrorDomain Code=-1001 “(null)” UserInfo={_NSURLErrorRelatedURLSessionTaskErrorKey=(
“LocalDataTask <D6E1DFDB-D7FA-4CCE-B75E-A76223D61FB3>.<5>”
), _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <D6E1DFDB-D7FA-4CCE-B75E-A76223D61FB3>.<5>}

Некоторые указывают на выделение из нее ошибки. Код -1001 представляет собой ошибку тайм-аута. Ошибка в полном видении представляет собой плохое создание URLSession, которое без конфигурации имеет тенденцию к столкновению с сценарием.

Если проблема в том, что конфигурация не передается, давайте просто переопределим инициализацию URLSession на нашем двойнике и передадим ее. Перейдя к объявлению класса, мы получили его:

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

У URLSession есть public init, а не open, что делает его недоступным для переопределения, а кроме того, configuration является свойством только для получения. Связанные руки.

Третий подход - Решение

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

Что бы мы сделали?

Мое предложение и окончательная реализация текущей проблемы - использовать метод swizzling. В основном мы продолжим использовать реальный URLSession, но заменим его реализацию метода, который мы хотим контролировать, на фальшивую.

ДА! Мы немного смешиваем два предыдущих сценария, чтобы добиться контролируемого контекста, и, наконец, тестируем наш метод dataTask cancel .

Первоначально мы создаем расширение URLSession, чтобы добавить статический метод, отвечающий за смену исходной и поддельной реализации.

Смена метода заключается в получении каждого метода экземпляра (оригинального и поддельного) и вызове функции, ответственной за обмен обеими реализациями, и все это во время выполнения. Для этого нам просто нужно передать тип каждого объекта, содержащего реализацию, и селекторы, указывающие соответствующие методы, как показано ниже.

FakeURLSession - это, по сути, класс-заглушка, который предоставляет нам контроль над тем, что возвращается в методе getAllTasks (), и выполняется сразу после его вызова.

Таким образом, наш тест будет очень похож на второй подход. Я только что добавил новое утверждение перед вызовом метода sut, чтобы проверить, действительно ли наше шпионское значение меняется.

Ура! Мы снова находимся под контролем, определяя, что возвращается в getAllTasks (), без необходимости создавать настраиваемый элемент управления async, а также сопоставляя окончательные значения того, что у нас сейчас есть в качестве цели тестирования.

Соображения

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

NSHipster - Метод Swizzling

NSHint - Тестирование камеры на симуляторе

Внутри PSDPDFKit - Swi zzling в Swift

Особая благодарность моим замечательным товарищам по команде Энрике Гало и Джоване Поссебон за отличный обзор!

Огромное спасибо за чтение, надеюсь, оно вам чем-то поможет ❤