Mostrando entradas con la etiqueta Web API. Mostrar todas las entradas
Mostrando entradas con la etiqueta Web API. Mostrar todas las entradas

sábado, 1 de febrero de 2014

Test unitarios de un Controller que devuelve IHttpActionResult

Sigo con el intenso aprendizaje de construir una API REST con ASP.NET Web API, y me encontraba con el problema de que necesitaba poder realizar los test a los fallos que me estaban enviando los desarrolladores de las app que consumen este API.

La parte buena de trabajar con Web API, es que utiliza´el patrón MVC, el cual me permite testear el controlador (incluso la vista si me pusiera), la dificultad es que nunca había testeado el interfaz de  IHttpActionResult.

Pero es bastante sencillo, y me ha mostrado una debilidad de mi formato de mensajes (que ya me habían avisado Ambrin y Julio).

Voy a probar que el resultado de una operación es efectivamente un código de error específico.

Para lo cual tengo una clase Error tal que así:

    public class MensajeDeError
   
{
       
public string Code { get; set; }
       
public string Message { get; set; }
       
public string MessageDetail { get; set; }
       
public string MoreInfo { get; set; }
    }

El Controlador que voy a testear es algo tal que así:

        [HttpPost] public IHttpActionResult PostItem(negociositem item)
        {
           
if (item != null)
            {
               
var accion = new Items();
               
var error = new MensajeDeError();

               
var resultado = accion.AddItem(item, out error);

               
if (error.Code == ObtenError.Sin_error().Code)
                {
return Json(resultado); }
               
else
               
{ return Json(error); }
            }
           
else
           
{
               
return Json(ObtenError.Item_no_valido());
            }
        }

Como creo que se lee fácilmente, lo que hago es intentar persistir un item. Y si tengo algún error, lo que me devuelve (en vez del objeto resultado) un objeto mensaje de error. (Y aquí está la debilidad de devolver dos mensajes diferentes).

¿Cómo pruebo esto? Haciendo un test que fuerce un error, y comprobando que el código de error sea el esperado.

using api.Controllers;
using api.Entidades;
using System.Web.Http.Results;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace api.Controllers.Tests
{
    [
TestClass()]
   
public class ItemsControllerTests
   
{
        [
TestMethod()]
       
public void PostItemTest()
        {
           
var accion = new ItemsController();
           
var item = new negociositem { business_id = 0,
                                                          name =
"borrame",
                                                          description =
"",
                                                          origin = 2, picture =
"" };

           
var resultado = accion.PostItem(item);

           
Assert.AreEqual("503", ((JsonResult<api.MensajeDeError>)resultado).Content.Code);
        }
    }
}

¿Qué es lo importante aquí?

Primero asegurarme que me estoy importando al proyecto de Testing los namespaces adecuados. Es decir, los que contienen los tipos de objeto que voy a usar (Controllers, y Entidades), y el interfaz de respuesta (System.Web.Http.Results).

Segundo (y que vuelve a mostrar la debilidad del formato de respuesta), debo asegurarme de que el tipo de la respuesta sea la esperada. Por ejemplo, si todo hubiese ido bien, no hubiera recibido un tipo MensajeDeError, si no un tipo negociositem… lo cual es incómodo para testear y trabajar con esta api (pero es bueno para reducir el consumo de tráfico ya que devuelve solo lo que necesitas.

A partir de aquí, se me habré el horizonte de poder probar como si estuviera enviando peticiones a la API como cualquier otra APP, y pudiendo hacer test casi de integración.

Espero que sea de utilidad para alguien.

 

 

domingo, 19 de enero de 2014

Web API. Fiddler OK, jQuery Fail

Llevo un día completo y complejo con un auténtico error rarísimo.

He construido una API REST con ASP.NET Web API que puedes ver lo básico en este tutorial en GenbetaDev.

Pero cuando el resto del equipo se puso a intentar consumirla desde jQuery, nos encontramos con un molesto error que nos devolvía, según la herramienta de “snifado” de las comunicaciones http, errores diferentes.

Lo peor es que Fiddler, que es la que utilizo para probar que todo está bien programado, me respondía que todo era correcto… para volverse loco!!.

Por suerte un mensaje en la consola de IE11 (que se abre con F12) me indicó el camino del error (a pesar de que Ambrin me lo venía avisando desde el principio): tenía un problema de cross domain.

¿Pero cómo podía tener ese problema si me baje el paquete de Nuget para habilitar CROS y lo active en el fichero App_Star/WebApiConfig.cs?

Pues porque soy un gañan apresurado, y me había saltado un paso en la configuración. Si bien había habilitado el CORS, había ignorado completamente la definición de cuales eran los dominios desde donde iba a aceptar peticiones a la API.

Así en el fichero que os he indicado anteriormente he puesto:

    public static class WebApiConfig
   
{
       
public static void Register(HttpConfiguration config)
        {
           
// Web API configuration and services

            // Habilitando CORS
           
var urlPermitidas = new EnableCorsAttribute("*", "*", "*");
            config.EnableCors(urlPermitidas);

           
// Web API routes
           
config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name:
"DefaultApi",
                routeTemplate:
"api/{controller}/{id}",
                defaults:
new { id = RouteParameter.Optional }
            );
        }
    }

 
Aquí lo único que tengo que tener cuidado, es que estoy configurando una API pública sin validación de seguridad. Es decir, cualquiera, desde cualquier sitio va a poder leer de esta API.
La información completa y un excelente ejemplo lo puedes encontrar en este artículo.

Espero que sea de utilidad.