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: ASP.NET MVC, TDD.
1 Comment Add your own
Leave a Comment
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


1. dotnetomaniak.pl | Marzec 12, 2009 at 6:09 pm
Testowanie konfiguracji routingu w ASP.NET…
Dziękujemy za publikację – Trackback z dotnetomaniak.pl…