Предыдущий ролик Следующий ролик  

Видео урок: Creating unit tests

Основы ASP.NET MVC 5

В этом видео я покажу вам, как настроить фреймворк модульного тестирования в Visual Studio и начать писать небольшие тесты для своего кода. Созданный нами в начале этого курса проект модульного теста содержит папку Controllers, внутри которой находится тестовый класс HomeController, предназначенный для тестирования действий контроллера HomeController. Если вы действительно собираетесь заняться модульным тестированием, то хорошо бы организовать код тестирования таким образом, чтобы он отражал структуру основного проекта и содержал множество различных тестовых классов. Сейчас я удалю эту папку и начну все с нуля. Просто добавлю новый тестовый класс, выделив нужный проект, нажав клавишу Ctrl+Shift+A и выбрав вариант "Базовый модульный тест" (Basic Unit Test).

Можно не менять то название, которое предлагается по умолчанию. Внутри мы видим каркас класса с одним методом. Обратите внимание на атрибуты TestClass и TestMethod, которыми отмечены класс и метод. Когда мы решим запустить наши модульные тесты, фреймворк модульного тестирования просмотрит все тестовые классы и тестовые методы проекта, отмеченные такими атрибутами. Этот тест пока ничего не делает, но и не выдает никаких исключений, поэтому выполняется успешно. В главном меню программы есть пункт "Тест", в котором предлагаются варианты запуска либо всех тестов одновременно, либо отдельных подмножеств тестов.

Можно также нажать правой кнопкой мыши внутри этого файла и выбрать пункт "Выполнить тесты" (Run Tests). Далее в Обозревателе тестов, который я передвину вот сюда, получаем список выполненных тестов. Неудачные тесты тоже будут отображаться здесь, если, конечно, таковые у нас будут. А теперь давайте напишем наш первый реальный тест. Если вы помните, то в Главе 1 для контроллера HomeController мы создавали действие Foo, которое возвращало представление About. Некоторым разработчикам нравится проверять, возвращает ли действие корректное представление.

Остальные считают это пустой тратой времени и полагают, что никогда не внесут таких изменений, которые будут способны разрушить эту простую функциональность. Но на самом деле такой тест не причинит никакого вреда и послужит хорошим примером работы с контроллером в рамках модульного теста. Я изменю имя этого метода на FooActionReturnsAboutView. По такому имени сразу будет понятно, что мы тестируем с помощью этого метода. Мы хотим, чтобы некий разработчик, которому, возможно, в дальнейшем придется сопровождать этот код, точно понял, что мы делаем. Таким образом, имена подобных методов будут выступать в качестве документации для теста и одновременно для самого основного кода.

И такие довольно длинные имена вполне нам подходят, поскольку они нисколько не помешают другому клиентскому коду. Создадим экземпляр класса HomeController, который будет моим шагом Arrange. А затем из шага Act просто вызовем метод Foo и приведем результат к ViewResult, чтобы можно было проверить свойства ViewName. Как видите, как только я ввожу "ViewResult", я попадаю в пространство имен, которого не существует. После этого я заявляю, что строка "About" совпадает со значением свойства ViewName.

Перед тем как начать тестирование, давайте добавим еще один тест. С помощью данного теста мы проверяем, что в сообщении, размещенном в ViewBag, отображается "Thanks" при каждой отправке контактной формы. Напишем аналогичный тест и вызовем метод Contact, вторую его перегрузку, которая принимает в качестве параметра сообщение, и передадим в него любую строку. Затем я хочу убедиться, что сообщение во ViewBag совпадает со строкой "Thanks". Не забудьте привести результат к типу ViewResult подобно тому, как мы делали это в первом тесте, чтобы можно было обратиться к ViewBag.

Это пример весьма конкретного теста, основная цель которого - предотвратить изменение этого сообщения в будущем. Если теперь нажать правую кнопку мыши и снова выбрать пункт "Выполнить тесты", то можно увидеть, что тест Foo завершился успешно, а тест ContactForm - неудачно. Если выбрать этот тест, то можно увидеть, почему так произошло. Потому что в этом сообщении содержится не только слово "Thanks". Может, я решу, что этот тест на самом деле немного глупый, но было бы неплохо убедиться, что во ViewBag вообще есть какое-то сообщение.

Пусть в этом тесте используется метод IsNotNull. Просто передадим в него сообщение. Можно снова запустить тест, открыв Обозреватель тестов и выбрав опцию "Выполнить неудачные тесты" (Run Failed Tests). Теперь все прошло успешно. Следует упомянуть, что свойство ViewName класса ViewResult задается только тогда, когда оно явно передается в метод View, как это делалось в этом действии. Если вам захочется выполнить точно такой же тест, например, с действием Contact, то вам придется явно передать в него ViewName, в противном случае тест выполнится неудачно.

Тесты должны быть краткими и быстрыми. В них не должны использоваться такие зависимости, как базы данных. Например, если бы я тестировал действие Deposit контроллера Transaction в его текущем состоянии, то такой тест точно назывался бы интеграционным, поскольку в этом случае я тестировал бы не только модуль, но и интеграцию этого модуля с другим компонентом. Я уже показал вам несколько простых видов модульных тестов. В следующем видео мы поговорим о том, как подделать такую зависимость, как база данных, чтобы можно было продолжить тестирование кода, не затрагивая при этом другие компоненты.