Одной из наиболее распространенных задач в разработке приложений для iOS является написание сетевого кода. Существует высокая вероятность того, что ваша команда также может разработать собственный бэкэнд-API и не всегда готова к тому, чтобы вы могли проводить интеграционные тесты, когда вам это нужно.

Чтобы создать полнофункциональное демонстрационное приложение, вам нужно смоделировать ответ вашего сервера. Для вас как разработчика iOS есть несколько обходных решений:

  1. Используйте сторонний сервис, например Postman.
  2. написать свой собственный фиктивный localhost сервер

К счастью, вы можете имитировать ответ сервера прямо в коде Swift/Objective-C, используя URLProtocol, предоставленный Apple.

Ваш первый протокол MockURL

Прежде всего, давайте создадим ваш класс MockURLProtocol, унаследовав open class URLProtocol:

requestHandler — это место, куда мы позже передадим наш пользовательский ответ сервера.

Нам нужно override 4 функции, рекомендованные Apple:

  • canInit(with request: URLRequest) -> Bool
  • canonicalRequest(for request: URLRequest) -> URLRequest
  • stopLoading()
  • startLoading()

Интеграция

Затем, вместо использования URLSession.shared, инициализируйте URLSession вашим пользовательским URLSessionConfiguration:

let configuration = URLSessionConfiguration.ephemeral
configuration.protocolClasses = [MockURLProtocol.self]
let urlSession = URLSession(configuration: configuration)
urlSession.dataTask(with: urlRequest) { data, response, error in
   // ... handle your response
}.resume()

Однако я предлагаю добавить флаг Swift, чтобы легко вернуться к исходному коду:

Наконец, передав код ответа примера сервера, предоставленный вашей командой бэкэнда, в requestHandler :

Настройте свой ответ

Есть 2 основных способа настроить свой ответ:

  1. Обработка request такой информации, как:
MockURLProtocol.requestHandler = {request in 
// checking URL Path ...
if !request.url!.absoluteString.contains("/employeeInfo") {
// return 404 HTTPURLResponse
}
// checking headers ...
guard let v = request.allHTTPHeaderFields?["Authorization"] else {
    return // or throw an error
}

2. Наследовать MockURLProtocol, что очень полезно, если вы создаете разные class для разных запросов:

Например, если у вас есть класс EmployeeInfoRequest, вам просто нужно переопределить функцию startLoading, чтобы передать ваш фиктивный ответ. Затем передайте новый класс EmployeeInfoRequest.iMockURLProtocol -[URLSessionConfiguration protocolClasses]

Вы можете применить полиморфизм, используя протокол:

Дополнительные преимущества

Помимо поддержки разработчика iOS в создании функционального приложения без готового бэкенда, имитация URLProtocol на самом деле очень хороша для написания модульных тестов. Передача фиктивного ответа таким образом может помочь вам проверить:

  • соответствует ли ваша модель ответу вашего сервера JSON
  • Ваш код URLSession уже вызывает resume() ?

Чтобы узнать больше о соответствующем тестировании, посетите доклад Apple на WWDC18: Советы и рекомендации по тестированию.