Tworzenie testów jednostkowych dla aplikacji ASP.NET MVC (C#)

Autor: Stephen Walther

Dowiedz się, jak tworzyć testy jednostkowe dla akcji kontrolera. W tym samouczku Stephen Walther pokazuje, jak sprawdzić, czy akcja kontrolera zwraca określony widok, zwraca określony zestaw danych lub zwraca inny typ wyniku akcji.

Celem tego samouczka jest zademonstrowanie sposobu pisania testów jednostkowych dla kontrolerów w aplikacjach MVC ASP.NET. Omawiamy sposób tworzenia trzech różnych typów testów jednostkowych. Dowiesz się, jak przetestować widok zwrócony przez akcję kontrolera, jak przetestować dane widoku zwrócone przez akcję kontrolera oraz sprawdzić, czy jedna akcja kontrolera przekierowuje cię do drugiej akcji kontrolera.

Tworzenie kontrolera w ramach testu

Zacznijmy od utworzenia kontrolera, który zamierzamy przetestować. Kontroler o nazwie ProductControllerznajduje się na liście 1.

Lista 1 — ProductController.cs

using System;
using System.Web.Mvc;

namespace Store.Controllers
{
     public class ProductController : Controller
     {
          public ActionResult Index()
          {
               // Add action logic here
               throw new NotImplementedException();
          }

          public ActionResult Details(int Id)
          {

               return View("Details");
          }
     }
}

Zawiera ProductController dwie metody akcji o nazwach Index() i Details(). Obie metody akcji zwracają widok. Zwróć uwagę, że Details() akcja akceptuje parametr o nazwie Id.

Testowanie widoku zwróconego przez kontroler

Załóżmy, że chcemy sprawdzić, czy ProductController obiekt zwraca właściwy widok. Chcemy upewnić się, że po ProductController.Details() wywołaniu akcji zwracany jest widok Szczegóły. Klasa testowa na liście 2 zawiera test jednostkowy do testowania widoku zwróconego ProductController.Details() przez akcję.

Lista 2 — ProductControllerTest.cs

using System.Web.Mvc;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Store.Controllers;

namespace StoreTests.Controllers
{
     [TestClass]
     public class ProductControllerTest
     {
          [TestMethod]
          public void TestDetailsView()
          {
               var controller = new ProductController();
               var result = controller.Details(2) as ViewResult;
               Assert.AreEqual("Details", result.ViewName);

          }
     }
}

Klasa w liście 2 zawiera metodę testową o nazwie TestDetailsView(). Ta metoda zawiera trzy wiersze kodu. Pierwszy wiersz kodu tworzy nowe wystąpienie ProductController klasy . Drugi wiersz kodu wywołuje metodę akcji kontrolera Details() . Na koniec ostatni wiersz kodu sprawdza, czy widok zwrócony przez Details() akcję to widok Szczegóły.

Właściwość ViewResult.ViewName reprezentuje nazwę widoku zwróconego przez kontroler. Jedno duże ostrzeżenie dotyczące testowania tej właściwości. Istnieją dwa sposoby zwracania widoku przez kontroler. Kontroler może jawnie zwrócić widok podobny do następującego:

public ActionResult Details(int Id)
{
     return View("Details");
}

Alternatywnie nazwę widoku można wywnioskować z nazwy akcji kontrolera w następujący sposób:

public ActionResult Details(int Id)
{
     return View();
}

Ta akcja kontrolera zwraca również widok o nazwie Details. Jednak nazwa widoku jest wywnioskowana z nazwy akcji. Jeśli chcesz przetestować nazwę widoku, musisz jawnie zwrócić nazwę widoku z akcji kontrolera.

Test jednostkowy można uruchomić na liście 2, wprowadzając kombinację klawiatury Ctrl-R, A lub klikając przycisk Uruchom wszystkie testy w rozwiązaniu (zobacz Rysunek 1). Jeśli test zakończy się pomyślnie, zostanie wyświetlone okno Wyniki testu na rysunku 2.

Uruchamianie wszystkich testów w rozwiązaniu

Rysunek 01. Uruchamianie wszystkich testów w rozwiązaniu (kliknij, aby wyświetlić obraz pełnowymiarowy)

Sukces!

Rysunek 02. Sukces! (Kliknij, aby wyświetlić obraz w pełnym rozmiarze)

Testowanie danych widoku zwróconych przez kontroler

Kontroler MVC przekazuje dane do widoku przy użyciu elementu o nazwie View Data. Załóżmy na przykład, że chcesz wyświetlić szczegóły określonego produktu podczas wywoływania ProductController Details() akcji. W takim przypadku możesz utworzyć wystąpienie Product klasy (zdefiniowanej w modelu) i przekazać wystąpienie do Details widoku, korzystając z View Datafunkcji .

ProductController Zmodyfikowany element w liście 3 zawiera zaktualizowaną Details() akcję zwracającą produkt.

Lista 3 — ProductController.cs

using System;
using System.Web.Mvc;

namespace Store.Controllers
{
     public class ProductController : Controller
     {
          public ActionResult Index()
          {
               // Add action logic here
               throw new NotImplementedException();
          }

          public ActionResult Details(int Id)
          {
               var product = new Product(Id, "Laptop");
               return View("Details", product);
          }
     }
}

Najpierw akcja Details() tworzy nowe wystąpienie Product klasy reprezentującej komputer przenośny. Następnie wystąpienie Product klasy jest przekazywane jako drugi parametr do View() metody .

Możesz napisać testy jednostkowe, aby sprawdzić, czy oczekiwane dane są zawarte w danych widoku. Test jednostkowy w liście 4 sprawdza, czy podczas wywoływania ProductController Details() metody akcji jest zwracany produkt reprezentujący komputer przenośny.

Lista 4 — ProductControllerTest.cs

using System.Web.Mvc;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Store.Controllers;

namespace StoreTests.Controllers
{
     [TestClass]
     public class ProductControllerTest
     {

          [TestMethod]
          public void TestDetailsViewData()
          {
               var controller = new ProductController();
               var result = controller.Details(2) as ViewResult;
               var product = (Product) result.ViewData.Model;
               Assert.AreEqual("Laptop", product.Name);
          }
     }
}

Na liście 4 TestDetailsView() metoda testuje dane widoku zwrócone przez wywołanie Details() metody . Właściwość ViewData jest uwidoczniona jako właściwość zwrócona ViewResult przez wywołanie Details() metody . Właściwość ViewData.Model zawiera produkt przekazany do widoku. Test sprawdza po prostu, czy produkt zawarty w danych widoku ma nazwę Laptop.

Testowanie wyniku akcji zwróconego przez kontroler

Bardziej złożona akcja kontrolera może zwracać różne typy wyników akcji w zależności od wartości parametrów przekazanych do akcji kontrolera. Akcja kontrolera może zwracać różne typy wyników akcji, w tym ViewResult, RedirectToRouteResultlub JsonResult.

Na przykład zmodyfikowana Details() akcja w pozycji Lista 5 zwraca Details widok po przekazaniu prawidłowego identyfikatora produktu do akcji. Jeśli przekażesz nieprawidłowy identyfikator produktu — identyfikator o wartości mniejszej niż 1 — nastąpi przekierowanie do Index() akcji.

Lista 5 — ProductController.cs

using System;
using System.Web.Mvc;
namespace Store.Controllers
{
     public class ProductController : Controller
     {
          public ActionResult Index()
          {
               // Add action logic here
               throw new NotImplementedException();
          }
          public ActionResult Details(int Id)
          {
               if (Id < 1)
                    return RedirectToAction("Index");
               var product = new Product(Id, "Laptop");
               return View("Details", product);

          }
     }
}

Działanie akcji można przetestować Details() za pomocą testu jednostkowego na liście 6. Test jednostkowy z listy 6 sprawdza, czy nastąpi przekierowanie do Index widoku, gdy identyfikator o wartości -1 zostanie przekazany do Details() metody .

Lista 6 — ProductControllerTest.cs

using System.Web.Mvc;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Store.Controllers;
namespace StoreTests.Controllers
{
     [TestClass]
     public class ProductControllerTest
     {
          [TestMethod]
          public void TestDetailsRedirect()
          {
               var controller = new ProductController();
               var result = (RedirectToRouteResult) controller.Details(-1);
               Assert.AreEqual("Index", result.Values["action"]);

          }
     }
}

Po wywołaniu RedirectToAction() metody w akcji kontrolera akcja kontrolera zwraca RedirectToRouteResultwartość . Test sprawdza, czy RedirectToRouteResult użytkownik przekierowuje użytkownika do akcji kontrolera o nazwie Index.

Podsumowanie

W tym samouczku przedstawiono sposób tworzenia testów jednostkowych dla akcji kontrolera MVC. Najpierw pokazano, jak sprawdzić, czy właściwy widok jest zwracany przez akcję kontrolera. Pokazano, jak używać ViewResult.ViewName właściwości do weryfikowania nazwy widoku.

Następnie sprawdziliśmy, jak można przetestować zawartość elementu View Data. Wiesz już, jak sprawdzić, czy właściwy produkt został zwrócony View Data po wywołaniu akcji kontrolera.

Na koniec omówiliśmy sposób testowania, czy różne typy wyników akcji są zwracane z akcji kontrolera. Pokazano, jak sprawdzić, czy kontroler zwraca ViewResult obiekt , czy RedirectToRouteResult.