Breno Ferreira

Opniões e códigos de um desenvolvedor de software .NET.

Testando Rotas no ASP.NET MVC

leave a comment »

Olá pessoal, tudo bem?

Rotas e MVC

Uma conceito muito importante do ASP.NET MVC é o de rotas. Elas servem para mapear a URI dos requests HTTP para algum Controller e uma Action, e, opcionalmente, algum parâmetro.

A rota mais conhecida é aquela que já vem por padrão quando criamos um projeto novo:

  1. routes.MapRoute(
  2.     "Default", // Route name
  3.     "{controller}/{action}/{id}", // URL with parameters
  4.     new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
  5. );

Conforme adicionamos outras rotas ao nosso projeto, fica clara a necessidade de começarmos a testa-las, para termos certeza de que os Controllers e Actions e parâmetros estão sendo mapeados corretamente.

Definindo Rotas

Como exemplo, criei um Controller chamado ProductsController e adicionei duas rotas, uma para a Action Details, e outra para a Action ProductsInCategory, conforme os dois trechos de código abaixo:

ProductsController
  1. public class ProductsController : Controller
  2. {
  3.     // GET: /Produtos/
  4.     public ActionResult Index()
  5.  
  6.     // GET: /Produtos/123
  7.     public ActionResult Details(int id)
  8.  
  9.     //Get: /Produtos/Bebidas
  10.     public ActionResult ProductsInCategory(String category)
  11. }

 

Routes
  1. routes.MapRoute(
  2.     "ProductDetails",
  3.     "Products/{id}",
  4.     new { controller = "Products", action = "Details" },
  5.     new { id = "\\d+" }); //id must be a number
  6.  
  7. routes.MapRoute(
  8.     "ProductsInCategory",
  9.     "Products/{category}",
  10.     new { controller = "Products", action = "ProductsInCategory" },
  11.     new { category = "[a-zA-Z]+" }); //category must be chars only

 

Testando as Rotas

Para testarmos essas rotas, iremos adicionar algums UnitTests ao nosso projeto de testes. Repare que irei usar o Moq para criar um objeto Fake de um HttpContext. Irei também utilizar o FluentAssertions para fazer as Assertions nos tests.

Teste 1
  1. [TestMethod()]
  2. public void QuandoARotaEBarraProductsOControllerMapeadoDeveSerProductsEActionDeveSerIndex()
  3. {
  4.     //arrange
  5.     RouteCollection routes = new RouteCollection();
  6.  
  7.     var httpContextMock = new Mock<HttpContextBase>();
  8.     httpContextMock.Setup(httpContext => httpContext.Request.AppRelativeCurrentExecutionFilePath)
  9.         .Returns("~/Products");
  10.  
  11.     //act
  12.     MvcApplication.RegisterRoutes(routes);
  13.  
  14.     var routeData = routes.GetRouteData(httpContextMock.Object);
  15.  
  16.     //assert
  17.     routeData.Values["Controller"].Should().Be("Products");
  18.     routeData.Values["Action"].Should().Be("Index");
  19. }

 

Teste 2
  1. [TestMethod()]
  2. public void QuandoARotaEBarraProductsBarraIdOControllerMapeadoDeveSerProductsEActionDeveSerDetailsEIdDeveSer1()
  3. {
  4.     //arrange
  5.     RouteCollection routes = new RouteCollection();
  6.  
  7.     var httpContextMock = new Mock<HttpContextBase>();
  8.     httpContextMock.Setup(httpContext => httpContext.Request.AppRelativeCurrentExecutionFilePath)
  9.         .Returns("~/Products/1");
  10.  
  11.     //act
  12.     MvcApplication.RegisterRoutes(routes);
  13.  
  14.     var routeData = routes.GetRouteData(httpContextMock.Object);
  15.  
  16.     //assert
  17.     routeData.Values["Controller"].Should().Be("Products");
  18.     routeData.Values["Action"].Should().Be("Details");
  19.     routeData.Values["id"].Should().Be("1");
  20. }

 

Teste 3
  1. [TestMethod()]
  2. public void QuandoARotaEBarraProductsBarraCategoriaOControllerMapeadoDeveSerProductsEActionDeveSerProductsInCategoryECategoriaDeveSerBebidas()
  3. {
  4.     //arrange
  5.     RouteCollection routes = new RouteCollection();
  6.  
  7.     var httpContextMock = new Mock<HttpContextBase>();
  8.     httpContextMock.Setup(httpContext => httpContext.Request.AppRelativeCurrentExecutionFilePath)
  9.         .Returns("~/Products/Bebidas");
  10.  
  11.     //act
  12.     MvcApplication.RegisterRoutes(routes);
  13.  
  14.     var routeData = routes.GetRouteData(httpContextMock.Object);
  15.  
  16.     //assert
  17.     routeData.Values["Controller"].Should().Be("Products");
  18.     routeData.Values["Action"].Should().Be("ProductsInCategory");
  19.     routeData.Values["category"].Should().Be("Bebidas");
  20. }

Para testarmos as rotas, precisamos seguir 3 passos:

Arrange: Criamos um objeto novo do tipo RouteCollection. Esse objeto é passado como parâmetro para o método RegisterRoutes. Também devemos criar um objeto Fake do tipo HttpContextBase. Esse Fake irá simular um Request feito para uma URI pré-definida para o teste.

Act: Chamamos o método RegisterRoutes, passando o objeto do tipo RouteCollection, e em seguida, chamamos o método GetRouteData, passando o nosso Fake de HttpContext. Isso irá mapear as informações na URI definida no objeto Fake para Controllers, Actions e parâmetros.

Assert: Realizamos as nossas Assertions necessárias para validar que a rota foi mapeada corretamente. Os dados mapeados estão na propriedade Values do nosso objeto RouteData.

Conclusão

Não é muito difícil testar as rotas, basta conhecer um pouco de como o as rotas são definidas por debaixo dos panos, e saber um pouco sobre como criar objetos Fake. Repare que o conceito de Rotas não é exclusivo do ASP.NET MVC, podendo ser usado em outras tecnologias também, como o WCF WebAPI. Porém, a maneira de testar as rotas aqui são específicas do ASP.NET MVC.

Abraços

Breno Ferreira

Written by Breno Ferreira

11/09/2011 at 18:49

Posted in Dev

Tagged with , ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s