CSharp Allure classic NUnit with improvements

Доброго времени суток, коллеги!

Как мы все прекрасно знаем (или не все), поддержка и разработка Allure порта под C# не особо продвигается, за исключением энтузиастов вроде @unickq.

Я столкнулся со следующими проблемами/неудобствами в аллюре на C#:

  1. Невозможность добавления шагов/аттачей в [SetUp] и [TearDown] методах.
  2. Отсутствие нормальной возможности указания собственных:
  • Suite (самое неприятное)
  • SubSuite
  • Owner
  • Epic Suite
  • Parent Suite
  1. При выполнении действий в других потоках в рамках одного теста - allure падает с исключением.
    Т.е. если вы сделаете нечто подобное
    Task.Run( () => someMethod());
    и внутри данного метода будет вызвано логирование аллюр - выбросится исключение NullReferenceException.

  2. Отсутствие проигнорированных тест-кейсов/тестов в отчётах. (Кейсы, у которых прописано TestCaseData.Ignore(string).
    Для меня это оказалось критично, т.к. если мы не смогли найти подходящие тестовые данные из БД для кейса, он должен об этом кричать в отчете, а не отсутствовать там.

  3. Отсутствие нормального AddAttachment метода, который форматировал бы string в читабельный вид с отступами (json/xml).

Было что-то ещё, но оно не столь критичное, сейчас я уже не вспомню.

Я взял за основу проект https://github.com/unickq/allure-csharp-fork и добавил в него всю необходимую функциональность.

Переработанный мною C# allure имеет функциональность только для классического NUnit.
Если вы используете SpecFlow - не устанавливайте этот пакет, в нём нет ничего относящегося к SpecFlow, у вас всё сломается!

В будущем я добавлю нововведения для SpecFlow и сам SpecFlow, если это вообще кому-то будет нужно, кроме меня :slight_smile:

Итак…

Представляю вашему вниманию nuget пакет с переработанным C# Allure под классический NUnit: NuGet Gallery | Noksa.NUnit.Allure 3.2.0

Некоторые методы я видоизменил, поэтому возможно придётся немного изменить их старую сигнатуру переходя с классического аллюра. Но это не точно. :slight_smile:

Кратко, как использовать данный allure и его некоторые новые фишки:

  1. ГЛАВНОЕ: Для включения логирования - необходимо унаследовать класс Allure.Commons.AllureReport базовым классом ваших тестов. Не нужно у каждого класса/метода писать какие-либо allure атрибуты:
public abstract class ABaseTestConfig : AllureReport

Либо непосредственно каждый класс с тестами, если базового нет.

  1. Для использования своего названия Suite, нужно добавить атрибут [AllureSuiteAttribute] у класса:
[AllureSuite(LoginPassNotExists)]
 public partial class MyTests: ABaseApiTestConfig
Своё название Suite

Внутри класса у методов можно использовать атрибут [AllureSubSuiteAttribute], для разделения на более мелкие Suite’s внутри одной большой [AllureSuiteAttribute]:

Пример SubSuites

  1. Для указания Epic Story для всего класса следует использовать атрибут [AllureEpicAttribute]:
[AllureEpic("Epic story")]
public partial class MyTests: ABaseApiTestConfig
Пример Epic Story

Соответственно, если в таком классе будут методы с атрибутами [AllureStoryAttribute], все они будут дочерними в следующем порядке:
Epic → Feature > Story.

[AllureStory("С авторизацией")]
[AllureStory("Hey hey")]
public void Test()
Пример каскадности Story

image

  1. Атрибут [AllureOwnerAttribute] - устанавливает Owner’a теста\тест-кейса.

  2. Если у метода указаны атрибуты [AllureIssueAttribute], то в отчете в Suite класса добавится ещё один SubSuite с названием “With Defects”, где будет список тестов/кейсов класса, в которых этот атрибут присутствует.
    Сделано для быстрого поиска тестов с дефектами в указанных классах.
    В Story не добавляется, т.к. не вижу смысла в дублировании пока что:

SubSuite со всеми дефектами тестового класса

  1. Аналогично дефектам из 5 пункта, в Suite класса будут добавлены все проигнорированные тесты/кейсы этого класса (для этого ничего указывать не надо).

  2. Сам игнорированный тест имеет в отчете указанную причину, по которой это произошло:

Игнорированный тест

  1. Добавлена перегрузка метода AddAttachment()
    Выглядит так:
public AllureLifecycle AddAttachment(string name, AttachFormat type, string content, string fileExtension = "")

Используется для добавления отформатированных аттачей (xml/json), чтобы они выглядели читабельно, а не в одну строку:

Отформатированные аттачи

  1. Соответственно, теперь можно использовать добавление шагов/атачей в [SetUp] и [TearDown] методах.
    Пример Setup:
[SetUp]
public virtual void Setup()
        {
            AllureLifecycle.Instance.AddAttachment($"Screenshot [{DateTime.Now:HH:mm:ss}]",
                "image/png",
                Driver.TakeScreenshot().AsByteArray);
          ...
         }
    • Возможность использования потоков внутри одного теста для логирования в аллюр.
      Например: Task.Run( () => someMethod());
      Данный метод будет иметь начальным шагом не текущий шаг главного потока, а рутовый шаг отчета.
      Если вы в этом методе будете создавать steps с substeps - они будут создаваться корректно, внутри steps своего потока.

Итд…
Если возникнут проблемы/вопросы, пишите, буду рад помочь.

Это мой первый опыт выкладывания чего-либо в opensource, поэтому прошу отнестись с пониманием, если я где-то мог накосячить с пакетом :frowning:

Так же я не очень долго обкатывал новые атрибуты, поэтому если есть желающие быть бета-тестерами - велком :slight_smile:

Из известных проблем сейчас:

  1. В отчет попадают все проигнорированные тест-кейсы из тестового класса, даже если вы запускали только один тест в нём.

5 лайков

Разобрался с тем, как правильно пилить пакеты. :sunglasses:
Ну и по такому радостному событию обновил версию до 1.0.4.

Нововведения:
Добавлена поддержка net45/net451/net452 и netstandard2.0.

… nuget хорошо но все-таки.

  • дайте пожалуйста линк на код вашего проекта на гитхаб
1 лайк

Для чего вклеивать все один проект? Тем более allure.csharp.fork, а не оригинальный allure.csharp

Не очень пронял про что именно речь.
Но вообще, в целом, я не люблю лишние зависимости, которые можно убрать. Именно поэтому я и взял fork как основу, чтобы не тянуть зоопарк.

Кор проект это лишняя зависимость?) Really :man_facepalming:

