Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core
Кроме собственно фреймворков для создания и проведения юнит-тестов при тестировании часто бывают полезны такие фреймворки, которые позволяют имитировать или эмулировать какую-то функциональность или создавать мок-объекты. Подобных фреймворков существует множество, и одним из самых популярных является Moq.
Итак, возьмем проект из прошлой темы и подключим Moq через NuGet в проект тестов (а не в проект веб-приложения):
После этого в узел References проекта тестов будет добавлена библиотека Moq, содержащая всю основную функциональность.
Теперь изменим класс тестов следующим образом:
using Moq; ................. [TestClass] public class HomeControllerTest { [TestMethod] public void IndexViewModelNotNull() { // Arrange var mock = new Mock<IRepository>(); mock.Setup(a => a.GetComputerList()).Returns(new List<Computer>()); HomeController controller = new HomeController(mock.Object); // Act ViewResult result = controller.Index() as ViewResult; // Assert Assert.IsNotNull(result.Model); } }
Для доступа к функциональности Moq вначале подключается соответствующее пространство имен using Moq;
.
Moq предназначен для имитации объектов. В данном случае имитируется функциональность репозитория. Для этого объект Mock типизируется
соответствующим типом: var mock = new Mock<IRepository>()
Затем выполняется настройка mock объекта с помощью метода Setup
. Так как нам надо имитировать возвращение методом GetComputerList()
набора объектов, то данный метод вызывается в методе Setup, а с помощью метода Returns
определяем данный набор объектов.
Поскольку контроллер HomeController теперь в конструкторе принимает объект репозитория, то мы можем передать в конструктор мок-объект, который имитирует функциональность
репозитория: HomeController controller = new HomeController(mock.Object)
Теперь запустим тест. Он должен завершиться неудачей, так как у нас не передается в методе Index в представление никакой модели. Поэтому изменим метод Index:
public ActionResult Index() { var model = repo.GetComputerList(); return View(model); }
И если мы сейчас запустим тест, то он пройдет успешно.
Теперь для примера добавим в класс тестов еще один метод:
[TestMethod] public void IndexViewBagMessage() { // Arrange var mock = new Mock<IRepository>(); mock.Setup(a => a.GetComputerList()).Returns(new List<Computer>() { new Computer()}); HomeController controller = new HomeController(mock.Object); string expected = "В базе данных 1 объект"; // Act ViewResult result = controller.Index() as ViewResult; string actual = result.ViewBag.Message as string; // Assert Assert.AreEqual(expected, actual); }
Цель данного метода - проверить сообщение, передаваемое через ViewBag. Причем я хочу, чтобы сообщение передавалось, если
в базе данных больше 0 объектов. Для этого список, возвращаемый методом GetComputerList()
, инициализируется одним объектом. А
метод Assert.AreEqual
проверяет оба сообщения.
Запустим тест и увидим, что он завершился неудачей. Теперь нам надо изменить метод Index в главном проекте, чтобы он соответствовал тесту:
public ActionResult Index() { var model = repo.GetComputerList(); if (model.Count > 0) ViewBag.Message = String.Format("В базе данных {0} объект", model.Count); return View(model); }
Поскольку с помощью Moq мы имитировали в методе контроллера список с одним элементом, то если мы сейчас запустим тест, то он пройдет успешно, так как строка в тесте и значение ViewBag.Message будут совпадать.