Статьи

Модульное тестирование лаконично: Visual Studio

Это отрывок из электронной книги «Единичное тестирование » Марка Клифтона, любезно предоставленный Syncfusion.

Модульный тест состоит из двух вещей:

  • Класс, представляющий тестовое устройство.
  • Методы в классе, представляющие юнит-тесты.

Visual Studio автоматически создаст заглушку для тестового проекта, с которого мы и начнем.

Модульные тесты обычно размещаются в отдельном проекте (в результате получается отдельная сборка) из кода вашего приложения. В Visual Studio 2008 или 2012 вы можете создать проект модульного теста, щелкнув правой кнопкой мыши решение и выбрав Add, а затем New Project из всплывающего меню:

Добавление нового проекта
Добавление нового проекта

В открывшемся диалоговом окне выберите тестовый проект:

VS2008 Новый тестовый проект
VS2008 Новый тестовый проект
VS2012 Новый тестовый проект
VS2012 Новый тестовый проект

Visual Studio 2008 создаст файл-заглушку «UnitTest1.cs» (если вы выбрали язык C #) с множеством полезных комментариев в заглушке. Visual Studio 2012 создает гораздо более сложную заглушку:

Visual Studio 2008 также создаст класс TestContext — его больше нет в VS2012, и мы его игнорируем, — вместо этого используйте предыдущий заглушку из VS2012.

Также удалите файл «ManualTest1.mht», в противном случае вам будет предложено выбрать результаты теста и ввести примечания к тесту вручную.

Обратите внимание, что класс украшен атрибутом TestClass. Это определяет тестовое устройство — набор тестовых методов.

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


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

  • AreEqual / AreNotEqual
  • AreSame / AreNotSame
  • IsTrue / IsFalse
  • IsNull / IsNotNull
  • IsInstanceOfType / IsNotInstanceOfType

Многие из этих утверждений перегружены, и рекомендуется ознакомиться с полной документацией, которую предоставляет Microsoft.

Обратите внимание, что в следующих примерах используется VS2008.

Утверждения являются основой каждого теста. В отношении результатов теста можно сделать множество утверждений. Для начала напишем простое утверждение, в котором говорится «один равен одному», другими словами, трюизм:

Запустите тест, который должен привести к «Пройдено»:

Простое утверждение
Простое утверждение

Методы AreEqual и AreNotEqual сравнивают:

  • объекты
  • двойники
  • одиночный разряд
  • строки
  • типизированные данные

Они принимают форму сравнения ожидаемого (первый параметр) с фактическим (второй параметр) значением. Что касается одинарных и двойных значений, то можно указать «с определенной точностью». Наконец, все перегрузки имеют возможность отображать сообщение (необязательно отформатированное), если утверждение не выполнено.

Что касается равенства объектов, этот метод сравнивает, идентичны ли экземпляры:

Предыдущий тест проходит, так как object1 и object2 не равны. Однако если класс переопределяет метод Equals, тогда равенство основывается на сравнении, выполненном методом Equals, реализованным в классе. Например:

Эти два метода проверяют, совпадают ли экземпляры (или нет). Например:

Несмотря на то, что класс AnObject переопределяет оператор Equals, предыдущий тест проходит, поскольку экземпляры двух объектов не совпадают.

Эти два метода позволяют вам проверить истинность сравнения значений. С точки зрения читабельности методы IsTrue и IsFalse обычно используются для сравнения значений , тогда как AreEqual и AreSame обычно используются для сравнения экземпляров (объектов).

Например:

Это подтверждает это значение свойства.

Эти два теста проверяют, является ли объект нулевым или нет:

Эти два метода проверяют, является ли объект экземпляром определенного типа (или нет). Например:

Метод Assert.Inconclusive можно использовать, чтобы указать, что ни тест, ни функциональность, стоящая за тестом, еще не реализованы, и поэтому тест не является окончательным.

Что касается модульного тестирования Visual Studio, то при сбое утверждения метод Assert создает исключение AssertFailedException. Это исключение никогда не должно обрабатываться вашим тестовым кодом.


Есть два других класса утверждений:

  • CollectionAssert
  • StringAssert

Как видно из их названий, эти утверждения работают с коллекциями и строками соответственно.

Эти методы реализованы в классе Microsoft.VisualStudio.TestTools.UnitTesting.CollectionAssert. Обратите внимание, что параметр коллекции в этих методах предполагает, что коллекция будет реализовывать ICollection (в отличие от NUnit, который ожидает IEnumerable).

Это утверждение проверяет, что объекты в коллекции имеют один и тот же тип, который включает в себя производные типы ожидаемого типа, как показано здесь:

Это утверждение проверяет, что объекты в коллекции не являются нулевыми.

Этот тест гарантирует, что объекты в коллекции являются уникальными. Если сравнивать структуры:

структуры сравниваются по значению, а не по экземпляру — предыдущий тест не проходит. Однако, даже если класс переопределяет метод Equals:

этот тест проходит:

Эти тесты утверждают, что две коллекции равны. Методы включают в себя перегрузки, которые позволяют предоставить метод сравнения. Если объект переопределяет метод Equals, этот метод будет использоваться для определения равенства. Например:

Эти две коллекции равны, потому что класс AnObject переопределяет метод Equals (см. Предыдущий пример).

Обратите внимание, что для передачи утверждения списки должны иметь одинаковую длину и считаться не равными, если списки идентичны, за исключением другого порядка. Сравните это с утверждением AreEquivalent, описанным ниже.

Это утверждение сравнивает два списка и считает списки равных элементов эквивалентными независимо от порядка. К сожалению, в реализации есть ошибка, так как этот тест не пройден:

Визуальные Студии - Эквивалентная Ошибка
Ошибка Visual Studio в AreEquivalent

с сообщением об ошибке:

Принимая во внимание, что реализация NUnit этого утверждения проходит:

NUnits AreEvivalent работает правильно
AreUquivalent NUnit работает правильно

Это утверждение проверяет, что объект содержится в коллекции:

используя метод Equals (если он переопределен) для выполнения теста на равенство.

Это утверждение проверяет, что первый параметр (подмножество) содержится в коллекции второго параметра (надмножество).

Обратите внимание, что тест подмножества не проверяет порядок или последовательность — он просто проверяет, содержатся ли элементы в списке подмножеств в надмножестве.

Эти методы реализованы в классе Microsoft.VisualStudio.TestTools.UnitTesting.StringAssert:

  • Содержит
  • Матчи / DoesNotMatch
  • StartsWith / EndsWith

Это обсуждается далее.

Метод Contains утверждает, что подмножество (обратите внимание, что это второй параметр) содержится в строке (первый параметр). Например, этот тест проходит:

Этот метод утверждает, что строка (первый параметр) соответствует шаблону регулярного выражения, предоставленному во втором параметре.

Этот метод утверждает, что строка (первый параметр) либо начинается, либо заканчивается другой строкой (второй параметр).


Исключения могут быть проверены без написания блоков try-catch вокруг метода test. Например, пока вы могли бы написать это:

Намного удобнее использовать атрибут ExpectedException в тестовом методе:


Существуют некоторые дополнительные атрибуты, которые полезны для запуска набора тестов, а также отдельных тестов, которые улучшают возможность повторного использования и читаемость базы кода модульных тестов.

Модуль модульного тестирования Visual Studio предоставляет четыре дополнительных атрибута метода:

  • ClassInitialize
  • ClassCleanup
  • TestInitialize
  • TestCleanup

Эти атрибуты предшествуют и следуют за выполнением всех тестов в приборе (классе), а также до и после каждого теста в приборе.

Обратите внимание, что методы, украшенные этим атрибутом, должны быть статическими.

Если метод украшен этим атрибутом, код в методе выполняется до запуска всех тестов в приборе. Обратите внимание, что этот метод требует параметр TestContext.

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

Метод, украшенный этим атрибутом, отвечает за освобождение ресурсов, закрытие соединений и т. Д., Которые были созданы во время инициализации класса. Этот метод всегда будет выполняться после запуска тестов внутри прибора, независимо от того, успешны они или нет.

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

В дополнение к атрибуту TestInitialize методы, украшенные TestCleanup, будут выполняться при завершении каждого теста.

Следующий код демонстрирует последовательность настройки и демонтажа прибора по отношению к фактическим тестам:

Запуск этого устройства приводит к следующей трассировке выходных данных отладки:

Как показано в предыдущем примере, прибор инициализируется — затем для каждого теста выполняется настройка теста и код разрыва, после чего в конце завершается разбор прибора.


В следующем разделе описаны менее часто используемые атрибуты.

Методы, украшенные этим атрибутом, должны быть статическими и выполняться при загрузке сборки. Возникает вопрос: что если в сборке имеется более одного тестового устройства?

Если вы попробуете это, тестовый механизм не сможет запустить какие-либо модульные тесты, сообщив:

«UTA013: UnitTestExamplesVS2008.Fixture2: невозможно определить более одного метода с атрибутом AssemblyInitialize внутри сборки».

Поэтому для сборки может существовать только один метод AssemblyInitialize и один метод AssemblyCleanup, независимо от количества тестовых приборов в этой сборке. Поэтому рекомендуется, чтобы никакие фактические тесты не помещались в класс, который определяет эти методы:

в результате получается следующая последовательность выполнения:

Обратите внимание на дополнительные вызовы инициализации и очистки сборки.

Этот метод может украшать определенные методы или целые приборы.

Если этот атрибут украшает метод теста:

тест не запустится. К сожалению, панель результатов теста Visual Studio не указывает на то, что в настоящее время игнорируются тесты:

Игнорируемые тесты не отображаются
Игнорируемые тесты не отображаются

Сравните это с NUnit, который ясно показывает проигнорированные тесты:

NUnit показывает игнорируемые тесты
NUnit показывает игнорируемые тесты

Дисплей NUnit помечает все тестовое дерево как «неизвестное», если один или несколько методов теста помечены как «Игнорировать»

Методы всего прибора могут быть проигнорированы с помощью атрибута Ignore на уровне класса:

Если вы добавите атрибут Ignore в метод, вы можете заметить, что Visual Studio все еще выполняет тест. Необходимо очистить кэш теста для Visual Studio, чтобы получить изменения. Один из способов сделать это — очистить решение и восстановить его.

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

Если модульные тесты выполняются в отдельной папке развертывания, этот атрибут можно использовать для указания файлов, которые требуются классу теста или методу теста для запуска. Вы можете указать файлы или папки для копирования в папку развертывания и при желании указать целевой путь относительно папки развертывания.

Используемый для отчетности, этот атрибут предоставляет описание метода теста. Как ни странно, этот атрибут доступен только в тестовых методах и недоступен в тестовых классах.

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

Этот атрибут не используется механизмом тестирования, но может быть использован, путем отражения, вашим собственным тестовым кодом. Полезность этого атрибута сомнительна.

Если вы используете Team Foundation Server (TFS), вы можете использовать этот атрибут в методе тестирования, чтобы указать идентификатор рабочего элемента, назначенный TFS для конкретного модульного теста.

Эти два атрибута используются во взаимосвязи с TeamBuild и TestManagementService и позволяют вам указать итерацию проекта, которой соответствует метод теста.


Модуль модульного тестирования Microsoft поддерживает CSV, XML или источники данных базы данных для параметризованного тестирования. Это не совсем верно параметризованное тестирование (см., Как NUnit реализует параметризованное тестирование), потому что параметры не передаются методу модульного теста, а должны быть извлечены из источника данных и переданы тестируемому методу. Однако возможность загрузки тестовых данных в DataTable из различных источников полезна для автоматизации тестирования вождения.

Текстовый файл с разделителями-запятыми может использоваться для источника данных:

и используется в методе испытаний:

Это приводит к следующему выводу:

Обратите внимание, что в окне результатов теста не отображаются параметры запуска (в отличие от NUnit):

Параметризованные результаты испытаний
Параметризованные результаты испытаний

Однако есть очевидные преимущества не отображать каждую тестовую комбинацию, особенно для больших наборов данных.

Имеется файл XML, такой как:

1
2
3
4
5
<Data>
    <Row Numerator = «10» Denominator = «5» ExpectedResult = «2»/>
    <Row Numerator = «20» Denominator = «5» ExpectedResult = «4»/>
    <Row Numerator = «33» Denominator = «3» ExpectedResult = «11»/>
</Data>

Пример использования источника данных XML для модульного теста:

Обратите внимание, что кроме параметров атрибута источника данных, тестовый код такой же.

Таблица базы данных также может быть использована в качестве источника данных. Учитывая таблицу, такую ​​как:

Таблица базы данных как источник данных
Таблица базы данных как источник данных

и данные:

Данные теста базы данных
Данные теста базы данных

Пример теста с использованием этих данных выглядит следующим образом:

Опять же, обратите внимание, что сам код тестового метода одинаков — единственное, что мы здесь сделали, изменили определение источника данных.

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

Кроме того, код, описанный в блоге Крейга Андеры , для использования атрибута TestProperty для параметризации процесса инициализации теста не влияет на коллекцию TestContext.Properties в Visual Studio 2008 или Visual Studio 2012.