CSharp SpecFlow Framework - аналог sbtqa PageFactory Framework на Java - нужен ли?

csharp
specflow
framework
page-object
Теги: #<Tag:0x00007fedbb9eac68> #<Tag:0x00007fedbb9eab28> #<Tag:0x00007fedbb9ea9e8> #<Tag:0x00007fedbb9ea808>

(Alexandr D ) #1

Коллеги, добрый день.

Небольшое отступление:
Буквально пару месяцев назад у меня была прекрасная возможность начать автоматизацию с нулю в компании, где её вообще не было на моём любимом языке - C#.
Пошуршав в интернетах, я понял - что, в принципе, на C# нет в опенсорсе достаточно мощного и удобного фреймворка написанного для использования со SpecFlow (либо я его не нашёл).

Лично для меня, когда я занимался автоматизацией на Java, был очень удобен фреймворк от sbtqa: https://github.com/sbtqa/page-factory, естественно допиленный под свои нужды и избавленный от кучи ненужных вещей.
Ключевое в нём - избавиться от большого количества самописных/хардкодных шагов.

К сожалению, на C# подобного я не нашёл и решил сам написать аналог.
Но, обстоятельства сложились так, что от BDD отказались (слава Богу, на мой взгляд), и я начал допиливать классический фреймворк, забросив specflow.
Но, учитывая что он всё же уже был написан, я решил его возродить и поддерживать, т.к. уже накопилось много плюшек, которые можно реализовать в нём.
(Проект фреймворка: https://github.com/Noksa/AAA)

Но, чтобы не заниматься этим просто так, я решил провести опрос.

Нужен ли конкретно вам подобный фреймворк и будете ли вы им пользоваться?

  • Да, нужен.
  • Попробовал(а) бы.
  • Нужен, но переход с существующего фреймворка слишком затратен.
  • Нет, не требуется.
  • Не знаю что это, не знаком с ним на Java.

0 участников


(Юрий Аксютин) #2
  1. Скачал и запусти ваши тесты, результат выполнения нашел только в тестовой консоли(надеюсь это пытается распарсить результаты, которых я не смог найти):

  2. Allure + Nunit + Specflow - по моему, это слишком. Раньше использовал Nunit + Specflow. Через некоторое время Nunit выкинул - проще обновлять один фреймворк, чем сразу два(или больше).

  3. Русский язык для написания фич и для сообщений о ошибках - ваш фреймворк, смогут испольовать только в проектах для стран бывшего СССР)

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


(Alexandr D ) #3

@Yurij_Aksyutin
Спасибо, что уделили этому время :slight_smile:

Попытаюсь ответить на ваши не заданные и заданные вопросы.

Попробуйте запустить студию под админскими правами, если запускаете тесты в ней. Это поможет.
У меня была похожая проблема, которая сама рассосалась и я не смог найти в чем была причина, т.к. она исчезла.
Видимо, не на совсем…

Аллюр отвечает за отчеты.
NUnit за запуск тестов. (Хотя, по большому счету, NUnit можно заменить на любой другой тестовый фреймворк, с которым дружит SpecFlow).
Ну а SpecFlow - понятное дело, за сами тесты.

Это недолго исправить, если в этом будет необходимость. :slight_smile:

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

В самом фреймворке есть всего два места, куда вы можете добавлять core-steps.

  1. Класс с самой высокоуровневой абстракцией - CoreSteps.cs.
    С этого места начинается каждое действие в ФФ.
    Я для примера туда написал далеко не все возможные варианты.

Пример:
Этот метод:

[StepDefinition("^пользователь \\((.*)\\) \"([^\"]*)\" (?:значением |со значением |с параметром | |)\"([^\"]*)\"$")]
        public void ExecuteMethodByTitle(string actionTitle, Transforms.WrappedString param1, Transforms.WrappedString param2)
        {
            PageManager.PageContext.CurrentPage.ExecuteMethodByTitle(actionTitle, param1.Value, param2.Value);
        }

может выглядеть в ФФ в зависимости от действия так:

И пользователь (заполняет поле) "Логин" значением "Мой логин"

или так:

И пользователь (заполняет поле) "Логин" "Мой логин"

или так:

И пользователь (сравнивает текст элемента) "Логин" со значением "Это не мой логин"

Все эти действия будут обработаны вышеуказанным методом.
И там таких методов много, но, возможно, не все.

  1. Второе место - класс BasePage. Какие-то общие действия, которые встречаются чаще всего во многих проектах.
    Например такой метод:
[ActionTitle("заполняет поле")]
        public virtual void FillField(string elementTitle, string value)
        {
            var element = (AProxyElement) GetElementByTitle(elementTitle);
            element.Clear();
            element.SendKeys(value);
            AllureSteps.AddSingleStep($"Поле '{elementTitle}' заполнено значением '{value}'.");
        }

Этот метод можно использовать в любом из методов в классе CoreSteps.cs.

