Подтвердить что ты не робот

Тестирование HTTP-трафика в приложении Alamofire

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

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

Это сообщение в блоге (http://nshipster.com/xctestcase/) описывает, как легко сделать Mock объект в Swift - но я не уверен, как сделайте это с помощью Alamofire и его цепных ответов.

Я высмеиваю менеджера? запрос? Отклик? Любая помощь будет оценена!

4b9b3361

Ответ 1

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

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

Например, я создал свою версию класса Request, где я определяю пару статических переменных, которые я оцениваю в зависимости от теста, и для этого класса я реализовал только init и responseJSON.

public class Request {

    var request:String?
    struct response{
        static var data:NSHTTPURLResponse?
        static var json:AnyObject?
        static var error:NSError?
    }

    init (request:String){
        self.request = request
    }

    public func responseJSON(options: NSJSONReadingOptions = .AllowFragments, completionHandler: (NSURLRequest, NSHTTPURLResponse?, AnyObject?, NSError?) -> Void) -> Self {

        completionHandler(NSURLRequest(URL: NSURL(string:self.request!)!), Request.response.data, Request.response.json, Request.response.error)
        return self
    }
}

Теперь я могу высмеять ответ в тесте:

func testMytestFunction(){
    var HTMLResponse = NSHTTPURLResponse(URL: NSURL(string: "myurl")!, statusCode: 200, HTTPVersion: "HTTP/1.1", headerFields: nil)

    Request.response.data = HTMLResponse
    Request.response.json = LoadDataFromJSONFile("MyJsonFile")

    request(.POST, "myurl", parameters: nil, encoding: ParameterEncoding.JSON).responseJSON {
        (request, response, JSON, error) -> Void in
        // the JSON and response variable now contains exactly the data that you have passed to Request.response.data and Request.response.json
    }
}

Функция запроса определяется здесь:

public func request(method: Method, URLString: URLStringConvertible, parameters: [String: AnyObject]? = nil, encoding: ParameterEncoding = .URL) -> Request {

    return Request(request: URLString.URLString)
}

public func request(URLRequest: URLRequestConvertible) -> Request {

    return Request(request: "fakecall")
}

Ответ 2

Этот вопрос стареет, но я столкнулся с одной и той же проблемой, и решение очень просто при использовании OHHTTPStubs.

OHHTTPStubs просто издевается над ответами, полученными от NSURLSession, поэтому он хорошо работает с Alamofire, и вы очень хорошо просматриваете свой код.

Например, в вашем тестовом примере просто высмеивайте ответ, используя:

OHHTTPStubs.stubRequestsPassingTest({
  (request: NSURLRequest) -> Bool in
    return request.URL!.host == "myhost.com"
  }, withStubResponse: {
  (request: NSURLRequest) -> OHHTTPStubsResponse in
    let obj = ["status": "ok", "data": "something"]
    return OHHTTPStubsResponse(JSONObject: obj, statusCode:200, headers:nil)
})

Ответ 3

Ожидание ответа от @mattt Я отправляю пример своего кода.

Скажем, что у нас есть класс Client, который отвечает за вызов простой веб-службы. Этот класс реализует функцию под названием userSignIn, которая выполняет знак с использованием WS.

Это код функции userSignIn:

func userSignIn(
        #email:String,
        password:String,
        completionHandler: (Bool, String?, NSError?) -> Void
        )-> Void
        {

            var parameters:[String:AnyObject] = [
                "email":email,
                "password":password,
            ]


            Alamofire.request(.POST, Client.urlPath, parameters: parameters, encoding: ParameterEncoding.JSON).responseJSON {
                (request, response, JSON, responseError) -> Void in

                // Setup callback params

                // HERE WE INJECT THE "FAKE" DATA--------
                var operationComplete = false
                var accessToken:String?
                var error:NSError?
                // --------------------------------------

                if let statusCode = response?.statusCode {

                    // Check for errors and build response data
                    (operationComplete, accessToken, error) = self.checkSignInResponse(statusCode, JSON: JSON)
                }

                // Call the completion handler
                completionHandler(operationComplete, accessToken, error)
            }
    }

Целью функции является получение маркера из веб-службы, если информация, переданная пользователем, верна.

Функция checkSignInResponse (я не сообщаю свой код, так как она не полезна для ответа) имеет роль для оценки трех переменных operationComplete, accessToken и error в зависимости от полученного ответа JSON.

Теперь, когда 3 переменные имеют значение, мы вызываем completionHandler, используя их.

Как издеваться над этой функцией?!

Чтобы высмеять ответ, я переопределяю функцию userSignIn непосредственно в тестовую функцию (как объясняется в статье NSHipster).

func testUserSignIn_whenParamsAreInvalid(){

    class MockClient:Client {

        override func userSignIn(#email: String, password: String, completionHandler:
            (Bool, String?, NSError?) -> Void) {

            // Set callback params
            var operationComplete = false
            var accessToken:String? = nil
            var error:NSError? = NSError(domain: "Testing", code: 99, userInfo: nil)

            completionHandler(operationComplete, accessToken, error)
        }
    }

    signInViewController!.client = MockClient()
    signInViewController!.loadView()

    fillRegisterFieldsWithDataAndSubmit(femail(), password: fpassword())

    XCTAssertNotNil(signInViewController!.error, "Expect error to be not nil")

}

то я заменяю Client внутри контроллера представления, который я тестирую, используя мой "издевавшийся" клиент. В этом случае я проверяю, что контроллер передает информацию о функциях недействительно, поэтому я проверяю, что свойство error контроллера не равно нулю. Чтобы заставить эти данные, я просто установил operationComplete в false и я вручную создаю NSError.

Это имеет смысл для вас? Я не уверен, что этот тест - хороший тест... но по крайней мере я могу проверить поток данных.