Хранение локаторов

Доброго дня!

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

Как и где оптимальнее всего огранизовать их хранение?

 

Тоже послушаю - сам хочу организовать хранение, да ещё так, чтобы лишнгно софта с фреймворками не таскать. :)

 

Часто юзают SQLite - типа, взял файл с собой вместе со скриптовым или скомпиленным тестом и достаточно (эскулайт поддерживается многими языками). Пока меня останавливает лень :) и вдруг кто-то лучше предложит.

А чем вам не нравится держать в коде?

 

Для каждой страницы - свой файл/класс с переменными-локаторами и методами взаимодействующими со страницой.

Общие локаторы выносятся в отдельный файл/класс, от которого, при необходимости, наследуемся.

Как результат - весь UI отдельно, сгрупирован по страницам. 

 

По мне - дополнительная логика хранения добавит больше мороки, нежели пользы. Хотя возможно у кого-то есть положительный опыт использования. Будет интересно узнать.

Храню все локаторы в переменных внутри PageObjects и чувствую себя сухо и комфортно. В случае NoSuchElementException, StackTrace ткнет нам на строку с методом, получившим невалидный локатор. И все, через минуту анализа и поиска локатор поправлен и все довольны.

Хранить локаторы в БД или файлах - бесполезная трата времени и ресурсов, имхо.

2 лайка

а если надо заполнить данные о сотруднике: Фамилия/Имя/Отчество/Предыдущее место работы/Адрес/Телефон... и еще 100500 данных

 

т.е. у вас страница будет забита кучей переменных с локаторами

или Вы считаете это нормальным ?

 

 

 

речь же не только о локаторах (именах контролов в моём случае) - здесь

1) локаторы/контролы

2) данные, которые пихаются в тест - их гораздо больше, чем локаторов/контролов, наборов данных. И их можно поручить заполнять кому-то другому (кто не пишет тест, а думает над тем какие данные должны что выдавать)

3) проверки, обработка ошибок и прочая вспомогательная куча всего

Тесты же получают как минимум несколько наборов данных: правильные данные (несколько классов), неправильные данные (может быть много комбинаций), пустая форма, автозаполнение и т.д. На всё это продукт/сайт реагирует (как это говорят в биржевых новостях в значении "хз как"?) разнонаправленно.

И где все эти данные хранить, и как их править другим членам команды?

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

Можно сгруппировать поля по критериям и распихать по разным файлам (в том же или разных pageObject классах).

Но даже в одном файле это вполне нормально (если оформление в порядке) - и любая другая организация локаторов (будь то xml или БД) положение не исправит - так как "проблема" в самой форме.

 

Чем, по-вашему, плоха организация локаторов в pageObject-e ? 

Пока речь шла только о локаторах. Возможно я что-то неправильно понял.

Касательно Вашего сообщения: по мне - это все разные слои.

1) локаторы/контролы - это UI (pageObject)  - там локатор, get/set/click или любое другое взаимодействие с интерфейсом. 

2) тест данные - отдельный слой; данные могут создаваться, генерироваться, браться из эксель файла - это уже другой вопрос

3) собственно проверки - это уже логика теста, это опять отдельный (и можно сказать основной) слой

А повторяющиеся/вспомогательные элементы выносятся в отдельный класс.

 

Пока такой вариант полностью устраивает. Какие, по вашему мнению, тут есть недостатки?

А у вас как реализовано ?

1 лайк

Да вот у нас м ногое в коде, что и смущает: к примеру, как показать кому-то наборы тестовых данных (да и самому посмотреть на них в виде таблички).

Или кому-то надо поправить чужой код - и как эти локаторы искать, если они то по id, то по XPath (абстрактный пример).

 

В противоположность самописным тестам, платные тулы типа QTP, Coded UI и т.д. работают с репозиториями объектов и картами контролов, что кажется удобным с точки зрения консолидации данных, но хорошо ли при изменяющихся данных.

Вопросы (к участникам обсуждения) получаются такие:

1) как удобнее вносить массовые изменения (затрагивают много классов, например)

2) как манирулировать входными данными (обычно это сводится к вопросу: "как наращивать наборы данных" :))

3) как разобраться в коде кому-то, кто не автор кода

 

На мой взгляд, локаторы лучше хранить в коде (PageObject). Декларации страниц и тесты необходимо обязательно разделять и хранить в отдельных пакетах/сборках. 
Таким образом у вас может быть 2 и более тест-сьюта, которые используют одну и ту же библиотеку с декларациями.
Сами ПейджОбжекты должны быть оформлены в виде структуры, напоминающей структуру приложения. Т.е. декларации для администрирования пользователей хранятся в папке Admin\Users\UsersManagement.cs и т.д. Тот же принцип следует применять и для тестов.
Так как тип IWebElement/WebElement не говорит практически ничего о том, что это за элемент, для внесения ясности, я использую Венгерскую Нотацию в именах элементов:
http://ru.wikipedia.org/wiki/Венгерская_нотация
 
