Фреймворк Moq

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core

Последнее обновление: 31.10.2015

Кроме собственно фреймворков для создания и проведения юнит-тестов при тестировании часто бывают полезны такие фреймворки, которые позволяют имитировать или эмулировать какую-то функциональность или создавать мок-объекты. Подобных фреймворков существует множество, и одним из самых популярных является Moq.

Итак, возьмем проект из прошлой темы и подключим Moq через NuGet в проект тестов (а не в проект веб-приложения):

Moq фреймворк в ASP.NET MVC 5

После этого в узел 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 будут совпадать.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850