Тест на проверку наличия всех элементов на странице.

Добрый день всем!

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

Дано:

Веб - приложение.

Пользовательские сценарии на языке Gherkin с помощью Specflow.

Тесты - пишутся на С# с помощью Selenium Web Driver, используют Page Object pattern и Page Factory,  выполняются с помощью MSTest.

Вопросы:

1. Требуется реализовать тест, проверяющий наличие всех элементов на странице.

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

В результате выполнения теста все эелементы могут быть равны, или на текущем окне были добавлены/удалены элементы, что сигнализирует о том что есть баг (или фича:)).

Как с помощью Веб Драйвера реализовать подобный тест? Что посоветуете? Нет ли у Веб Драйвера возможности сравнивать элементы "на лету".

2. Каким образом в Ваших тестах организована обработка исключений: генерируются встроенные или Ваши кастомные исключения? Как в таком случае организовать логирование результатов тестов?

Заранее благодарен всем за ответы!

 

 

 

1. проверки всех элементов на странице, такой функциональности нету

увы ее надо будет реализовывать самому, 

как это сделать? у вас же есть ваши локаторы, где-то описанные, так вот вы можете 

вы можете вопспользоваться интроспекцией или рефлексией (например, ссылка) объектов, для того чтобы вытащить сами локаторы,

а ну а дальше нужен просто метод, который запустить все найденные локаторы на странице и выдаст соответствующий результат 

 

2. в завимости от потребностей

например я зачастую пользуюсь только встроенными exception

но переопределить свои exception из стандартных не составляет особо труда и вызывать нужные вам exception

ну а логгирование это отдельная тема, создавайте новую тему :)

Интересно, а зачем ВСЕ проверять? Насколько я заметил, хром, к примеру, может обрасти тулбарами, кнопками ипр. барахлом  и тогда кол-во элементов может не совпасть с кол-вом у лиса. Я наблюдал это на довольно простых html'ках, разное общее число элементов.

Как собрать все элементы? Самый простой, но не быстрый способ - собрать по tagName = * или XPath = //* (обсуждали здесь: http://automated-testing.info/forum/kak-sdelat-vyborku-vsego-vsego )

 

Интересно, надо будет поизучать этот силктест - за два дня вторая интересная инфа о нём. В UIAutomaiton мы делаем так (показан дефолтный аутпут, можно дампить хоть хэндлы с пидами, что, конечно, имеет смысл только пока программа запущена :):

 

PS C:\Users\shuran> Start-Process calc -PassThru | Get-UIAWindow | Get-UIAButton | ConvertTo-UIASearchCriteria
@{Name="Memory clear";AutomationId="122";ControlType="Button";}
@{Name="Backspace";AutomationId="83";ControlType="Button";}
@{Name="7";AutomationId="137";ControlType="Button";}
@{Name="4";AutomationId="134";ControlType="Button";}
@{Name="1";AutomationId="131";ControlType="Button";}
@{Name="0";AutomationId="130";ControlType="Button";}
@{Name="Memory recall";AutomationId="123";ControlType="Button";}
@{Name="Clear entry";AutomationId="82";ControlType="Button";}
@{Name="8";AutomationId="138";ControlType="Button";}
@{Name="5";AutomationId="135";ControlType="Button";}
@{Name="2";AutomationId="132";ControlType="Button";}
@{Name="Memory store";AutomationId="124";ControlType="Button";}
@{Name="Clear";AutomationId="81";ControlType="Button";}
@{Name="9";AutomationId="139";ControlType="Button";}
@{Name="6";AutomationId="136";ControlType="Button";}
@{Name="3";AutomationId="133";ControlType="Button";}
@{Name="Decimal separator";AutomationId="84";ControlType="Button";}
@{Name="Memory add";AutomationId="125";ControlType="Button";}
@{Name="Negate";AutomationId="80";ControlType="Button";}
@{Name="Divide";AutomationId="91";ControlType="Button";}
@{Name="Multiply";AutomationId="92";ControlType="Button";}
@{Name="Subtract";AutomationId="94";ControlType="Button";}
@{Name="Add";AutomationId="93";ControlType="Button";}
@{Name="Memory subtract";AutomationId="126";ControlType="Button";}
@{Name="Square root";AutomationId="110";ControlType="Button";}
@{Name="Percentage";AutomationId="118";ControlType="Button";}
@{Name="Reciprocal";AutomationId="114";ControlType="Button";}
@{Name="Equals";AutomationId="121";ControlType="Button";}
@{Name="Minimize";AutomationId="Minimize";ControlType="Button";}
@{Name="Maximize";AutomationId="Maximize";ControlType="Button";}
@{Name="Close";AutomationId="Close";ControlType="Button";}
 