lnkClickMe
txtLoginName
lstSelectLanguage
lblLogoText
imgLogo
 
Каждое действие по работе со страницей я выношу в метод к соответствующему PageObject. 
Например, в тесте я * не * пишу что-то типа:
 
loginPage.txtLogin.SendKeys(“Vasya”);
loginPage.txtPassword.SendKeys(“Poopkin”);
loginPage.btnLogin.Click();
 
эти строки я выношу в метод loginPage.Login(“Vasya”, “Poopkin”);
И, конечно же, логин и пароль в реальном коде забит в отдельные переменные либо читается из конфигурационного файла. 
Над PageObject, у меня есть так называемые Хелперы и Классы данных. 
Хелперы – это статические функцие, которые при надобности принимают классы с данными:
 
User.Delete(“Vasya”)
 
var userData = new UserData();
userData.GenerateUniqueDataWithDateTime();
userData.Name = “Vasya”;
User.Create(userData)
 
В данном случае User.Create выполняет все необходимые манипуляции по созданию пользователя, учитывая бизнес-логику приложения. 
 
Теперь ответы порядку:
1) как удобнее вносить массовые изменения (затрагивают много классов, например)
Если это уникальные изменения, например, если ваше приложение переписывают каждую неделю с нуля – то тут ничего не поделать, только править руками. 
Если это однообразные изменения, то повторяющуюся бизнес-логику можно выносить в методы-хелперы. Так же помогает наследование для PageObject’ов. 
Например, если у вас в нескольких страницах дублируются btnLogOut, то нужно создать базовый класс, и поместить ее туда. Так, что эта кнопка будет автоматически доступна страницам-наследникам. 
Если вы правите тестовые данные, то их необходимо выносить в отдельные файлы. Лучше всего текстовые. Например, файл userproperties.xls может быть внутри с текстовой информацией разделенной табами. Парсер написать очень просто + отредактировать в Excel. 
Можно использовать и такие форматы как Json или YAML. Ну, а если вам удобно править данные в XML, то и этот формат подойдет. 
 
2) как манирулировать входными данными (обычно это сводится к вопросу: "как наращивать наборы данных" :))
Многие фреймворки содержат так называемые параметризированые тесткейсы. И почти для всех можно прочитать данные из внешнего файла
 
http://weblogs.java.net/blog/johnsmart/archive/2009/11/28/data-driven-tests-junit-4-and-excel
http://www.gallio.org/wiki/doku.php?id=mbunit:data-driven_testing:external_data_sources
 
Данные лучше хранить в текстовых файлах и использовать систему контроля версий. С бинарными файлами и базой данных в таком случае работать сложнее, потому что потом сложно отследить кто когда и что менял. 
Данные должны хранится в отдельных папках. Например Data\Users\new_users_creation.txt, чтобы не было путаницы.
 
3) как разобраться в коде кому-то, кто не автор кода
Документировать структуру фреймворка. Выдавать максимально понятный отчет о проходе теста. 
Записать парочку скринкастов по работе с фреймворком. Создать FAQ. 
Выработать у команды единые правила написания кода, как это делают программисты. 
 
 
4 лайка

Діло каже! (с)

все четко изложил, так как оно и должно быть.

Я вот думаю, такие вопросы возникают постоянно и у всех, почему бы не написать тутоориал объясняющий это все просто и подробно. А если сделать серию статей где бы это все расписывалось от А до Я с примерами тогда вообще тестировщикам сразу научитсья писать нормальный код будет легче простого.

Например:

Этапы обучения: (что после чего необходимо будет изучить, до какого достаточного уровня)

1. Понимание что такое тестирование - тут идут пару самых внятных и коротких ссылок на то где можно посмотреть и почитать.

2. Базовый язык (Джава, СиШарп, скриптовый язык любой) расписать какой достаточный уровень, где лучше и как выучить

3. Фреймворк тестирования (например Junit или TestNG )

4. Фреймворк для веб тестирования - WebDriver - опять же ссылки где коротко и ясно

5. Как правильно это все компоновать чтобы работало - ссылки на идею PageObject и правильное создание логики.

6. Дополнительные полезные вещи: например работа с логерами, подтягивание данных из xml, вывод "красивых" репортов

7. Продвинутый уровень: запуск тестов Jenkins или дру интеграц. сист, а так же работа с SVN

8. Дальнейшее развитие...

Спасибо, хорошо изложено.

1) надо будет поискать, где же данные хранить (реальный кандидат - SQLite: штатный движок доступен; можно работать практически почти только с данными, а не с тем, как их записать/прочитать; есть просмотрщики или можно навеять свой поверх для ручного ввода тестовых данных; это просто файл, его и перенести/передать несложно).

у нас использовался как минимум в паре коммерческих продуктов, как БД для агентов, которые читают наши групполиси.

3) у нас выжатая команда - увольняться разрешают, а нанимать обычно нет :)

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

