unit testing - unitaria - Unidad de pruebas de tráfico HTTP en la aplicación Alamofire
pruebas unitarias php (3)
Esperando una respuesta de @mattt publico un ejemplo de mi código.
Digamos que tenemos una clase de Client
que es responsable de llamar a un servicio web simple. Esta clase implementa una función llamada userSignIn
que realiza un inicio de sesión utilizando el WS.
Este es el código para la función 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)
}
}
El objetivo de la función es obtener un token del servicio web si la información transmitida por el usuario es correcta.
La función checkSignInResponse
(no checkSignInResponse
su código, ya que no es útil para la respuesta) tiene la función de valorizar las 3 variables operationComplete
, accessToken
y error
según la respuesta JSON recibida.
Ahora que las 3 variables tienen un valor, llamamos a completionHandler
usándolas.
¿Cómo burlarse de esta función?
Para simular la respuesta, userSignIn
función userSignIn
directamente en la función de prueba (como se explica en el artículo de 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")
}
Luego sustituyo al client
dentro del controlador de vista que estoy probando usando mi cliente "simulado". En este caso, estoy probando que el controlador pasa a la información de la función que no es válida, así que verifico que la propiedad de error
del controlador no sea nula. Para forzar estos datos simplemente establezco operationComplete
en falso y genero manualmente un NSError
.
¿Tiene algún sentido para ti? No estoy seguro de que esta prueba sea una buena prueba ... pero al menos puedo verificar el flujo de datos.
Estoy luchando un poco para encontrar la mejor manera de probar una aplicación que utiliza Alamofire para ayudar a sincronizar con los datos del servidor.
Quiero poder probar mi código que utiliza Alamofire y procesa las respuestas JSON de un servidor. Me gustaría burlarme de esas pruebas para poder enviar los datos de respuesta esperados a esas pruebas sin incurrir en tráfico de red real.
Esta publicación del blog ( http://nshipster.com/xctestcase/ ) describe lo fácil que es simular un objeto en Swift, pero no estoy seguro de cómo hacerlo con Alamofire y sus respuestas encadenadas.
¿Me burlaría del gerente? ¿la solicitud? ¿Respuesta? ¡Cualquier ayuda sería apreciada!
Esta pregunta se está haciendo vieja, pero acabo de encontrar el mismo problema y la solución es muy sencilla cuando se usan OHHTTPStubs.
OHHTTPStubs simplemente se burla de las respuestas que recibe de NSURLSession, por lo que funciona bien con Alamofire, y obtiene una muy buena cobertura de la ruta de su código.
Por ejemplo, en su caso de prueba, simplemente se burla de la respuesta usando:
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)
})
Estoy agregando otra respuesta ya que acabo de encontrar este enfoque que, en mi opinión, es más fácil y realmente fácil de leer y usar.
He creado una clase ficticia de Alamofire que contiene solo las funciones y los tipos necesarios para las pruebas. Ahora incluyo este archivo en el objetivo de prueba en lugar del Alamofire real.
Por ejemplo, he creado mi versión de la clase de Request
donde defino un par de variables estáticas que valorizo según la prueba, y para esta clase implementé solo la función init
y 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
}
}
Ahora puedo burlar una respuesta en una prueba:
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
}
}
La función de solicitud se define aquí:
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")
}