Форк это обрезанная версия старого allure-csharp, дабы была поддержка net45 без утяжеления ms json configuration, пока автор оригинала не решил таки переехать на newtonsoft json.

Потому собственно и вопрос - зачем внутри кор, так еще и не совсем валидный :slight_smile:

Как бы совместимость с уже сущевствующей инфраструктурой должна бы быть - если уж тут такая презентация, а не просто базовый класс для себя, делающий скрины в teardown :wink:

Если бы Вы чуточку внимательнее изучили мой проект, то заметили бы, что в core проекте (если я правильно Вас понял - то вы имеете в виду Commons) был так же изменен код классов AllureStorage.cs (для поддержки многопоточной записи в отчет в рамках одного теста) и AllureLifeCycle.cs, поэтому я не мог просто взять его и прицепить как зависимость.
Делать для изменённого core проекта отдельный nuget-пакет на мой взгляд было бы перебором, учитывая что он нигде кроме этого проекта не используется.
Это к вопросу зачем он там и почему не является зависимостью.

Изначально, собственно, это и делалось для себя с единственной целью - setup/teardown, но потом обросло большим функционалом.

Ну и, собственно, я не обещал совместимость с нынешней инфраструктурой, о чем и написал в первом сообщении. Она вполне может быть, просто я, честно говоря, не помню что я изменял в самом начале. :slight_smile:

И, опять же, если внимательнее изучить проект, то базовый класс в core-проекте не делает никаких скриншотов в teardown, он делает совсем другие вещи :wink:

Обновлено до 1.0.5 версии.

Нововведения:

  • Убран метод AllureLifecycle.CreateInstance(string dir) - вызов данного метода ломал запись отчетов.
  • Добавлен метод AllureLifecycle.Instance.ChangeResultsDirectory(string dir) - данный метод изменяет директорию, куда будут складываться отчёты.
1 лайк

Обновлено до 1.0.6 версии.

Исправлено:

  • При вызове методов StartStep/UpdateStep/StopStep в методах, помеченных атрибутом [OneTimeSetup] и [OneTimeTearDown] теперь не будет выбрасываться исключение.

Использование аллюра в методах с атрибутами [OneTimeSetup] и [OneTimeTearDown] не является запланированным действием, по причине того, что в этот момент нет активного теста/тест-кейса, т.е. аллюр просто не знает, в какой тест-кейс записывать указанный шаг, т.к. контейнера с тест-кейсом просто не существует.
Я убрал выкидывание исключения, можно использовать аллюр в этих методах, с поправкой на то, что никакого логирования по факту выполняться не будет.

