В автоматизированном тестировании начал разбираться недавно.
Есть проект на Ruby, для написания тестов используется webdriver, cucumber, capybara.
Насколько критично использование page object-а?
Абсолютно не критично, это просто удобный инструмент ))).
Все зависит от подхода и предпочтений
Не критично, пока у вас до ~20-30 тестов. Правда, смотря каких по количеству степов и сложности.
Ну или до серьезных изменений в апликухе)
В том-то и дело, что тестов будет много, но изменения вряд ли будут глобальные, проект работает…
Есть у кого-то опыт использования аналогичных инструментво без page object-а на большом проекте?
Паттерны придумали не просто так. Вы то конечно можете их и не использовать. Но рано или поздно появится вероятность наткнуться на некий архитектурный блокер, который приведет к тому, что вы начнете изобретать свой собственный велосипед. Начав его причесывать со всех сторон, через время обнаружится, что ваш велосипед уж больно что-то напоминает:
`- А не PageObject ли это?
- Тю, а почему я раньше его не использовал? - произнесете вы, хватаясь за голову и жалея о потраченном времени.`
В целом, вас никто не заставляет использовать этот паттерн в чистом виде. Вы можете чем-то пренебречь. Но ключевым аспектом тут является как раз таки сама модель представления реальных вэб-страницы и их компонентов.
Если не сложно, приведите пример архитектурного блокера, пусть даже некий гипотетический, чтобы я смог критично взглянуть на проект и найти что-то подобное
Если вы не используете модель пейджей, то возникает вопрос организации структуры вашего проекта в целом.
У вас есть тестируемый сайт. При этом, вам нужно каким-то образом описать его доменную составляющую. Зачем это нужно? Чтобы в последствии тратить минимум усилий на саппорт ваших тестов, ровно как и ускорить процесс девелопмента.
Итак, вы отказались от PageObjects. Где и как будете хранить локаторы? В один файл все спихнете? Как будете бороться с дублированием кода, если функционал реальных страниц будет технически почти идентичен? Как будете логически связывать последовательность ваших степов между собой? Статические вызовы? Как будет организована связь с webdriver’ом? Будете напрямую из методов вызывать driver.findElement...
или вынесете в отдельный класс? Чем тогда по отношению к остальным классам будет являться ваш новоиспеченный с точки зрения ООП? Тут главный вопрос в том, сколько времени вы потратите на построение другого архитектурного решения, и как это будет влиять на вашу повседневную работу.
У меня есть опыт построения большого проект без пэдж обжектов. Проблем никаких. Проект активно развивается больше трёх лет, всё постоянно меняется и дописываются новые тесты. Никаких архитектурных блокеров мы не встречаем.
Правда, мы используем библиотеку Selenide, и поэтому нам не приходится ломать голову над тем, откуда и куда передавать вебдрайвер.
Конечно же, вы можете обойтись без пейджобжектов.
Пейджобжекты – это не сама цель, а инструмент, который делает код более “прочным” и поддерживаемым
Вместо того, чтобы убеждать о том, как важны Пейджобжекты, давайте вначале рассмотрим пример (на псевдокоде)
Черный цвет кода:
driver.findElement(By.XPath("//*[contains(@class, 'container')]/div[2]//button[5]")).Click();
driver.findElement(By.XPath("//*[contains(@class, 'container')]/div[2]//button[15]")).Click();
driver.findElement(By.XPath("//*[contains(@class, 'container')]/div[2]//button[5]")).Click();
driver.findElement(By.XPath("//*[contains(@class, 'container')]/div[2]//button[6]")).Click();
assert(driver.findElement(By.XPath("//*[contains(@class, 'container')]/div[1]"))).Text, "6");
попро- ____
буйте ____
уга- ____
дать ____
что те- ____
сти- ____
рует ____
этот ____
код ____
пока ____
чита- ____
ете ____
этот ____
текс ____
Ну хорошо, давайте теперь немного видоизменим сам код и разбавим его переменными:
Темно-серый цвет кода:
// ARRANGE
var btnThree = driver.findElement(By.XPath("//*[contains(@class, 'container')]/div[2]//button[5]"));
var btnPlus = driver.findElement(By.XPath("//*[contains(@class, 'container')]/div[2]//button[15]"));
var btnEq = driver.findElement(By.XPath("//*[contains(@class, 'container')]/div[2]//button[6]"));
var txtResult = driver.findElement(By.XPath("//*[contains(@class, 'container')]/div[1]")));
//ACT
btnThree.Click();
btnPlus.Click();
btnThree.Click()
btnEq.Click()
// ASSERT
assert(txtResult.Text, "6");
Поставьте лайк под этим комментарием, если вы подумали, что этот код тестирует калькулятор.
Если мы планируем писать больше тестов для калькулятора, то логично было бы вынести все это в отдельную функцию, которая бы принимала два числа на вход и возвращала бы результат сложения.
Чтобы не появилась мысль, что вы можете упростить задачу и подставить нужно число в индексы XPath, я скажу, что у каждого ряда кнопок свой уникальный xpath.
А кнопки “3”, “4”, “5” на самом деле в DOM модели документа идут как “5”, “3”, “4” и средствами CSS и
JavaScript позицинируется в нужном порядке при рендеринге HTML страницы.
Я это к тому, что для каждой кнопки вам нужено найти уникальный локатор.
Давайте назовем эту функцию addNumbers(operand1:int, operand2:int) : int
Серый цвет кода
function addNumbers(operand1:int, operand2:int) : int {
var btnOne = ... ;
var btnTwo = ... ;
var btnThree = driver.findElement(By.XPath("//*[contains(@class, 'container')]/div[2]//button[5]"));
...
var btnNine = ...
var btnPlus = driver.findElement(By.XPath("//*[contains(@class, 'container')]/div[2]//button[15]"));
var btnEq = driver.findElement(By.XPath("//*[contains(@class, 'container')]/div[2]//button[6]"));
var txtResult = driver.findElement(By.XPath("//*[contains(@class, 'container')]/div[1]"));
switch (operand1) {
case 1: btnOne.Click();
break;
case 2: btnTwo.Click();
break;
...
}
btnPlus.Click();
// Ugly copy-paste
switch (operand2) {
case 1: btnOne.Click();
break;
case 2: btnTwo.Click();
break;
....
}
btnEq.Click();
return convert.toInteger(txtResult.Text);
}
Поставьте лайк если вы подумали что я наговнокодил. Если вы уже ставили лайк, то не снимайте его.
Ну да, у этого кода много недостатков. Во-первых, он поддерживает сложение только одноразрядных чисел.
Во-вторых, эти btnOne Two Three вообще нужно в нормальный человеческий массив вынести, и копипаст в switch…
Тем не менее, тест теперь выглядит вот так:
var result = addNumbers(3, 3);
assert(result, 6);
А теперь давайте подумаем, куда лучше положить эту addNumbers
.
А почему бы не в класс SimpleCalculator?
var calcPage = new SimpleCalculator();
calcPage.Open();
var result = calcPage.addNumbers(3, 3);
assert(result, 6);
Таки получился PageObject… потому что, в первую очередь PageObject определяет действия над конкретной страницей.
Внутри addNumbers
есть куча деклараций элементов, которые, я уверен, вы будете использовать для нового метода subtractNumbers
, почему бы их не вынести и сделать полями класса SimpleCalculator?
Тогда любой метод внутри класса сможет работать с общими декларациями элементов.
Использовать или не использовать пейджобжекты – это не бинарное понятие. Ваш код будет еволюционировать и в итоге вы все равно придете к пейджобжектам. Но, это в том случае, если планируется развитие кодовой базы проекта автоматизации, добавления новых автоматизаторовю Если это проект на 30 тестов, который вы не планируете поддерживать – то SeleniumIDE – лучший выбор (там нет PageObject, а записанные тесты не жалко выбросить).
Если функция addNumbers нужна во многих тестах, то я действительно вынес бы этот код в отдельную функцию. Но вовсе не обязательно делать из этого ПэджОбжект. Это нормальная практика переиспользования кода, это не какой-то уникальный только для тестирования паттерн.
Но я очень хочу подчеркнуть, что тестировать множество комбинаций чисел и операций через UI - плохая идея. Комбинации надо покрывать юнит-тестами, а UI-тестов должно быть мало, и они должны покрывать один-два базовых сценария. Тогда вам и не понадобится выстраивать ракеты из пэдж обжектов.
Без пейдж объектов ты обрекаешь себя на муки и страдания. Делай изначально правильно и все будет хорошо
Голословно. Мы не используем пэдж обжекты и живём прекрасно.
В таких случах, когда человек не имеет большого опыта, лучше учить писать правильно, с пейдж обжектами и всеми делами. Я имею дело со студентами, им если сказать что можно писать без этого и этого, то потом получается адская кухня из спегетти кода
Почему PageObject не всегда нужны? Выскажусь и я.
Вот скажем, тестирую я приложение под windows 7. И build validation tests, как и функциональные тесты, включают в себя работу с множеством окон. Окна эти по своему содержимому - не однородны, они содержат разные контролы, они различны также и по объему логики в каждом диалоговом окне. Где-то - это проходное окошко, где нужно ввести чекбокс и указать путь. А где-то: это панель с кучей данных в таблице.
Паттерны тем и хороши, что их можно употреблять, а можно и нет. Например, такая всем известная вещь, как визард виндоус, имеет внутри себя 2-3 кнопки. Для теста важно, что я точно знаю, что оказался в нужном окне на нужном шаге и нажал 1 из 3 кнопок. Пейдж объекты хороши в вебе, где контекст можно легко воссоздавать, например, за счет просто переданного POST запроса с JSON, который должным образом тебя к работе с конкретным PageObject и вернет. Мне кажется, что это - фундаментальная важность ПейджОбъектов - то, а) работа в них заключает большой(или потенциально большой) функционал, наличие контролов, методов и проч. б) при тестировании ПейджОбъекта можно будет на него попасть, принимая преимущества REST протокола и того, что в вебе по сути можно дойти до нужного состояния Сценария не используя автоматизацию.
В ОС контекст приходится либо дольше создавать, либо не бросать его. И во втором случае как по мне PageObjects - лишнее нагромождение, затратное по времени.
А давайте сформулируем более общим образом:
Кто не видит необходимости в декомпозиции тестовой логики и интерфейса взаимодействия с исследуемым объектом?
Немного запутанно…
Но…
- REST и JSON к пейджобжектам не имеют отношения
- Представьте, что вы тестируете Single Page App, которое делалось для ентерпрайза. Так вот, роутинг (изменение URL в зависимости от состояния приложения) – это опциональная фича фреймворка на котором оно делалось, следовательно, чтобы добраться до n-й страницы, скрипту и пользователю нужно прокликать с первой.
- В BorlandSilktest, с которого начался мой путь автоматизитора, есть понятие декларации окна как объекта в коде. Это аналог PageObject. Мы декларировали и это очень помогало не утонуть в коде. Этот подход можно использовать для всего где есть UI.
- Да, фактически декларация PageObject будет отнимать время вначале. Чтобы сократить его я работаю над инструментом SWD Page Recorder. В случае поддержки и поиска ошибки в коде, за счет правильной архитектуры (это не только PageObject), вы можете сэкономить намного больше времени.
Да, но куда вынести эту функцию? Utils.java? В базовый класс?
А что если у нас есть еще логарифмический калькулятор на соседней странице и у него тоже должен быть addNumbers ?
Это (калькулятор) вымышленный пример. Есть разные ситуации, в которых использование юнит тестов или даже интеграционных может быть либо нереальным либо сложным. Я не говорю что это самое правильное решение, но хочу сказать что это в некоторых ситуациях может быть единственным решением.
Некоторые ситуации – это большие Legacy проекты, в которых можно найти код на фортране, который генерирует javascript из xslt; этот сгенерированный javascript вставляет IFRAME с SQL запросом в URL для отображения дополнительной информации. Переписать по человечески – значит потратить 3 года чтобы добится результата который есть сегодня.
Только не надо придраться, XSLT был лучшим шаблонизатором вначале 21-го века.
Из того, что вы говорите, следует, что пэдж обжекты действительно иногда полезны - когда в проекте технологии 90х, когда локаторы громоздкие, когда нет юнит-тестов, когда до разработчиков не достучаться. Вот поэтому не надо учить этому молодых, называя “хорошей практикой”.
Изначальный вопрос был - можно ли обойтись без пэдж обжектов. И мой ответ - прекрасно можно, там, где процесс разработки налажен грамотно.
[quote=“asolntsev, post:18, topic:7601”]
И мой ответ - прекрасно можно, там, где процесс разработки налажен грамотно.
[/quote]А вы писали когда-нибудь UI тесты в black_box_mode на проекте, где “процесс разработки налажен не очень грамотно”?
А видели тесты “молодых” на подобных проектах? Саппортили их?
Так может стоит перестраховаться и таки называть это “хорошей практикой”?
И расшифруйте понятие “грамотно” - это когда ты “сам на кодил сам натестил”? Топикстартер явно не из этой категории.
[quote=“asolntsev, post:18, topic:7601, full:true”]
Из того, что вы говорите, следует, что пэдж обжекты действительно иногда полезны - когда в проекте технологии 90х
[/quote]Может тогда ответите на
В данном контексте грамотно - это когда разработчики пишут юнит-тесты и сотрудничают с тестировщиками, совместными усилиями делая приложение легко тестируемым. Среди прочего это означает читаемые локаторы и эмуляторы внешних сервисов. Тогда в тесте проще использовать локатор, чем городить пэдж обжект.
Вредный вопрос. Идея красивая, я согласен. Но полезнее спросить: какую проблему мы решаем? Какую реальную проблему решает эта декомпозиция? Если разобраться, ту самую проблему неэффективного процесса разработки. И не решает, а прячет.
Я понимаю, это нужно. В большинстве компаний процесс именно такой. Локаторы плохие, разработчики в Индии, юнит-тестами и не пахнет. Это данность, ничего не поделаешь. Просто не говорите молодым, что это хорошая практика.