При создании тестов часто возникает необходимость выполнить определенные действия до или после запуска теста или их группы. Например, для подготовки и освобождения ресурсов, создания дополнительных файлов с данными и т. д. MSTest V2 позволяет при помощи атрибутов указать методы, которые будут запущенны в нужные моменты времени. |
До и после тестов сборки
Атрибут [AssemblyInitialize] используется чтобы отметить метод, который будет выполнен один раз до запуска любых тестов из сборки в которой он расположен. Его имя может быть любым, но сигнатура обязательно должна строго соответствовать следующему виду:
[AssemblyInitialize]
public static [void / async Task] ИмяМетода(TestContext context) { … }
Параметр типа TestContext предоставляет информацию о запускаемых тестах. В данном случае, актуальной будет информация об используемых директориях: откуда тесты были запущенны, где будут сохранены результаты.
Существуют следующие правила использования [AssemblyInitialize]:
- В сборке может существовать только один метод, отмеченный данным атрибутом.
- Класс, содержащий такой метод, должен быть отмечен атрибутом [TestClass].
- Если отмеченный метод завершится выбросом исключения, то все тесты из данной сборки запущены не будут и автоматически будут считаться проваленными.
Второй атрибут, [AssemblyCleanup], позволяет указать метод, который будет запущен после того, как были выполнены все тесты из соответствующей сборки. Его сигнатура немного отличается:
[AssemblyCleanup]
public static [void / async Task] ИмяМетода() { … }
При этом также есть правила:
- Только один метод в сборке может быть отмечен атрибутом [AssemblyCleanup].
- Класс, содержащий такой метод, должен быть отмечен атрибутом [TestClass].
- Если отмеченный метод завершится выбросом исключения, то это не повлияет на результаты тестов.
До и после тестов класса
Предыдущие два атрибута указывали методы для всей сборки. Следующие два, [ClassInitialize] и [ClassCleanup], используются для указания методов, которые будут выполнены, соответственно, до и после тестов класса, в котором они использованы.
Требуемые сигнатуры аналогичны рассмотренным выше:
[ClassInitialize]
public static [void / async Task] ИмяМетода(TestContext context) { … }
[ClassCleanup]
public static [void / async Task] ИмяМетода() { … }
Но есть и отличия:
Во-первых, у [ClassInitialize] и [ClassCleanup] есть параметр типа InheritanceBehavior. С его помощью можно контролировать поведение отмеченного метода при запуске тестов в классах-наследниках:
- InheritanceBehavior.None (поведение по умолчанию) – метод будет выполняться только для класса, где он был определен .
- InheritanceBehavior.BeforeEachDerivedClass – метод будет выполняться также для каждого класса-наследника. Обратите внимание, параметр типа TestContext, рассмотренный выше, содержит имя текущего класса с тестами.
Во-вторых, можно управлять моментом запуска метода, отмеченного [ClassCleanup]. Для этого у него необходимо указать параметр типа ClassCleanupBehavior:
- ClassCleanupBehavior.EndOfAssembly (по умолчанию) – после завершения всех тестов в сборке.
- ClassCleanupBehavior.EndOfClass – после завершения всех тестов в классе.
Поведение ClassCleanupBehavior по умолчанию можно переопределить для всей сборки, используя атрибут [ClassCleanupExecution]:
[assembly: ClassCleanupExecution(ClassCleanupBehavior.EndOfClass)]
Конструктор класса
Конструктор класса можно использовать как альтернативу [ClassInitialize]. Однако, при использовании атрибута есть преимущества. Он:
- Получает контекст тестов в виде параметра типа TestContext.
- Может возвращать Task, т.е. быть асинхронным.
- Можно отключить вызов метода у наследников, передав InheritanceBehavior.None в атрибут.
- Вызывается только один раз для всех тестов данного класса независимо от того, сколько раз создается тестовый класс (здесь аналогом будет статический конструктор).
После каждого теста
Последний способ, который стоит отметить, позволяет запускать заданный код после каждого теста в классе. Для этого достаточно реализовать интерфейс IDisposable, разместив нужный код в методе Dispose(…).