Спасибо @Ihor_Kokhan за фидбэк по данной проблеме.

1 лайк

Обновлено до 1.0.7 версии.

Добавлено:

  • Новое свойство AllureLifecycle.Instance.AllowEmptySuites
    При установке значения true, если у вас произойдёт ошибка в методе с атрибутом [OneTimeSetUp] в тестовом классе, все тесты из него попадут в отчёт с ошибкой, а не будут пропущены.

Исправлено:

  • При использовании атрибута [Retry] перезапуски теста теперь будут отображаться во вкладке Retries в отчёте, аналогично атрибуту [Repeat]

Спасибо @Ihor_Kokhan за фидбэк.

1 лайк

Обновлено до версии 2.0.

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

Что нового:

  • Теперь все настройки задаются в файле allureConfig.json, который должен лежать в той же директории, что и файлы сборки проекта с тестами.
    Таких настроек пока только две, но вы всегда можете предложить что-то новое и полезное :slight_smile:

  • Неактуальные более методы были помечены как Obsolete, и в дальнейших релизах будут удалены - вместо этих методов вам нужно задать значение в allureConfig.json, если вы хотите переопределить настройку

  • Добавлен новый AttachFormat - Video
    Пример использования: AllureLifecycle.Instance.AddAttachment("Видео теста", AllureLifecycle.AttachFormat.Video, pathToFile);

  • Теперь если вы запускаете тесты через IDE, по умолчанию результаты будут создаваться в директории allure-results рядом с файлами сборки проекта с тестами, а не во временной директории (в некоторых случаях это была директория внутри IDE, если она запущена с админскими правами)

Если Вам требуется использовать временную директорию, Вы можете просто указать "directory" : "temp"

:warning: После обновления до данной версии, вам нужно будет включить копирование файла allureConfig.json в Output Directory, как показано на скриншоте. Делается это один раз.
Файл появится в корне проекта.
В противном случае будет ошибка при запуске тестов.

Screenshot

image

Был обнаружен недочёт, спасибо @Ihor_Kokhan.

Обновлено до версии 2.0.4.

Что нового:

  • Аргументы тест-кейсов будут добавляться в отчёт как параметры, с указанием типа аргумента.
    Тем самым одинаковое название теста больше не будет вносить недопонимание, когда с виду тесты одинаковые, но разные аргументы.

Исправлено:

  • Если тест-кейсы имеют одинаковое название, но разные параметры - теперь такие тест-кейсы в отчёте будут фигурировать как отдельный тест, а не Retry одного и того же.

Изменено:

  • Теперь отчёты будут появляться в той директории, из которой вы запускаете тесты.
    Прошлая версия ломала генерацию отчётов в Jenkins, когда запуск тестов производился из workspace директории и отчёт искался там же, т.к. всегда генерировались результаты рядом с dll тестов (если не менять директорию по умолчанию), что не очень правильно.
    Сейчас всё вернётся на круги своя, но при запуске из IDE отчёты тем не менее будут появляться рядом с dll по умолчанию.
1 лайк

Версия 2.0.4.1 доступна для скачивания.

Так же в неё было включено ещё два нововведения.

  1. Т.к. не всегда уместно показывать значение всех параметров в отчёте (например пароли), был добавлен новый атрибут, который применяется к методам: [AllureHideParams], который принимает на вход номера параметров через запятую, которые следует скрыть.

Например так:

[AllureHideParams(2, 3)]
 public void LoginToApp(string login, string password, string password2)
        {
            //code here
        }

Соответственно, значение второго и третьего параметра (password и password2) будут скрыты в отчёте.

Пример скрытия параметра

image

  1. Так же бывают случаи, когда Вы вообще не хотите отображать какой-то параметр, а может быть и вообще все параметры.
    Для этого случая вам подойдет новый атрибут [AllureRemoveParams], который работает аналогично атрибуту [AllureHideParams], только не прячет параметры, а вообще удаляет упоминание о них из отчёта.

[AllureRemoveParams] имеет приоритет. Т.е. если вы укажите два этих атрибута с одним и тем же номером параметра - он будет удален, а не спрятан.

В json конфиг была добавлена новая настройка enableParameters, имеющая по умолчанию значение true.

Если вы хотите отключить запись параметров в тест-кейсы во всём проекте, используйте эту настройку со значением false

2 лайка

Обновлено до 2.2 версии.

