Создание юнит-тестов

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

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

Возьмем тот же проект из прошлый темы (либо создадим новый) и изменим в главном проекте код контроллера HomeController:

using Microsoft.AspNetCore.Mvc;

namespace UnitTestApp.Controllers
{
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            ViewData["Message"] = "Hello!";
            return View("Index");
        }
    }
}

Контроллер имеет только один метод, который устанавливает значение ViewData["Message"] и генерирует объект ViewResult, который использует представление Index. Теперь протестируем этот метод.

Для этого в проект тестов добавим новый класс, который назовем HomeControllerTests:

using Microsoft.AspNetCore.Mvc;
using UnitTestApp.Controllers;
using Xunit;

namespace UnitTestApp.Tests
{
    public class HomeControllerTests
    {
        [Fact]
        public void IndexViewDataMessage()
        {
            // Arrange
            HomeController controller = new HomeController();

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

            // Assert
            Assert.Equal("Hello world!", result?.ViewData["Message"]);
        }

        [Fact]
        public void IndexViewResultNotNull()
        {
            // Arrange
            HomeController controller = new HomeController();
            // Act
            ViewResult result = controller.Index() as ViewResult;
            // Assert
            Assert.NotNull(result);
        }

        [Fact]
        public void IndexViewNameEqualIndex()
        {
            // Arrange
            HomeController controller = new HomeController();
            // Act
            ViewResult result = controller.Index() as ViewResult;
            // Assert
            Assert.Equal("Index", result?.ViewName);
        }
    }
}

Этот простейший стандартный тест, который призван дать начальное понимание работы тестов.

Метод IndexViewResultNotNull тестирует результат метода - возвращаемый объект ViewResult не должен иметь значение null. Метод IndexViewNameEqualIndex проверяет название вызываемого представления с помощью вызова Assert.Equal. А метод IndexViewDataMessage проверяет значение по ключу "Message" в словаре ViewData.

Проект юнит-тестов в ASP.NET Core

Тесты в xUnit определяются в виде методов, к которым применяются атрибуты Fact и Theory. Атрибут Fact указывает, что методы представляет тест.

Каждый метод содержит три логических части - Arrange, Act и Assert. Они помечены соответствующими комментариями. Вкратце рассмотрим, что они делают.

Секция Arrange выполняет начальную инициализацию контекста тестов, а именно создает объект контроллера: HomeController controller = new HomeController().

Далее в секции Act выполняет само действие, которое надо протестировать, а именно генерация представления: ViewResult result = controller.Index() as ViewResult. Так как метод Index контроллера возвращает объект ActionResult, то его еще надо привести к объекту ViewResult.

Чтобы проверить результат текста в секции Assert вызывается один из методов класса Assert.

Модель тестов Arrange-Act-Assert представляет целую парадигму тестирования, которая используется многими фреймворками юнит-тестов:

  • Arrange: устанавливает начальные условия для выполнения теста

  • Act: выполняет тест (обычно представляет одну строку кода)

  • Assert: верифицирует результат теста

Секции Arrange и Act представляют обычный код на языке C#. А секция Assert использует одноименный класс Assert, который определен в библиотеке xUnit.net.

Для проверки результата в классе Assert определено ряд методов, среди которых можно выделить следующие:

  • All(collection, action): метод подтверждает, что все элементы коллекции collection соответствуют действию action

  • Contains(expectedSubString, actualString): метод подтверждает, что строка actualString содержит expectedSubString

  • DoesNotContain(expectedSubString, actualString): метод подтверждает, что строка actualString не содержит строку expectedSubString

  • DoesNotMatch(expectedRegexPattern, actualString): метод подтверждает, что строка actualString не соответствует регулярному выражению expectedRegexPattern

  • Matches(expectedRegexPattern, actualString): метод подтверждает, что строка actualString соответствует регулярному выражению expectedRegexPattern

  • Equal(expected, result): метод сравнивает результат теста в виде значения result и ожидаемое значение expected и подтверждает их равенство

  • NotEqual(expected, result): метод сравнивает результат теста в виде значения result и ожидаемое значение expected и подтверждает их неравенство

  • Empty(collection): метод подтверждает, что коллекция collection пустая

  • NotEmpty(collection): метод подтверждает, что коллекция collection не пустая

  • True(result): метод подтверждает, что результат теста равен true

  • False(result): метод подтверждает, что результат теста равен false

  • IsType(expected, result): метод подтверждает, что результат теста имеет тип expected

  • IsNotType(expected, result): метод подтверждает, что результат теста не представляет тип expected

  • IsNull(result): метод подтверждает, что результат теста имеет значение null

  • IsNotNull(result): метод подтверждает, что результат теста не равен null

  • InRange(result, low, high): метод подтверждает, что результат теста находится в диапазоне между low и high

  • NotInRange(result, low, high): метод подтверждает, что результат теста не принадлежит диапазону от low до high

  • Same(expected, actual): метод подтверждает, что ссылки expected и actual указывают на один и тот же объект в памяти

  • NotSame(expected, actual): метод подтверждает, что ссылки expected и actual указывают на разные объекты в памяти

  • Throws(exception, expression): метод подтверждает, что выражение expression генерирует исключение exception

Теперь запустим тест на выполнение через меню Test->Run All Tests:

Запуск юнит-тестов в ASP.NET Core

После этого откроется окно Test Explorer или обозреватель тестов. Если все нормально, то обозреватель тестов сигнализирует нам зеленым цветом, что все тесты успешно пройдены. Если же нет, то не пройденные тесты будут отмечены красным цветом.

В данном случае после запуска тестов мы увидим, что один тест - IndexViewDataMessage не пройден. Потому что мы ожидаем, что ViewData["Message"] будет иметь значение "Hello world!". Однако в методе Index контроллера HomeController передается совсем другое значение: ViewData["Message"] = "Hello!". То есть имеющаяся логика не соответствует нашим ожиданиям, и в нем имеется ошибка. Теперь изменим код метода Index:

public class HomeController : Controller
{
    public IActionResult Index()
    {
        ViewData["Message"] = "Hello world!";
        return View("Index");
    }
}

И заново запустим тесты:

Unit test in ASP.NET Core MVC

Теперь все тесты пройдены.

В принципе необязательно было бы разделять все ключевые действия по разным методам. Можно было бы объединить все тесты в один:

[Fact]
public void IndexTest()
{
    // Arrange
    HomeController controller = new HomeController();

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

    // Assert
    Assert.Equal("Hello world!", result?.ViewData["Message"]);
    Assert.NotNull(result);
    Assert.Equal("Index", result?.ViewName);
}

В этом случае тест был пройден, если подтверждены все используемые выражения Assert.

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