Testowanie aplikacji ASP.NET MVC

Udostępnij na: Facebook

Autor: Piotr Zieliński

Opublikowano: 2010-10-29

Wprowadzenie

Framework ASP.NET MVC został stworzony m.in. po to, aby ułatwić testowanie. Elastyczna architektura oraz separacja kodu pozwala na łatwe przetestowanie różnych aspektów aplikacji. Dzięki wzorcowi Model-View-Controller warstwa prezentacji jest oddzielona od logiki biznesowej. W aplikacji ASP.NET MVC można przetestować następujące aspekty:

  • widok zwrócony przez kontroler,
  • dane przekazane do widoku przez kontroler,
  • rezultat zwrócony przez kontroler (np. widok lub przekserowanie).

Utworzenie projektu

Dla celów artykułu zostanie utworzona prosta aplikacja ASP.NET MVC. Wybieramy zatem z menu głównego kolejno New->Project->Web->ASP.NET MVC 2. Po wprowadzeniu nazwy i akceptacji zostanie wyświetlone następującego okienko:

Rysunek 1. Wybór frameworku do testowania.

Jak już tu wspomniano, framework ASP.NET MVC został stworzony z myślą o łatwym testowaniu aplikacji. Kreator zatem automatycznie może wygenerować osobny projekt przeznaczony do testu jednostkowego. Ponadto Visual Studio nie ogranicza nas tylko do frameworku zaprojektowanego przez Microsoft. Możliwe jest wybranie z listy dowolnego zainstalowanego narzędzia. W naszym przykładzie użyjemy standardowego frameworku Visual Studio Unit Test.

Kreator automatycznie wygeneruje przykładowe kontrolery (Home i Account) oraz stosowne testy jednostkowe.

Testowanie zwróconego widoku

Kontroler Home zawiera m.in. akcję About, przekierowującą do widoku o tej samej nazwie:

public ActionResult About()
{
     return View("About");
}

Warto zaznaczyć, że widok jest zwracany w sposób jawny – z podaniem jego nazwy. Ułatwia to znacznie testowanie, ponieważ można wtedy oprzeć się na nazwie. W przypadku niejawnego zwracania widoku (tj. return View()) taka asercja byłoby niemożliwa, ponieważ właściwość ViewName zwracałaby wartość pustą ("").

Zadaniem testu jednostkowego jest zweryfikowanie, czy wywołanie kontrolera zwraca prawidłowy widok. Implementacja stosownej metody testującego wygląda więc następująco:

 [TestMethod]
public void About()
{
     // Arrange
     HomeController controller = new HomeController();

     // Act
     ViewResult result = controller.About() as ViewResult;

     // Assert
     Assert.AreEqual("About", result.ViewName);
}

Najpierw tworzona jest oczywiście instancja kontrolera. Następnie wywoływana jest odpowiednia akcja. Na końcu wystarczy sprawdzić, czy zwrócony widok faktycznie jest tym, którego się spodziewamy. Przykład może wydawać się banalny, jednak często akcje zawierają bardziej złożoną logikę i zwracają widok zależny od parametru wejściowego. Na przykład, łatwo sobie wyobrazić, że akcja przyjmuje pewien identyfikator (np. z QueryString), a następnie pobiera dane z bazy danych. Następnie, w zależności od pobranych danych, zwraca odpowiednią akcje. W takim przypadku napisanie testu jednostkowego wydaje się jak najbardziej rozsądne.

Testowanie zwróconych danych

Kolejnym typem testów jest weryfikacja, czy odpowiednie dane zostały przekazane do widoku. Aby maksymalnie uprościć problem, rozważmy przypadek, w którym przekazujemy po prostu tekst:

public ActionResult Index()
{
     ViewData["Message"] = "Welcome to ASP.NET MVC!";

     return View();
}

Test jednostkowy sprawdzający, czy zostały przekazane poprawne dane:

[TestMethod]
public void Index()
{
     // Arrange
     HomeController controller = new HomeController();

     // Act
     ViewResult result = controller.Index() as ViewResult;

     // Assert
     ViewDataDictionary viewData = result.ViewData;

     Assert.AreEqual("Welcome to ASP.NET MVC!", viewData["Message"]);
}

Jak widać, test jest również bardzo prosty. Analogicznie do poprzedniego przypadku wywołujemy akcję i analizujemy ViewResult. Dane przekazane do widoku znajdują się we właściwości ViewData.

Testowanie zwróconego rezultatu

Akcje nie tylko zwracają widok, jak to przedstawiono w poprzednich przykładach. Oprócz ViewResult, mogą też zwracać RedirectToRouteResult i  JsonResult. Rozważmy zatem akcję, która przekierowuje do akcji Index (czysto teoretyczny przypadek):

public ActionResult Redirect()
{
     return RedirectToAction("Index");
}

Test jednostkowy powinien najpierw sprawdzać, czy jakiekolwiek przekierowanie zostało wykonane, a jeśli tak, to jakie:

[TestMethod]
public void Redirect()
{
     // Arrange
     HomeController controller = new HomeController();

     // Act
     RedirectToRouteResult result = controller.Redirect() as RedirectToRouteResult;

     // Assert
     Assert.IsNotNull(result);

     Assert.AreEqual("Index", result.RouteValues["action"]);
}

Zakończenie

Architektura wzorca MVC bardzo ułatwia testowanie. W przypadku czystego ASP.NET zadanie byłoby znacznie trudniejsze, ponieważ często napisany  kod nie spełnia zasady SoC (separation of concerns).


          

Piotr Zieliński

Absolwent informatyki o specjalizacji inżynieria oprogramowania Uniwersytetu Zielonogórskiego. Posiada szereg certyfikatów z technologii Microsoft (MCP, MCTS, MCPD). W 2011 roku wyróżniony nagrodą MVP w kategorii Visual C#. Aktualnie pracuje w General Electric pisząc oprogramowanie wykorzystywane w monitorowaniu transformatorów . Platformę .NET zna od wersji 1.1 – wcześniej wykorzystywał głównie MFC oraz C++ Builder. Interesuje się wieloma technologiami m.in. ASP.NET MVC, WPF, PRISM, WCF, WCF Data Services, WWF, Azure, Silverlight, WCF RIA Services, XNA, Entity Framework, nHibernate. Oprócz czystych technologii zajmuje się również wzorcami projektowymi, bezpieczeństwem aplikacji webowych i testowaniem oprogramowania od strony programisty. W wolnych chwilach prowadzi blog o .NET i tzw. patterns & practices.