Нововведения:

  • Добавлен новый метод RunStep с одной перегрузкой.
  • Добавлен новый класс Verify
  • Добавлено два новых метода, отвечающие за настройку действий при ошибках в проверках Verify и RunStep
  • Теперь шаги, которые были выполнены в методах [SetUp] и [TearDown] в отчётах будут отображаться не в TestBody, а соответственно в SetUp и TearDown.
  • Файл categories.json больше не будет удаляться из allure-results.
  • Проигнорированные тесты теперь помечаются как skipped, а не broken.

Теперь подробнее.

  1. Два новых настроечных метода:
AllureLifecycle.Instance.SetGlobalActionInException(Action action)

и

AllureLifecycle.Instance.SetCurrentTestActionInException(Action action)

Можно указать, какие действия нужно дополнительно выполнять, если в методе RunStep или в проверках в классе Verify возникла ошибка/проверка не прошла.

Например, вы можете добавить, чтобы в отчёт при ошибке так же прикреплялся скриншот:

AllureLifecycle.Instance.SetGlobalActionInException(() =>
            {
                DriverManager.MakeScreenshotAtStep();
            });

Это глобальная настройка для всех тестов, её достаточно вызвать один раз.

Метод SetCurrentTestActionInException отвечает за настройку доп. действий для конкретного теста и существует только в рамках запуска теста, если её указали.
Используется опционально.

  1. Метод AllureLifecycle.Instance.RunStep(string stepName, Action action) оборачивает указанный string в аллюр-степ.
    Если в данном методе возникнет исключение - тест зафэйлится с исключением.
    В отчёт при этом будет добавлен сабстеп у шага stepName, с текстом исключения.
    Если вы добавите доп. логику через настроечные методы из п.1, то эта информация так же добавится в отчёт как сабстепы у stepName.
    Если же ошибок не будет, то шаг stepName в отчёте просто будет зелёный.

  2. Класс Verify - это по сути копия Assert из NUnit с дополнительным функционалом.
    Использование, например так:

AllureLifecycle.Instance.Verify.That("Проверяем, что 5 больше 2", 5, Is.GreaterThan(2));

Если при данной проверке возникнет исключение (т.е. она не пройдёт), тест не упадёт и пойдёт дальше, при этом информация в отчёт будет добавлена по такой же логике, как в методе RunStep.
Подходит для большого количества проверок в рамках одного теста.
Т.е. все непрошедшие проверки будут отображены как неудачные шаги с информацией из исключений.
В отчёте так же будет наглядное сообщение о всех непрошедших проверках в ходе теста:

Screenshot

PS: Так же вы можете использовать RunStep внутри другого RunStep, если произойдёт ошибка, то все связанные шаги будут окрашены красным.
Либо использовать Verify внутри RunStep.

Более полные примеры использования нововведений вы можете посмотреть здесь: https://github.com/Noksa/Allure.NUnit/blob/master/TestsSamples/Tests1.cs

3 лайка

Обновлено до версии 2.3.

Что нового:

  • :exclamation: Теперь шаги, которые будут вызваны в методах, обозначенных атрибутами [OneTimeSetup] [Setup] [TearDown] [OneTimeTearDown] будут отображаться в своих собственных вкладках внутри Setup и TearDown, как показано на скриншоте. Эти шаги имеют такой же функционал как и шаги в тесте.
    Название вкладки с шагами - это имя метода с указанным атрибутом.
Screenshot

  • Добавлена перегрузка метода RunStep без указания первым аргументом названия шага. В таком случае названием шага будет название родительского метода.
AllureLifecycle.Instance.RunStep(() => _driver.Close());
1 лайк

Небольшое обновление 2.3.4.

Что нового:

  • Теперь название suite в отчёте будет так же содержать параметры фикстуры, если она параметризована (отобразятся при enableParameters == true):
    image
  • Добавлены опциональные аргументы в методы RunStep и в большинство перегрузок Verify.That.
    Теперь вы можете добавлять параметры в конкретный шаг (отобразятся при enableParameters == true):
AllureLifecycle.Instance.RunStep("This is my step", () =>
            {
                _driver.Close();
            }, "This is string param", 50, 2300);

  • Небольшие баг-фиксы.

Известные проблемы сейчас:

  • Не работает функционал аллюра, если вы используете мультитрединг в рамках одного теста (например через Task.Run).
    Судя по всему, не работает уже давно, будет пофикшено ASAP.
2 лайка

Совсем забыл про добавление ещё пары фич в релиз. :frowning:
Так что встречайте 2.3.5.2 :slight_smile:

Что нового:

  • Добавлена настройка отображения в отчете своих категорий. Настройка осуществляется через конфиг-файл allureConfig.json.
    Пример нового конфига с категориями:
{
  "allure": {
    "directory": "allure-results",
    "allowEmptySuites": true,
    "enableParameters": true
  },

  "categories": [
    {
      "name": "Broken locators",
      "messageRegex": ".*Unable to locate element.*"
    },
    {
      "name": "Problems with timeout",
      "messageRegex": ".*Timed out.*",
      "traceRegex": ".*"
    },
    {
      "name": "Broken tests",
      "matchedStatuses": [ "broken" ]
    },
    {
      "name": "Ignored tests",
      "matchedStatuses": [ "skipped" ]
    },
    {
      "name": "Tests with defects",
      "matchedStatuses": ["failed"] 
    }

  ]
}

Документация, как добавлять категории: https://github.com/allure-framework/allure-docs/blob/master/docs/features/categories.adoc

Если вы планируете использовать русские имена категорий, убедитесь, что ваш allureConfig.json в проекте имеет кодировку UTF-8

Соответственно, тест-кейсы, которые попадают под условия, будут добавлены в соответствующие категории в отчете:
image

  • Добавлен новый атрибут [AllureLink], для добавления ссылок к тест-кейсам или тестовым классам в отчёт, которые не подходят под определение tms или issue.
  • Атрибуты [AllureLink] [AllureTms] [AllureIssue] теперь можно применять и к тестовым классам. В таком случае ссылки будут добавлены в каждый дочерний тест/тест-кейс.
1 лайк

Доступна бета-версия 2.4.

Что нового:

  • Добавлена возможность указания переменных в Environment отчёта. Настраивается через allureConfig.json

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

  1. Константы в самом конфиг-файле, в блоке environment:
    image
    Результат:
  2. Переменные, значение которых будет известно только во время запуска тестов. Добавляется в блок environment.runtime. Работает только с константами и статичными полями/свойствами.
    Указывать необходимо следующим образом: Namespace.ClassName.MemberName
    Работает с public/internal/private:

Результат:


3) Так же можно добавлять системные переменные (и переменные из CI). Добавляется так же в блок environment.runtime следующим образом: System.Environment.NameOfVariable:

Результат:

Все типы переменных можно комбинировать как угодно.

Пример конфига с переменными:

{
  "allure": {
    "directory": "allure-results",
    "allowEmptySuites": true,
    "enableParameters": true
  },

  "categories": [
    {
      "name": "Problems with locators",
      "traceRegex": ".*NoSuchElementException.*"
    },
    {
      "name": "Problems with DOM",
      "traceRegex": ".*StaleElementReferenceException.*"
    },
    {
      "name": "Problems with timeout",
      "messageRegex": ".*Timed out.*",
      "traceRegex": ".*"
    },
    {
      "name": "Broken tests",
      "matchedStatuses": [ "broken" ]
    },
    {
      "name": "Ignored tests",
      "matchedStatuses": [ "skipped" ]
    },
    {
      "name": "Defected tests",
      "matchedStatuses": [ "failed" ]
    }
  ],

  "environment": {
    "MyVariable": "This is value of my variable",
    "runtime": [
      {
        "BrowserVersion": "SomeNameSpaceHere.SomeClassHere.BrowserVersion",
        "Browser": "SomeNameSpaceHere.SomeClassHere.BrowserType",
        "StandEnv": "SomeNameSpaceHere.SomeClassHere.Environment",
        "OS": "System.Environment.OS"
      }
    ]
  }
}

Просьба о всех проблемах/недочётах писать в ЛС.

2 лайка

Доступна версия 2.4.0.2

Что нового:

  • Добавлена возможность использования локальной History Trend, если вы запускаете тесты из IDE.
    Настраивается через allureConfig.json, необходимо в блоке allure добавить allowLocalHistoryTrend, со значением true:
"allure": {
    // another settings here
    "allowLocalHistoryTrend": true 
  },

Не ставьте значение true при прогонах на CI, либо вообще не указывайте эту настройку.
Это для тех, кто не умеет или не хочет в CI :slight_smile:

В данном обновлении нет информации о history самих тестов при локальных прогонах.

После этого, если запускать тесты более 1 раза, на главной странице отчёта будет доступна информация в виджете Trend, аналогично запускам через CI:

Исправления:

  • Поправлено отображение Retries теста, при использовании атрибутов [Retry] и [Repeat]
  • Теперь во всех Retries будут отображаться шаги, выполненные внутри [OneTimeSetup] и [OneTimeTearDown], а не только в первой попытке.
  • Исправлена ситуация, когда выбрасывалось исключение NullReferenceException в некоторых случаях вместо записи результатов тестов фикстуры.

Спасибо @Ihor_Kokhan за фидбэк.

2 лайка