После этого эти самые сёрч крайтириа можно использовать в командлете Test-UIAControlState -SearchCriteria @{...},@{...},@{...},@{...},@{...},...
Как видите, на вход подаётся точно то же самое, но через запятую (массив хэштаблиц). На выходе - True или False.
На самом деле, гораздо лучше использовать Wait-UIAControlState -SearchCriteria @{...},@{...},@{...},@{...},@{...},...
Она делает точно такую же проверку, но регулярно на протяжении всего таймаута.
Подобные командлеты позволяют не заботиться о моменте отрисовки окна, они сами дождутся, таймаут лишь поставьте достаточный.
 
Вернёмся к вэб-дровам.
Драйвер может выдать все элементы (их положение и размеры, если это надо - но надо ли?). насколько я понимаю, вам это нужно для каких-то узких целей, потому что обычные сайты не обязаны быть всегда одинаковыми: баннеры, имя залогоненного юзера, всякие рюшечки под юзера, даже скины бывают. Разве что вэб-консоли разных железяк или админских продуктов, да и то - имя юзера наверняка Я бы посоветовал делать выборочный список - к примеру, выбрать элементы нескольких тэгов и достаточно.
 
Вообще тема интересная, не удивлюсь, если скоро появятся командлеты ConvertTo-SeSearchCriteria, Test-SeControlState и Wait-SeControlState.
 
Кстати говоря, есть ведь другой путь, и он даже может быть быстрее: сохранение в файл и сравнение файлов. Все браузеры поддаются автоматизации через UIAutomation (я про меню, странички-то как раз не поддаются во многих браузерах) или MS UI Automation, white, etc (на заметку: etc - это самый большой список тестировочных фреймворков в мире, упоминается чаще всего. Объединяет столько фреймворков, что все даже затрудняются их назвать).
Так вот, сохраняете страничку и сравниваете с сохранённой в прошлый раз. Утилиты fc, diff, etc (да, они тоже) проверены миллионами пользователей (без шуток!) и работают очень быстро.

О, я сразу не заметил - вы ведь пользуетесь MSTest'ом? Эта такая штуковина, которая отличается от NUnit только названиями атрибутов (я где-то видел пошаговую инструкцию по автозаменам для превращения кода под NUnit в код под MSTest - интересно, зачем?).

Так вот, в NUnit есть сравнение упорядоченных коллекций:  Assert.AreEqual(object1, object2);

Я это использую для тестов типа: что-то пощёлкать по форме или  по страничке и получить строки или объекты (лэйбл меняет текст по клику и т.д.) и сравниваю коллекцию результатов и коллекцию заготовленную как два объекта (сам не знаю почему, метод такой написался).

Так вот, в одном и том же браузере наверняка порядок лементов не изменится между билдами. Собираете все элементы с сайта и собираете вторым или этим е драйвером все элементы со вчерашней страницы. И кидаете в MSTest  две коллекции.

Можно при помощи рефлексии вытянуть все филды типа By PageObject'a, и записать в какой-нибудь List. Потом пройтись по списку при помощи findElement и как-нибудь пометить несуществующие локаторы.

