Использование URLProtocol для имитации сетевых запросов на iOS
Обеспечение стабильной работы UITest может быть сложной задачей, особенно если ваше приложение получает данные с сервера. Основная причина этого заключается в том, что некоторые тесты будут зависеть от сетевого подключения. Эти типы тестов известны как интеграционные тесты и полезны для тестирования данных, которые возвращает нам сервер. Тем не менее, мы должны учитывать следующие вещи…
- Выполнение этих тестов может занять много времени и, возможно, завершиться ошибкой из-за плохой задержки.
- Вызывать сбои в нашем конвейере непрерывной интеграции.
- Если произойдет сбой API, наши тесты не пройдут.
В этой статье мы рассмотрим способ решения этих проблем с помощью насмешек.
Мы напишем небольшой API, чтобы имитировать наши UITests было легко и безболезненно.
Зачем издеваться над сетевыми запросами?
Имитация сетевых запросов в ваших UITests может помочь вам создать предсказуемую среду тестирования. Управляя данными, которые получает ваше приложение, вы можете убедиться, что ваше приложение работает должным образом в различных сценариях.
Представляем URLProtocol
Мы будем использовать старый API, который существует со времен iOS 2 и называется URLProtocol.
Что такое URL-протокол?
- Он отвечает за загрузку данных URL для конкретного протокола.
- Это абстрактный тип, который предназначен для подкласса.
- Он может перехватывать и манипулировать сетевыми ответами на запросы, которые мы делаем в приложении.
Позже мы создадим собственный подкласс URLProtocol для перехвата сетевых вызовов, которые делает наше приложение, а затем вернет настроенный фиктивный ответ.
Издевательство над нашей моделью предметной области
Мы должны имитировать данные ответа на основе наших моделей предметной области, чтобы ответ оставался таким же, как ожидает приложение. Я собираюсь создать вспомогательное расширение нашей модели предметной области, чтобы сделать это проще:
Здесь у нас есть модель предметной области ShoppingList
с помощником для создания макета, принимающего массив строк.
Это расширение также полезно для:
- Повторное использование в наших модульных тестах.
- Построение предварительных просмотров SwiftUI, которые зависят от этой модели.
Закладка фундамента 🏗
Затем давайте начнем писать наш API для создания фиктивного ответа с заданным путем URL и типом ответа:
Авария:
- Мы принимаем путь URL к конечной точке, которую мы хотим имитировать, и тип ответа.
- Мы передаем ответ типа ошибка или успешно.
- В расширении мы создаем тип
MockResponse
из нашей модели предметной областиShoppingList
.
Этот код элегантно создает фиктивный ответ. И расширение очень полезное. Если мы добавим дополнительные имитированные ответы, мы можем легко добавить их сюда.
URL-протокол на практике
Теперь мы переопределим упомянутый ранее URLProtocol пользовательской реализацией:
Авария:
- Во-первых, мы указываем, какие запросы мы будем перехватывать внутри
canInit(with request: URLRequest) -> Bool
. Мы храним их внутри словаря. Все остальные запросы обрабатываться не будут. startLoading()
— это место, где мы реализуем логику возврата поддельного ответа.- Сначала мы получаем ответ от
allowedRequests
, а затем проверяем, относится ли он к типуerror
илиsuccess
. - В зависимости от типа мы затем вызываем методы в URLProtocolClient для связи с системой загрузки URL, передавая имитированные данные.
Регистрация UITestConnectionHandler
Чтобы UITestConnectionHandler
был распознан системой загрузки URL, нам нужно зарегистрировать его:
Авария:
setMockedResponse()
— это просто фасад для установкиMockResponse
наUITestConnectionHandler
.register()
делает наш пользовательский URLProtocol видимым для системы загрузки URL. Это важно вызывать, чтобы все наши сетевые запросы проходили черезUITestConnectionHandler
.unregister()
делает обратное и удаляет его из системы загрузки URL.
Я создал фасад для настройки имитируемых ответов onUITestConnectionHandler
, теперь мы можем объединить весь этот код в отдельный пакет, если захотим.
Запуск кода для UITests в основном приложении
Мы хотим зарегистрироваться UITestConnectionHandler
когда запускается наше приложение UITest runner. Поэтому для этого мы создадим расширение ProcessInfo, чтобы определить, запускаем ли мы UITests:
Имея это на месте, теперь мы можем проверить в нашем основном приложении, запускаем ли мы UITests, и если да, то зарегистрируем UITestConnectionHandler
:
Хороший! Теперь мы готовы написать наш UITest.
Написание UITest ✅
Когда все готово, мы можем написать наш UITest. Мы настроим фиктивный ответ, используя созданный ранее фасад:
Вуаля! Простой не так ли? И не забывайте, что для добавления другого фиктивного ответа требуется только добавить новый тип MockResponse
внутри расширения, которое мы определили ранее.
Заключение
Имитируя сетевые запросы в наших UITests, мы можем создать более стабильную среду тестирования и убедиться, что наше приложение работает должным образом в различных сценариях. Хотя есть и другие способы обеспечить стабильность ваших тестов UITest, URLProtocol — это мощный инструмент, который может помочь вам создавать предсказуемые тесты, не полагаясь на сторонние платформы.
Если у вас есть какие-либо вопросы или вы думаете, что я что-то упустил, оставьте отзыв ниже! Наконец, не забудьте поставить 👏, если вам понравилась эта статья.
Спасибо за прочтение! 👋