Вопрос или проблема
У меня есть тестовый класс с TestFixtureSource с двумя значениями: “Unit” и “Integration”. Эти значения представляют режим. В зависимости от этого режима класс устанавливает зависимости как мок-объекты или реальные реализации. Некоторые тесты класса актуальны для обоих режимов, в то время как другие актуальны только для одного из них. Я пытаюсь найти способ пропустить или игнорировать некоторые тесты в зависимости от значения режима. Поэтому я хочу сделать что-то вроде следующего
[TestFixtureSource(nameof(UnitOrIntegration))]
class Tests(string Mode)
{
[SetUp]
void Setup()
{
if (Mode == "Unit") { ... }
if (Mode == "Integration") { ... }
}
[Test] //актуален для обоих режимов
void Test1() { ... }
[Test][WhenModeIs("Unit")]
void Test2() { ... }
[Test][WhenModeIs("Integration")]
void Test3() { ... }
}
Я нашел нечто, что, похоже, может помочь
[AttributeUsage(
AttributeTargets.Method,
AllowMultiple = false,
Inherited = false)]
public class WhenModeIsAttribute(string Mode)
: NUnitAttribute, IApplyToTest
{
public void ApplyToTest(Test test)
{
if (/* Мне нужно проверить режим здесь */)
{
test.RunState = RunState.Ignored;
test.Properties.Set(
PropertyNames.SkipReason,
$"Это не актуально для {Mode}");
}
}
}
Но я не могу найти способ получить доступ к значению режима. Как это сделать?
Ответ или решение
Чтобы получить доступ к состоянию класса тестов и его атрибутам в пользовательском атрибуте IApplyToTest
, есть несколько шагов, которые необходимо учесть. В данном случае мы хотим игнорировать или пропускать определённые тесты в зависимости от значения режима ("Unit" или "Integration"), и это можно реализовать с помощью пользовательского атрибута.
Структура Тестового Класса
Начнем с определения класса тестов. Мы используем TestFixtureSource
, чтобы передать значения режима в наш тестовый класс:
[TestFixtureSource(nameof(UnitOrIntegration))]
class Tests(string Mode)
{
[SetUp]
void Setup()
{
if (Mode == "Unit")
{
// Настройка для юнит-тестов
}
else if (Mode == "Integration")
{
// Настройка для интеграционных тестов
}
}
[Test] // Этот тест актуален для обоих режимов
void Test1()
{
// Логика теста
}
[Test]
[WhenModeIs("Unit")]
void Test2()
{
// Логика теста
}
[Test]
[WhenModeIs("Integration")]
void Test3()
{
// Логика теста
}
}
Создание Пользовательского Атрибута
Далее мы определим наш атрибут WhenModeIs
, который будет использовать интерфейс IApplyToTest
для изменения состояния выполнения теста в зависимости от текущего значения Mode
.
[AttributeUsage(
AttributeTargets.Method,
AllowMultiple = false,
Inherited = false)]
public class WhenModeIsAttribute : NUnitAttribute, IApplyToTest
{
private readonly string _mode;
public WhenModeIsAttribute(string mode)
{
_mode = mode;
}
public void ApplyToTest(Test test)
{
// Получаем состояние теста-родителя, чтобы увидеть текущий режим
string currentMode = GetCurrentMode(test);
if (currentMode != _mode)
{
test.RunState = RunState.Ignored;
test.Properties.Set(
PropertyNames.SkipReason,
$"Тест пропущен, так как он не актуален для режима {_mode}");
}
}
private string GetCurrentMode(Test test)
{
// Так как переменная Mode передаётся в TestFixture, мы можем получить её с помощью свойства
var parentFixture = test.Properties.Get("Parent") as Test;
return parentFixture?.Arguments[0] as string; // Предполагаем, что передается один аргумент - режим
}
}
Как Это Работает
- В атрибуте
WhenModeIsAttribute
мы храним переданное значение режима в частном поле_mode
. - В методе
ApplyToTest
мы получаем ссылку на родительский тест или класс тестов и извлекаем текущее значение режима с помощью методаGetCurrentMode
. - Если текущий режим не совпадает со значением из атрибута, мы изменяем состояние теста на
RunState.Ignored
и задаем причину пропуска.
Заключение
С помощью этого подхода вы сможете эффективно управлять выполнением тестов в зависимости от текущего режима. Это значит, что вы можете создавать более чистые и управляемые тесты, избегая их ненужного выполнения, что в свою очередь увеличивает скорость тестирования и улучшает читаемость кода. Использование пользовательских атрибутов даёт большую гибкость в разработке автоматизированных тестов и эффективном управлении ими.