По поводу исключений... Делать красивенькие обработчики эксепшенов, которые вместо стек трейса выведут мне что-то типа "у вас неправильный локатор" - ну их нафиг, такие обработчики. По сути, кроме нас, никому эти логи даром не нужны. Так что я предпочитаю хэндлить стандартными способами и изучать проблему по стек трейсу. Кстати, злоупотреблять try / catch я бы тоже не рекомендовал, если дорожите производительностью.

Огромное спасибо за ответы.

Много почерпнул из них нового и того, что следует перечитать/попробовать еще раз.

По поводу моего вопроса о проверке всех элементов:

Самый простой случай (и самый крайний) - это просто создание списка элементов  - с помощью XPath запроса - FindElement(By.Xpath(" //* ");

В таком случае логика теста будет состоять в том, чтобы сравнить поочередно каждый обьект expected страницы и каждый обьект actual страницы с помощью Assert.AreEqual();

Но возникает небольшой вопрос - как и где хранить исходную коллекцию элементов, с которой потом сравнивать страницу при тестировании?

Заранее очень благодарен за советы. .

А если не хранить? Допустим, передвигать старую версию вэб-сервака на другой порт (или хост), новый накатывать на традиционный порт (или в тесте задавать "хост старой версии" и "хост новой версии"), и сравнивать двумя драйверами прямо с серверов.

 

Иначе вам или придётся делать свой сераилизатор/десериализатор (на диск, в XML, в БД - это я фигурально выразился про сериализацию), или, если это возможно - возможно сохранить странички без потерь работоспособности, сохраняйте странички средствами браузера.

Насколько я заметил, драйвер (хм, скорее, браузер это делает) хорошо воспринимает пути в файловой системе и сам преобразует c:\1\2\3.htm в file:///c:/1/2/3.htm.

Мысль про сравнивание элементов двумя драйверами(на разных хостах или энвайроментах)  очень хороша.

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

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

Пока что стандартными способами вижу только вариант чтобы брать ПейджСорс двух версий страницы, сравнивать по строково - так проверяем  - не добавились/модифицировались ли страницы. (Очень сомневаюсь в правильности такого подхода).

Проверку наличия необходимого минимума элементов думаю выполнять через создание массива тех же икспасов для каждой страницы - и при запуске теста эти икспасы будут подставляться в ФайндЕлемент и будет происходить проверка чтоб каждый вебэлемент возвращал положитетельный результат от element.IsDisplayed.

Дорогие друзья, а делаете ли вы проверку всех элементов - и вообще целесообразно ли ее делать?  

Совсем забыл - а как Вы в своих  Смоук тестах определяете что добавлено нечто новое после добавления новой фичи и т.д. ? И нужно ли писать такие тесты ? 

 

Про "как": наверное, это ссылка на драйвер мешается, ссылка на драйвер1 не равна ссылке на драйвер 2.

Это вам не пауэршелл, где несколькими буквами (не строками, буквами: $webElement | FL property1,property2,... ) можно получить объекты без лишних пропертей. :) Тут надо ручками всё это счищать (или использовать Linq).

 

Ладно, есть ещё средство: testapi.codeplex.com -> object manipulation

(я пока это только читал, но очень хочу заимплементить в свои фреймворки, просто руки не дошли)

Это сравнение объектов, оно репортит, какие поля не совпали и можно это настроить в некоторыъх пределах. Дока на проекте (читая примеры, это кажется очень просто. Надеюсь, так и есть), есть ещё блог Ivo Manolov, там тоже примеры есть (только пару версий назад).

 

Не могу ответить по поводу нужности. Нам нужно вот что: при прогоне теста сохранять слепок окна (страницы, и т.д.н - неважно, всё унифицировано) и анализировать ДО теста - а стоит ли и тест-то проводить? или сразу красным покрасить :)

Идея такая: в БД лежат константы типа Create*llection, nex*, и т.д. Тест, доходя до окна (страницы, чего-угодно, что имеет отражение в БД), берёт из БД эти константы и примеряет на окно (страницу). Если "лезет" - тест идёт. Если нет - три красных свистка.