Но продукт сценарийный: не сделал A, B, C, никогда не будешь в D. Поэтому выяснение приходится делать по мере прогона хоть и не всего, но солидной части кода (а иногда продукт падает сам по себе - устает за два часа :). Это вообще даже автору теста не отловить)

 

Хранение локаторов в пейджобжектах? Да, подумываю об этом. Сейчас это десктопный интерфейс, т.е. локаторы у нас это вилдкарты вида Nex*, Create*collection и т.д. Пока сьюта линейна или, скорее, как граф с основным путем (отошел в сторону, потестировал один или несколько раз, вернулся на основной путь). Локаторы уже очень хочется объединить :) но у нас беда, которой нет у вас (наверное) - буйные шаловливые руки программеров и пруфрид текстов контролов без предупреждения. Давайте назовем это локализацией раз в две недели - проще сразу обобщить. Т.е., в терминах селениума, локаторы в пейджобжектах могут меняться, допустим, раз в две недели.

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

Сразу возникает желание что-то откуда-то подгрузить :) Что говорит мировой и эсэнгешный тестировочный опыт?

Я тоже сторонник идеи того, чтобы локаторы хранить в классе, который описывает Вашу страницу (PageObject Pattern). Вы же описываете методы и переменные (они же - локаторы). Ваши переменные хранятся в одном месте. А по поводу тестовых данных, может стоит попробовать API для работы с XLS? Сам не пробовал, но думаю, что должно работать.

А если локаторы меняются (уж для вэб-сайта локализация очень частый случай)? LinkText, PartialLInkText, возможно, Name (хотя вряд ли), Text.

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

Должен признаться, что с вопросом локализации не сталкивался. А что касается частых изменений, так в этом же и выгода PageObject, что переменная (локатор) хранится в одном месте. Соответственно и  менять ее нужно один раз.

 

Подход с пейджобжектами не новый. И оба подхода: хранилище локаторов в отдельном файле данных, как это делают QTP и Ranorex для десктопа и хранение локаторов в коде вместе с декларацией окна, как это сделано в SilkTest – это два альтернативных пути. 
Я очень долго работал с SilkTest, который для декларации окон предлагал записать класс типа window, в котором отображалась вся иерархия десктопного приложения. При этом window могли наследоваться от базовых классов. Сами элементы находились по так называемому tag, который мог вычисляться динамически. И это было очень круто, потому что туда можно было запихнуть целую функцию, которая бы вычисляла нужное окно из нескольких с одинаковыми заголовками. 
Но, в основном, теги тоже  были похожи на Create*collection. 
Но, потом столкнулись с проблемой локализации, и решили ее при помощи выноса нужных строк в отдельный локализационный файл, следующего вида:
 
Key                         English                    French                     German
Create*collection     Create*collection      Le create*con           Das*conekhtung
 
А в коде выглядело это так:
 
PushButton    CreateConnection
    tag  “{LocalizationFor(“Create*collection”)}”
 
Где функция LocalizationFor возвращала строку на нужном языке, исходя из глобальных настроек проекта. 
Но, где это не требовалось, мы локализацию не использовали и обходились ControlId, который был постоянным. 
 
Что же касается Визардов – то каждую страницу мы описывали как отдельное окно. 
Понятное дело, что шапка, некоторые функции и кнопки Next/Back/Cancel были общими, и находились в базовом классе. 
За логику перещелкивания между страницами отвечали функции-хелперы либо сам тест кейс. 
 

А вот и не один раз - может же быть однотипный компонент на многих страницах. Его-то куда девать? В отдельный класс? Потому что одинаковые изменения в десятке и более классов/файлов - этого хочется никогда не огребать :)

Может, тут тоже можно пронаследовать ( как в силктесте)? Было бы удобно тогда менять в одном месте.

Однотипный компонент? Это что-то вроде одинаковой шапки на каждой странице(Поиск, какой-то тулбар)?

Тогда, я бы вынес эти элементы в суперкласс, а дальше классы-страницы наследовать.

прочел все переписку и хочу сказать, что все зависит от вашей ситуации,

нету правильных подходов, которые подходят всем и всегда

в нашей жизни очень много разных деталей и тонкостей, потому не заморачивайтесь

 

от себя хочу сказать, что когда ваших тестов много (1000 или 2000 :) ) и локаторов для этих страниц еще больше, тогда люди и приходят к мысли отделения локаторов

когда тестов мало, то все что необходимо для теста, удобно хранить в самих тестах

 

что вас должно вас беспокоить, вне зависимости от подхода который вы выбрали, это ваша ЦЕЛЬ - зачем вы это делаете

если все будет сделано через БД или xml файлы, ну пусть так и будет,

главное чтобы вы достигли своей цели, например, возможность пофиксить тест за 1 минуту

а если эта же цель достигается за счет хранения локаторов в исходниках, то зачем тогда тратить лишние ресурсы ?!

ведь их можно потратить на что-то полезное :)

ну и мне лично нравиться хранить локаторы в исходниках, потому что я с ними очень часто работаю :)

а на счет хранения данных, это совсем другая история (можно создать новую тему и по дискусировать)