class MainPageLocators(object): login_line = (By.ID, 'loginName') password_line = (By.ID, 'loginPass') enter_button = (By.ID, 'logButton') worker_button = (By.XPATH, "//span[contains(@class, 'navigation-LeftNavigation__row') and @title='Сотрудники']") x_link = (By.ID, 'ourOrg') our_company_button = (By.XPATH, "//div[@title='Наша компания']") search_name = (By.ID, 'fld-ПоискСотрудникаПоЮрЛицам') record = (By.ID, 'userName409') close = (By.XPATH, "//div[@type='Control/Button' and @sbisname='windowTitleClose']") initial_button = (By.XPATH, "//div[contains(@class, 'username asLink username__link')]") class BasePage(object): def __init__(self, driver): self.driver = driver class MainPage(BasePage): def login(self): element = self.driver.find_element(*MainPageLocators.login_line).send_keys('check_rigth_user') def password(self): element = self.driver.find_element(*MainPageLocators.password_line) element.send_keys('qwerty123') def enter_button_click(self): element = self.driver.find_element(*MainPageLocators.enter_button) element.click() def worker_button_click(self): element = self.driver.find_element(*MainPageLocators.worker_button) element.click() def x_link_click (self): element = self.driver.find_element(*MainPageLocators.x_link) element.click() def our_company_button_click (self): element = self.driver.find_element(*MainPageLocators.our_company_button) element.click() def name_for_search(self): element = self.driver.find_element(*MainPageLocators.search_name) element.send_keys('Белова Олеся Александровна') def record_click (self): element = self.driver.find_element(*MainPageLocators.record) element.click() def close_click (self): element = self.driver.find_element(*MainPageLocators.close) element.click() def initial_click (self): element = self.driver.find_element(*MainPageLocators.initial_button) element.click()
#1
Отправлено 11 ноября 2014 - 20:27
#2
Отправлено 12 ноября 2014 - 08:13
Не очень понятно, какого эффекта хочется добиться (то есть как должен выглядеть по Вашему мнению улучшенный код, но могу предложить два варианта:
1) Не делать методы типа enter_button_click, вместо этого сделать побольше выскоуровневых методов типа login, тем самым работа с элементами будет скрыта в объекте-странице.
Пример такого подхода к проектированию можно посмотреть тут: https://github.com/d...registration.py
2) Описывать элементы не как поля, а как properies
Пример такого подхода к проектированию можно посмотреть тут: описание элементов страницы и использование этих элементов
Тренинги для тестировщиков (тестирование производительности, защищенности, тест-дизайн, автоматизация):
Линейка тренингов по Selenium
#3
Отправлено 12 ноября 2014 - 08:14
Первый вариант - это можно сделать через миксование классов, так будет меньше всего переделок в коде. Узнать более подробно об этом можно по ссылке
from selenium.webdriver.common.by import By from selenium import webdriver class MainPageLocators(object): login_line = (By.ID, 'loginName') password_line = (By.ID, 'loginPass') enter_button = (By.ID, 'logButton') class BasePage(object): def __init__(self, driver): self.driver = driver class MainPage(BasePage, MainPageLocators): def login(self): element = self.driver.find_element(*self.login_line).send_keys('check_rigth_user') def password(self): element = self.driver.find_element(*self.password_line) element.send_keys('qwerty123') def enter_button_click(self): element = self.driver.find_element(*self.enter_button) element.click() page = MainPage(webdriver.Firefox()) print page.driver print page.login_line print page.login
Ну а во вторых, почему бы не соединить локаторы и действия в один класс ?!
from selenium.webdriver.common.by import By from selenium import webdriver class BasePage(object): def __init__(self, driver): self.driver = driver class MainPage(BasePage): login_line = (By.ID, 'loginName') password_line = (By.ID, 'loginPass') enter_button = (By.ID, 'logButton') def login(self): element = self.driver.find_element(*self.login_line).send_keys('check_rigth_user') def password(self): element = self.driver.find_element(*self.password_line) element.send_keys('qwerty123') def enter_button_click(self): element = self.driver.find_element(*self.enter_button) element.click() page = MainPage(webdriver.Firefox()) print page.driver print page.login_line print page.login
Практикующий консультант по автоматизации тестирования ПО и тренер
Портал по автоматизации тестирования ПО http://automated-testing.info
Онлайн обучение автоматизации тестирования http://lessons2.ru
Персональные консультации и менторинг SDConsulting
Личный сайт http://poliarush.com
#4
Отправлено 12 ноября 2014 - 08:51
Миша, не нужно публиковать скрытую рекламу как ссылки на якобы информационные материалы. Пиши честно -- "про это я рассказываю в своём тренинге, вот тут". За скрытую рекламу буду наказывать.
Тренинги для тестировщиков (тестирование производительности, защищенности, тест-дизайн, автоматизация):
Линейка тренингов по Selenium
#5
Отправлено 12 ноября 2014 - 12:56
Не очень понятно, какого эффекта хочется добиться (то есть как должен выглядеть по Вашему мнению улучшенный код, но могу предложить два варианта:
1) Не делать методы типа enter_button_click, вместо этого сделать побольше выскоуровневых методов типа login, тем самым работа с элементами будет скрыта в объекте-странице.
Пример такого подхода к проектированию можно посмотреть тут: https://github.com/d...registration.py
2) Описывать элементы не как поля, а как properies
Пример такого подхода к проектированию можно посмотреть тут: описание элементов страницы и использование этих элементов
Спасибо Вам и Михаилу. А не могли бы вы посмотреть код самого теста и подсказать, что в нем можно изменить или добавить. Стоит ли разбивать метод test_new на отдельные мини-тесты (методы) или оставить один? Как лучше выполнять проверки assert (правильно ли я их сделал)? Правильно ли организована работа с ожиданиями или лучше применять Implicit waits?
class main(unittest.TestCase): def setUp(self): self.driver = webdriver.Firefox() def test_new(self): self.driver.get('https://fix-inside.tensor.ru') main_page = MainPage(self.driver) main_page.login() main_page.password() main_page.enter_button_click() #нажимаем кнопку Войти #при переходе на главную страницу ждем загрузку таблицы новостей try: news = WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, "table.news-PreprocessorNews-main_page"))) except: pass assert 'news', "Переход на стартовую страницу отменен" #нажимаем на ссылку Сотрудники main_page.worker_button_click() #при переходе по ссылке Сотрудники ждем загрузку полей с именами сотрудников try: worker_table = WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, "div.ws-relativegrid-cellwrapper ws-relativegrid-firefox_100_height"))) except: pass assert 'worker_table', "Переход в раздел сотрудники не состоялся" #кликаем по ссылке в шапке страницы main_page.x_link_click() #при переходе по ссылке ждем загрузки формы (локация по селектору - строчный элемент "Выберите организацию") try: form_open = WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, "span.ws-float-area-title-style"))) except: pass assert 'form_open', "Форма не открылась" #Выбираем "Наша компания" main_page.our_company_button_click() #assert #Ищем сотрудника Белова Олеся Александровна main_page.name_for_search() #Ждем появления ссылки с фамилией запращиваемого сотрудника try: record = WebDriverWait(self.driver, 5).until(EC.presence_of_element_located((By.CSS_SELECTOR, "div.ws-ellipsis listEmpl-fio"))) except: pass assert 'record', "Запись не найдена" #Кликаем на записаь в таблицу main_page.record_click() #при открытии формы ждем ее полной загрузки и появления локатора - строчного элемента "Белова" try: card = WebDriverWait(self.driver, 5).until(EC.presence_of_element_located((By.CSS_SELECTOR, "span.ws-editAtPlace-inner"))) except: pass assert 'card', "Карточка не открылась" #Закрываем форму, крестик пропадает main_page.close_click() assert 'card', "Карточка не закрылась" #кликаем на ссылку с инициалами main_page.initial_click() #открывается меню со ссылками на другие разделы сайта try: menu = WebDriverWait(self.driver, 1).until(EC.presence_of_element_located((By.ID, "adminlinks"))) except: pass assert 'menu', "Меню не открылось" #main_page.quit_button_click() quit_click = WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, "#headerLeft > div.big.auth > div.log > div"))) quit_click.click() #проверка выхода с сайта по локации кнопки Вход try: last_check = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, "logButton"))) except: pass assert 'ast_check', "Выход не удался" #def tearDown(self): # self.driver.close() if __name__ == "__main__": unittest.main()
#6
Отправлено 12 ноября 2014 - 13:31
Почему маленькие авто-тесты лучше, чем большие?
1) Из отчёта сразу видно, что работает, а что нет (особенно если тестам дать хорошие имена)
2) Если один тест упал -- у остальных есть шанс отработать, так что за один проход мы получаем больше информации
3) При разработке (при отладке) или при воспроизведении сбоя проще работать с маленьким тестом
4) Можно мелкие тесты произвольным образом группировать, распараллеливать, в общем, как-то управлять тестовым набором
Разумеется, если у вас сложный сценарий, который на мелкие не разбивается -- тогда вопрос лишён смысла. Но везде, где можно разбить -- стоит это сделать.
Однако не следует впадать в противоположную крайность. Иногда советуют придерживаться правила "в одном тесте одна проверка", и тогда, например, если нам надо в какой-нибудь форме проверить, что пять полей являются обязательными -- надо делать пять отдельных тестов. Вовсе нет. Проверок в тесте может быть и несколько. Важно постараться не дублировать сценарии (действия).
Но даже в случае большого сценария, конечно, код стоит декомпозировать, выделить небольшие вспомогательные методы (не тестовые, а обычные), и в тесте обращаться к этим методам.
То есть этот длинный тестовый метод мог бы выглядеть так:
def test_new(self): main_page = self.openMainPage() main_page.login("admin", "password") workers_page = main_page.open_workers_page() workers_page.open_search_form() workers_page.select_organization("Наша компания") workers_page.search_worker("Белова Олеся Александровна") worker_page = workers_page.open_worker_card(0) # открываем первую из найденных карточек workers_page.close_search_form() worker_page.open_menu() main_page.logout()
а все подробности скрыты во вспомогательных методах. И тогда тестовый метод легко читать и понимать, даже никаких комментариев в коде не надо.
Тренинги для тестировщиков (тестирование производительности, защищенности, тест-дизайн, автоматизация):
Линейка тренингов по Selenium
#7
Отправлено 12 ноября 2014 - 14:45
Как лучше выполнять проверки assert (правильно ли я их сделал)? Правильно ли организована работа с ожиданиями или лучше применять Implicit waits?
1. Во-первых, сейчас Ваши проверки не проверяют ничего :)
Потому что, например, вместо
assert 'menu'
нужно было бы написать
assert menu
Если это понятно -- можно двигаться дальше.
2. Автотесты обычно пишутся исходя из предположения, что они большую часть запусков будут успешными, поэтому перехватывать каждое исключение особого смысла нет. Упадут -- будем разбираться. Видно же, в какой строчке упало. Иными словами, вместо
try: menu = WebDriverWait(self.driver, 1).until(EC.presence_of_element_located((By.ID, "adminlinks"))) except: pass assert menu, "Меню не открылось"
можно написать просто
menu = WebDriverWait(self.driver, 1).until(EC.presence_of_element_located((By.ID, "adminlinks")))
Да, отчёт будет чуть менее красивым (без пояснения "Меню не открылось"), но если это всё упадёт во вспомогательном методе, который называется, скажем, openMenu -- и так будет понятно, что меню не открылось.
3. Ожидания нормальные, тут всё в порядке, но если Вы везде используете только presence_of_element_located -- тогда может быть и правда стоит перейти на использование неявных (implicit) ожиданий.
Тренинги для тестировщиков (тестирование производительности, защищенности, тест-дизайн, автоматизация):
Линейка тренингов по Selenium
Темы с аналогичным тегами python selenium webdriver
Тестирование →
Автоматизированное тестирование →
can't access dead objectАвтор Alex_Alex, 03 авг 2019 python selenium webdriver |
|
Количество пользователей, читающих эту тему: 0
0 пользователей, 0 гостей, 0 анонимных