Testowanie konfiguracji routingu w ASP.NET MVC

Luty 20, 2009


Jedną z największych zalet architektury ASP.NET MVC jest prostota pisania testów jednostkowych, co umożliwia łatwą pracę tym wszystkim, którzy stosują TDD. Zdarzają się jednak przypadki, w których wymagana jest od programisty znajomość „zakamarków” frameworka w celu napisania, wydawałoby się prostego, testu. Jednym z takich przypadków jest testowanie routingu zapytań do odpowiedniej akcji kontrolera.

Głównym problemem jest sprzężenie komponentów routingu z klasą HttpContext. Klasa HttpContext moim zdaniem jest zmorą w przypadku wszystkich testów jednostkowych funkcjonalności wykorzystujących klasy z przestrzeni System.Web. W przeszłości, pisząc aplikacje oparte o ASP.NET Web Forms zmuszony byłem do tworzenia klasy adoptującej HttpContext, którą w prosty sposób potrafiłem zastąpić na potrzeby testów obiektami Test Double. W ASP.NET MVC problem ten został wyeliminowany poprzez wprowadzenie klasy HttpContextBase. Mimo to nadal pozostaje problem z tym, że klasa ta posiada zbyt wiele metod i właściwości zwracających często nam potrzebne obiekty. Najczęściej chodzi tutaj o obiekty klas HttpResponse i HttpRequest. Klasy te, podobnie jak klasa HttpContext, posiadają swoje odpowiedniki pozwalające na łatwiejsze testowanie – HttpResponseBase i HttpRequestBase.

To wszystko prowadzi do tego, że testowanie routingu w ASP.NET MVC wymaga z naszej strony dużego nakładu pracy by przygotować odpowiednio obiekty potrzebne do wykonania się testu. Na dodatek to nie koniec problemów. Wykorzystując routing w ASP.NET MVC, jako programiści nie jesteśmy zmuszeni do pisania skomplikowanej logiki, gdyż jedyne co musimy zrobić, to dodać jedną linię kodu domyślnie w klasie Application (global.asax) i już nasze zapytanie HTTP zostanie przekierowane do odpowiedniej akcji. W testach już tak łatwo nie jest, dlatego, że nie jesteśmy w stanie w prosty sposób sprawdzić, która z metod, będąca naszą akcją, zostanie wywołana. Aby dojść do sposobu pozwalającego na sprawdzenie wyniku, wymagane od nas jest zapoznanie się z operacjami wchodzącymi w skład routingu zapytania, które zostały przeze mnie opisane w jednym z poprzednich postów, oraz z paroma innymi klasami takimi jak ControllerActionInvoker czy MvcHandler.

W efekcie końcowym stworzymy test podobny do tego jak ten, poniżej, który weryfikują poprawność domyślnej konfigurację routingu.

//routes.MapRoute("Default",  "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = "" }

[Test]
public void should_route_to_the_home_page()
{
var httpContext = MockRepository.GenerateStub();
var httpRequest = MockRepository.GenerateStub();
httpContext.Stub(x => x.Request).Return(httpRequest);
string testedRequestUrl = "~/Home";
httpRequest.Stub(x => x.AppRelativeCurrentExecutionFilePath).Return(testedRequestUrl);
var routeData = RouteTable.Routes.GetRouteData(httpContext);
var controllerName = routeData.GetRequiredString("controller");
var actionName = routeData.GetRequiredString("action");
Assert.IsTrue(string.Equals(controllerName, "Home",StringComparison.OrdinalIgnoreCase));
Assert.IsTrue(string.Equals(actionName, "Index", StringComparison.OrdinalIgnoreCase));
}

W sumie okazuje się, że test nie jest znów tak trudny jak to się zapowiadało, ale… Zawsze musi być jakieś, ale:). Powyższy test może stwarzać problemy w trakcie refaktoryzacji. Kryteria powyższego testu polegają na porównywaniu ciągu znaków określających nazwę akcji (metody) i nazwę klasy kontrolera, który posiada daną akcję. Problem leży w tym, że ciągi te nie zostaną automatycznie zastąpione przez narzędzia refaktoryzujące takie jak naprzykład Resharper w przypadku zmiany nazwy akcji lub kontrolera.

Istnieje jednak alternatywa i jest ona dostępna w ramach projektu MVC Contrib. Biblioteka MvcContrib.TestHelper wchodząca w skład tego projektu posiada klasę RouteTestingExtensions z metodami rozszerzającymi pozwalającymi w bardzo prosty sposób dokonać odrobinę magii opartej o lambda expressions, co w efekcie pozwoli nam pisać testy takie jak ten poniższy.

[Test]
public void should_route_to_the_home_page()
{
"~/home".Route().ShouldMapTo(h => h.Index());
}

Jak widać test ten jest banalnie prosty i nie wymaga z naszej strony prawie że żadnego nakładu pracy, a co najważniejsze każdy jest w stanie rozpocząć przygodę z testowaniem przez siebie zdefiniowanych route.

Entry Filed under: Programowanie. Tagi: , .

1 Comment Add your own

  • 1. dotnetomaniak.pl  |  Marzec 12, 2009 at 6:09 pm

    Testowanie konfiguracji routingu w ASP.NET…

    Dziękujemy za publikację – Trackback z dotnetomaniak.pl…

    Odpowiedz

Leave a Comment

Required

Required, hidden

Some HTML allowed:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <pre> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Trackback this post  |  Subscribe to the comments via RSS Feed


Aktualnie czytam

  • Enterprise Integration Patterns

Tagi

About Agile ALT.NET ASP.NET MVC DDD Domain Driven Design Domain Model Exceptions Front Controller Logika biznesowa NHibernate OOP ORM Pair Programming Podstawy Prezentacja Projekty Informatyczne Routing SQL TDD Wroc.NET Wzorce XP

Dodatki

Blogroll

Znajomi

Najnowsze komentarze

zajefajnyx on Czy ty też nadużywasz procedur…
jenrom on Logowanie i obsługa wyjątków …
am on Fluent Nhibernate Rocks!!…
Jarek on Logowanie i obsługa wyjątków …
jenrom on Logowanie i obsługa wyjątków …

Archiwa