(сейчас, я чаю, налетят умные люди и скажут, что в туле X это реализовано и как это реализовано - буду рад, а то я доку этих платных тулов не читаю. Недавно нашёл в инете народный учебник по силктесту - так там такая продукт-ориентированная муть, что без продукта не разберёшься:)),

Добавлено новое или изменилось старое? А это ведь мысль! В продолжение моего соседнего поста: анализировать, что найдено и сравнивать со слепком окна/страницы в БД - и тут как раз сравнением коллекции и всех объектов выносить вердикт.

Слепок страницы - это хорошая вещь. Как вы его в получаете и в БД сохраняете? И в каком виде он представлен?

Просто хотелось бы получать в идеале файл с описанием всех элементов слепка. Потом таким же образом получать слепок страницы из текущего теста и поэлементно/построчно сравнить.

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

Что-то мне кажется, что идея сравнивать через вэб-драйвер бесперспективна.

Достаточно посмотреть на список элементов http://www.w3schools.com/html5/tag_comment.asp , а потом на список атрибутов для каждого (а ведь, по-хорошему, надо сравнивать и эвентные атрибуты тоже) - это ж сколько оно будет работать.

имхо проще взять $driver.PageSource и ступенчато сравнивать: если совпал html, то равны, если не равны, сравнивать head, body, и т.д. вглубь.

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

К примеру, если есть разница в строке, бежать влево-вверх, искать знак "меньше" и брать его тэг, и репортить. Ну а дальше или так репортить, или парсить вглубь.

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

 

На данный момент я проверяю наличие необходимых элементов на странице так:

Есть текстовый файл в котором описаны ИксПас запросы к ожидаемым элементам.

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

Вариант конечно слегка затратный - к тому же если были добавлены новые элементы на страницу - тест этого не определит.

 

Скрипты - разве не те же элементы в тэгом script? Иил речь про скрипты, которые лежат в отдельных файлах?

А икспасы вы генерите как-то или это ручная подборка?

а почему вообще возникла тема сравнения страниц

ведь это затратно по времени и не целесообразно в разработке

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

Меня это интересует, прежде всего, со стороны GUI-приложений - вот пример:

сейчас у нас богатое на визарды виндоус-приложение.

Если окно визарда не появилось (баг в визарде, баг раньше, приложение упало и т.д.), то тесты не будут идти сильно медленнее - вместо дефолтного таймаута 5 секунд по отсутствию окна выставится таймаут 2 секунды. Тест будет искать каждый контрол, но с меньшим таймаутом.

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

Что тут делать? не хочется ведь, чтобы тест лупил по каждому контролу по 5 секунд, как какой-нибудь тесткомплит :)

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

 

Решение видится такое: 0) однажды запопулировать эти данные в БД, конечно, полуавтоматически 1) автоматически собирать каждый экран (в случае гуёвого приложения это почти всегда быстрее вебдрайвера, хотя и не всегда) и сравнивать с набором контролов в БД

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

Получается, что сравнение экранов поможет избежать таймаутов (по умолчанию, 5 секунд на контрол) и ускорит тест в случае проблемы, а не замедлит. Т.е., в случае проблемы тест подзамедлится, но не сильно. :)

 

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

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

Я уверен, что много элементов не автотестируются именно потому, что там ничего не надо нажимать. А тут - автосравнение, явно ведь не хуже дело будет, если добавить ещё и автосравнение.

А НАСКОЛЬКО важна скорость тестов? Селениум используют как юнит-тестовый движок? имхо зависит от организации труда - где-то надо каждые десять минут или полчаса прогонять полную сьюту тестов, а где-то разработчики текущую работу проверяют прямо в редакторе, а весь сайт крутится по другому расписанию. Или я не так это понимаю?

 

А если кто боится, что от теста к тесту браузер запускается разного размера (окно) и размеры и/или положение элементов "поедут", так это поправимо:

Start-SeFirefox | ConvertTo-SeAutomationElement | Invoke-UIAWindowTransformResize -TransformResizeWidth 500 -TransformResizeHeight 200