Как получить доступ к состоянию тестового класса из пользовательского атрибута IApplyToTest?

Вопрос или проблема

У меня есть тестовый класс с 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; // Предполагаем, что передается один аргумент - режим
    }
}

Как Это Работает

  1. В атрибуте WhenModeIsAttribute мы храним переданное значение режима в частном поле _mode.
  2. В методе ApplyToTest мы получаем ссылку на родительский тест или класс тестов и извлекаем текущее значение режима с помощью метода GetCurrentMode.
  3. Если текущий режим не совпадает со значением из атрибута, мы изменяем состояние теста на RunState.Ignored и задаем причину пропуска.

Заключение

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

Оцените материал
Добавить комментарий

Капча загружается...