Поделиться через


Создание модульных тестов для приложений ASP.NET MVC (C#)

Стивен Уолтер

Узнайте, как создавать модульные тесты для действий контроллера. В этом руководстве Стивен Уолтер демонстрирует, как проверить, возвращает ли действие контроллера определенное представление, определенный набор данных или другой тип результата действия.

Цель этого руководства — продемонстрировать, как можно написать модульные тесты для контроллеров в приложениях MVC ASP.NET. Мы обсудим, как создать три разных типа модульных тестов. Вы узнаете, как проверить представление, возвращаемое действием контроллера, как проверить представление данных, возвращаемых действием контроллера, и как проверить, перенаправляет ли одно действие контроллера на второе действие контроллера.

Создание тестового контроллера

Начнем с создания контроллера, который мы собираемся протестировать. Контроллер с именем ProductControllerсодержится в листинге 1.

Листинг 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");
          }
     }
}

Содержит ProductController два метода действия с именами Index() и Details(). Оба метода действия возвращают представление. Обратите внимание, что Details() действие принимает параметр с именем Id.

Тестирование представления, возвращаемого контроллером

Представьте, что мы хотим проверить, возвращает ли ProductController объект правильное представление. Мы хотим убедиться, что при вызове ProductController.Details() действия возвращается представление Сведений. Тестовый класс в листинге 2 содержит модульный тест для тестирования представления, возвращаемого действием ProductController.Details() .

Листинг 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);

          }
     }
}

Класс в листинге 2 включает метод теста с именем TestDetailsView(). Этот метод содержит три строки кода. Первая строка кода создает новый экземпляр ProductController класса . Вторая строка кода вызывает метод действия контроллера Details() . Наконец, последняя строка кода проверяет, является ли представление, возвращенное действием Details() , представлением "Сведения".

Свойство ViewResult.ViewName представляет имя представления, возвращаемого контроллером. Одно большое предупреждение о тестировании этого свойства. Существует два способа возврата представления контроллером. Контроллер может явно возвращать представление следующим образом:

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

Кроме того, имя представления можно вывести из имени действия контроллера следующим образом:

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

Это действие контроллера также возвращает представление с именем Details. Однако имя представления выводится из имени действия. Если вы хотите проверить имя представления, необходимо явно вернуть имя представления из действия контроллера.

Модульный тест в листинге 2 можно запустить, введя сочетание клавиш CTRL+R, A или нажав кнопку Выполнить все тесты в решении (см. рис. 1). Если тест пройден, вы увидите окно Результаты теста на рис. 2.

Запуск всех тестов в решении

Рис. 01. Запуск всех тестов в решении (щелкните для просмотра полноразмерного изображения)

Успех!

Рис. 02. Успех! (Щелкните для просмотра полноразмерного изображения)

Тестирование данных просмотра, возвращаемых контроллером

Контроллер MVC передает данные в представление с помощью так называемого View Data. Например, представьте, что вы хотите отобразить сведения о конкретном продукте при вызове ProductController Details() действия. В этом случае можно создать экземпляр класса (определенный Product в модели) и передать экземпляр в Details представление, воспользовавшись преимуществами View Data.

Измененный ProductController в листинге 3 включает обновленное Details() действие, которое возвращает продукт.

Листинг 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);
          }
     }
}

Во-первых Details() , действие создает новый экземпляр Product класса , который представляет ноутбук. Затем экземпляр Product класса передается в качестве второго параметра методу View() .

Можно написать модульные тесты, чтобы проверить, содержатся ли ожидаемые данные в данных представления. Модульный тест в листинге 4 проверяет, возвращается ли продукт, представляющий ноутбук, при вызове ProductController Details() метода действия.

Листинг 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);
          }
     }
}

В листинге TestDetailsView() 4 метод проверяет возвращаемые данные просмотра путем Details() вызова метода . предоставляется ViewData в качестве свойства для возвращаемого ViewResult путем вызова Details() метода . Свойство ViewData.Model содержит продукт, переданный в представление. Тест просто проверяет, что продукт, содержащийся в представлении данных, имеет имя Laptop.

Проверка результата действия, возвращаемого контроллером

Более сложное действие контроллера может возвращать различные типы результатов действий в зависимости от значений параметров, переданных действию контроллера. Действие контроллера может возвращать различные типы результатов действий, включая ViewResult, RedirectToRouteResultили JsonResult.

Например, измененное Details() действие в листинге 5 возвращает Details представление при передаче допустимого идентификатора продукта действию. Если вы передаете недопустимый идентификатор продукта ( идентификатор со значением меньше 1), вы будете перенаправлены на Index() действие.

Листинг 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);

          }
     }
}

Поведение действия можно проверить Details() с помощью модульного теста в листинге 6. Модульный тест, приведенный в листинге 6, проверяет, перенаправляет Index ли вы в представление, когда в метод передается идентификатор со значением Details() -1.

Листинг 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"]);

          }
     }
}

При вызове метода в действии RedirectToAction() контроллера действие контроллера RedirectToRouteResultвозвращает . Тест проверяет, будет ли RedirectToRouteResult перенаправлять пользователя на действие контроллера с именем Index.

Итоги

В этом руководстве вы узнали, как создавать модульные тесты для действий контроллера MVC. Сначала вы узнали, как проверить, возвращается ли правильное представление действием контроллера. Вы узнали ViewResult.ViewName , как использовать свойство для проверки имени представления.

Далее мы рассмотрели, как можно проверить содержимое View Data. Вы узнали, как проверка, возвращается View Data ли нужный продукт после вызова действия контроллера.

Наконец, мы рассмотрели, как проверить, возвращаются ли различные типы результатов действия из действия контроллера. Вы узнали, как проверить, возвращает ViewResult ли контроллер или RedirectToRouteResult.