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.

 

 

2 comentarios:

Anónimo dijo...

Juan, una consulta/ sugerencia... Permiteme el abuso ¿Ok?

¿Realizarás un post sobre como hacer un test unitario a un controller que tiene un contexto EF?

:)

Juan Quijano dijo...

Para nada un abuso. Aunque este blog tiene como objetivo servirme como baul de recuerdos (mi memoria es RAM, y pierdo los recuerdos al milisegundo de aprenderlo), todo el mundo es bienvenido en opiniones y peticiones.

Creo que si que haré un artículo sobre el tema que me dices, porque tengo en la API algunos controladores tal y como dices, directamente enganchados a EF.

No lo prometo, pero es bastante posible.