Т.е. метод, помеченный атрибутом [ActionTitleAttribute] можно поместить в скобки методов из CoreSteps.cs.

Например:

[StepDefinition("^пользователь \\((.*)\\) из таблицы$")]
        public void ExecuteMethodByTitle(string actionTitle, Dictionary<string, string> dict)
        {
            PageManager.PageContext.CurrentPage.ExecuteMethodByTitle(actionTitle, dict);
        }

Метод из BasePage.cs:

[ActionTitle("заполняет поле")]
        public virtual void FillField(string elementTitle, string value)
        {
            var element = (AProxyElement) GetElementByTitle(elementTitle);
            element.Clear();
            element.SendKeys(value);
            AllureSteps.AddSingleStep($"Поле '{elementTitle}' заполнено значением '{value}'.");
        }

Всё вместе это будет выглядеть так:

И пользователь (заполняет поле) из таблицы
|Поле   |Текст       |
|Логин  |МойЛогин |
|Пароль |МойПароль|

Естественно, у метода (заполняет поле) должна быть перегрузка с Dictionary.
Вот она:

public virtual void FillField(Dictionary<string, string> dictionary)
        {
            foreach (var keyValuePair in dictionary)
            {
                var element = GetElementByTitle(keyValuePair.Key) as IWebElement;
                element.SendKeys(keyValuePair.Value);
                AllureSteps.AddSingleStep($"Поле '{GetElementByTitle(keyValuePair.Key)}' заполнено значением '{keyValuePair.Value}'.");
            }
        }

Все остальные локальные методы, в том числе и их перегрузки - вы можете писать конкретно в pageobject и в блоках в конкретном проекте.
При необходимости изменения где-то локально общих методов из ядра - просто оверрайдить их, если они работают иначе (не писать новый с атрибутом - а просто оверрайднуть)
Фреймворк найдет их.

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

Каков минимальный уровень знания у автоматизатора должен быть - достаточный для того, чтобы он мог писать свои методы и помечать их атрибутом ActionTitle в ядре / в своих проектах.
А так же при необходимости дописывать core steps или изменять их, в данном случае так же знать регулярки.

У меня где-то завалялась презентация по этому фреймворку, если хотите, могу найти, там более понятным языком всё описано.


(Nick) #4

Что значит фреймворк со спекфлоу? Забиндженные шаги кликов и прочих экшенов?

То есть хочется написать свои хардкодные шаги? и на русском языке? Не, я понимаю, что в атрибут можно написать все что уогодно, но русский язык это… ну короче не для всех :smiley:

Все давно есть. Плагин для спекфлоу, который в конце теста записывает JSON файлы Аллюра. Какой раннер будет у спеклофлоу - без разницы.


(Alexandr D ) #5

Угу.
Что-то типа этого на Java => https://github.com/sbtqa/page-factory
Где для старта написания авто-тестов не нужно ничего делать, кроме как подключить либу с фреймворком и написать ФФ с экшенами, попутно естественно создав pageobjects.
Понятно, что всё равно какие-то экшены будут свои и их придётся дописывать - либо в ядро либо в проект конкретного приложения, но это вопрос наполнения, который легко решается.

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

А так методы могут выглядеть так:

[ActionTitle("заполняет поле")]
[ActionTitle("fills field")]
[ActionTitle("füllt das Feld")]
        public virtual void FillField(string elementTitle, string value)
        {
            var element = (AProxyElement) GetElementByTitle(elementTitle);
            element.Clear();
            element.SendKeys(value);
            AllureSteps.AddSingleStep($"Поле '{elementTitle}' заполнено значением '{value}'.");
        }

ну и так далее, тоже самое и для coresteps.

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

Если только вы занимаетесь написанием тестов в BDD стиле, то конечно всё это не имеет смысла. (хотя тогда и BDD не имеет смысла)

Посыл фреймворка же здесь такой, что ваш словарь действий будет одинаковым для всех проектов, за исключением индивидуальных под проект действий (коих обычно бывает немного).
А это в свою очередь позволит пользователям писать ФФ на любом проекте используя общий словарь действий, а не искать в конфлюенсе словарь под каждый проект со своим стилем написания действий и объяснением что же это действие делает.

Например пользователь просто будет знать, что в любом проекте достаточно написать фразу

* пользователь (заполняет поле) "Поле" значением "Значение"

для того, чтобы оно работало.

Если же действия описываются для каждого проекта конкретно свои, то пользователю придется знать стиль написания/название экшена.

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

Если надо оверрайднуть метод(ы) для всего проекта в целом, а не для конкретной страницы/блока, то, если мне не изменяет память, созданием одного базового класса сейчас не обойтись, т.к. их нужно будет два - для блоков и для страниц, в них овверайдить методы, и уже от них наследовать блоки/страницы.
Но я давно не смотрел уже, если действительно нужно два класса - то, конечно, это требует изменения.