SlideShare a Scribd company logo
1 of 75
План доклада
● Вводное слово, о проекте, цели
● Что такое WinAppDriver
● Напишим наш первый тест, от простого к сложному
● Сложности в реальном проекте
● Советы и подведем итоги
Для кого этот доклад,
о проекте
● Проекту 5 лет
● 4 сервер разработчика + 2 клиент разработчика
● 2 тестировщика
● POS терминал .NET Framework 4.5, WPF
● Релизы:
○ крупные раз в 2-3 месяца
○ мелкие раз в 2-3 недели
● Требования меняются постоянно
Тесты должны
● Быстро писаться
● Легко читаться
● Легко поддерживаться
● Стабильно работать
● Давать понятные отчеты
Регрессия это скучно —
автоматизация это весело
Тесты должны
● Быстро писаться
● Легко читаться
● Легко поддерживаться
● Стабильно работать
● Давать понятные отчеты
https://github.com/Microsoft/WinAppDriver
WinAppDriver
Если вы искали лучшую поддержку для
использования Appium для тестирования
приложений Windows, эта услуга для вас!
Что нужно знать?
Минимум:
● Понимание ООП
● Функции, Классы
● Понимание работы Selenium WebDriver
Что нужно знать?
Минимум:
● Понимание ООП
● Функции, Классы
● Понимание работы Selenium WebDriver
Идеально:
● Один из языков программирования
поддерживаемых WinAppDriver
● Паттерны Page Object, ...
● Опыт работы с Selenium или Appium
● Опыт работы с Jenkins, Allure
Выбранный стек технологий
Как это работает?
- Переходие https://github.com/Microsoft/WinAppDriver/releases
- Скачиваете WindowsApplicationDriver.msi
- Устанавливайте
- Включите Режим Разработчика под Windows!
- Запускаеме cmd.exe
- Запускаете WinAppDriver.exe с номером порта на котором хотите его использовать
cd "C:Program Files (x86)Windows Application Driver"
WinAppDriver.exe 4723
WinAppDriver установка и запуск
Наш первый тест
Тест - Деление на ноль:
1. Открыть приложение "Калькулятор"
2. Нажать кнопку "Три"
3. Нажать кнопку "Разделить"
4. Нажать кнопку "Ноль"
5. Нажать кнопку "Равно"
6. Проверить что показалось сообщение
"Деление на ноль невозможно"
7. Закрыть приложение "Калькулятор"
Наш первый тест
Тест - Деление на ноль:
1. Открыть приложение "Калькулятор"
2. Нажать кнопку "Три"
3. Нажать кнопку "Разделить"
4. Нажать кнопку "Ноль"
5. Нажать кнопку "Равно"
6. Проверить что показалось сообщение
"Деление на ноль невозможно"
7. Закрыть приложение "Калькулятор"
def test_division_by_zero():
driver = webdriver.Remote(
command_executor='http://127.0.0.1:4723',
desired_capabilities={"app": "C:WindowsSystem32calc.exe"})
driver.find_element_by_name("Три").click()
driver.find_element_by_name("Разделить на").click()
driver.find_element_by_name("Ноль").click()
driver.find_element_by_name("Равно").click()
actual_result = driver.find_element_by_accessibility_id("CalculatorResults")
assert actual_result.text == "Деление на ноль невозможно"
driver.quit()
Наш первый тест
Тест - Деление на ноль:
1. Открыть приложение "Калькулятор"
2. Нажать кнопку "Три"
3. Нажать кнопку "Разделить"
4. Нажать кнопку "Ноль"
5. Нажать кнопку "Равно"
6. Проверить что показалось сообщение
"Деление на ноль невозможно"
7. Закрыть приложение "Калькулятор"
def test_division_by_zero():
driver = webdriver.Remote(
command_executor='http://127.0.0.1:4723',
desired_capabilities={"app": "C:WindowsSystem32calc.exe"})
driver.find_element_by_name("Три").click()
driver.find_element_by_name("Разделить на").click()
driver.find_element_by_name("Ноль").click()
driver.find_element_by_name("Равно").click()
actual_result = driver.find_element_by_accessibility_id("CalculatorResults")
assert actual_result.text == "Деление на ноль невозможно"
driver.quit()
Наш первый тест
Тест - Деление на ноль:
1. Открыть приложение "Калькулятор"
2. Нажать кнопку "Три"
3. Нажать кнопку "Разделить"
4. Нажать кнопку "Ноль"
5. Нажать кнопку "Равно"
6. Проверить что показалось сообщение
"Деление на ноль невозможно"
7. Закрыть приложение "Калькулятор"
def test_division_by_zero():
driver = webdriver.Remote(
command_executor='http://127.0.0.1:4723',
desired_capabilities={"app": "C:WindowsSystem32calc.exe"})
driver.find_element_by_name("Три").click()
driver.find_element_by_name("Разделить на").click()
driver.find_element_by_name("Ноль").click()
driver.find_element_by_name("Равно").click()
actual_result = driver.find_element_by_accessibility_id("CalculatorResults")
assert actual_result.text == "Деление на ноль невозможно"
driver.quit()
Наш первый тест
Тест - Деление на ноль:
1. Открыть приложение "Калькулятор"
2. Нажать кнопку "Три"
3. Нажать кнопку "Разделить"
4. Нажать кнопку "Ноль"
5. Нажать кнопку "Равно"
6. Проверить что показалось сообщение
"Деление на ноль невозможно"
7. Закрыть приложение "Калькулятор"
def test_division_by_zero():
driver = webdriver.Remote(
command_executor='http://127.0.0.1:4723',
desired_capabilities={"app": "C:WindowsSystem32calc.exe"})
driver.find_element_by_name("Три").click()
driver.find_element_by_name("Разделить на").click()
driver.find_element_by_name("Ноль").click()
driver.find_element_by_name("Равно").click()
actual_result = driver.find_element_by_accessibility_id("CalculatorResults")
assert actual_result.text == "Деление на ноль невозможно"
driver.quit()
Наш первый тест
Тест - Деление на ноль:
1. Открыть приложение "Калькулятор"
2. Нажать кнопку "Три"
3. Нажать кнопку "Разделить"
4. Нажать кнопку "Ноль"
5. Нажать кнопку "Равно"
6. Проверить что показалось сообщение
"Деление на ноль невозможно"
7. Закрыть приложение "Калькулятор"
def test_division_by_zero():
driver = webdriver.Remote(
command_executor='http://127.0.0.1:4723',
desired_capabilities={"app": "C:WindowsSystem32calc.exe"})
driver.find_element_by_name("Три").click()
driver.find_element_by_name("Разделить на").click()
driver.find_element_by_name("Ноль").click()
driver.find_element_by_name("Равно").click()
actual_result = driver.find_element_by_accessibility_id("CalculatorResults")
assert actual_result.text == "Деление на ноль невозможно"
driver.quit()
Наш первый тест
Тест - Деление на ноль:
1. Открыть приложение "Калькулятор"
2. Нажать кнопку "Три"
3. Нажать кнопку "Разделить"
4. Нажать кнопку "Ноль"
5. Нажать кнопку "Равно"
6. Проверить что показалось сообщение
"Деление на ноль невозможно"
7. Закрыть приложение "Калькулятор"
def test_division_by_zero():
driver = webdriver.Remote(
command_executor='http://127.0.0.1:4723',
desired_capabilities={"app": "C:WindowsSystem32calc.exe"})
driver.find_element_by_name("Три").click()
driver.find_element_by_name("Разделить на").click()
driver.find_element_by_name("Ноль").click()
driver.find_element_by_name("Равно").click()
actual_result = driver.find_element_by_accessibility_id("CalculatorResults")
assert actual_result.text == "Деление на ноль невозможно"
driver.quit()
Наш первый тест
Тест - Деление на ноль:
1. Открыть приложение "Калькулятор"
2. Нажать кнопку "Три"
3. Нажать кнопку "Разделить"
4. Нажать кнопку "Ноль"
5. Нажать кнопку "Равно"
6. Проверить что показалось сообщение
"Деление на ноль невозможно"
7. Закрыть приложение "Калькулятор"
def test_division_by_zero():
driver = webdriver.Remote(
command_executor='http://127.0.0.1:4723',
desired_capabilities={"app": "C:WindowsSystem32calc.exe"})
driver.find_element_by_name("Три").click()
driver.find_element_by_name("Разделить на").click()
driver.find_element_by_name("Ноль").click()
driver.find_element_by_name("Равно").click()
actual_result = driver.find_element_by_accessibility_id("CalculatorResults")
assert actual_result.text == "Деление на ноль невозможно"
driver.quit()
Наш первый тест
Тест - Деление на ноль:
1. Открыть приложение "Калькулятор"
2. Нажать кнопку "Три"
3. Нажать кнопку "Разделить"
4. Нажать кнопку "Ноль"
5. Нажать кнопку "Равно"
6. Проверить что показалось сообщение
"Деление на ноль невозможно"
7. Закрыть приложение "Калькулятор"
def test_division_by_zero():
driver = webdriver.Remote(
command_executor='http://127.0.0.1:4723',
desired_capabilities={"app": "C:WindowsSystem32calc.exe"})
driver.find_element_by_name("Три").click()
driver.find_element_by_name("Разделить на").click()
driver.find_element_by_name("Ноль").click()
driver.find_element_by_name("Равно").click()
actual_result = driver.find_element_by_accessibility_id("CalculatorResults")
assert actual_result.text == "Деление на ноль невозможно"
driver.quit()
Наш первый тест
Тест - Деление на ноль:
1. Открыть приложение "Калькулятор"
2. Нажать кнопку "Три"
3. Нажать кнопку "Разделить"
4. Нажать кнопку "Ноль"
5. Нажать кнопку "Равно"
6. Проверить что показалось сообщение
"Деление на ноль невозможно"
7. Закрыть приложение "Калькулятор"
def test_division_by_zero():
driver = webdriver.Remote(
command_executor='http://127.0.0.1:4723',
desired_capabilities={"app": "C:WindowsSystem32calc.exe"})
driver.find_element_by_name("Три").click()
driver.find_element_by_name("Разделить на").click()
driver.find_element_by_name("Ноль").click()
driver.find_element_by_name("Равно").click()
actual_result = driver.find_element_by_accessibility_id("CalculatorResults")
assert actual_result.text == "Деление на ноль невозможно"
driver.quit()
Inspect — получаем ID элементов
Тест - Деление на ноль:
1. Открыть приложение "Калькулятор"
2. Нажать кнопку "Три"
3. Нажать кнопку "Разделить"
4. Нажать кнопку "Ноль"
5. Нажать кнопку "Равно"
6. Проверить что показалось сообщение
"Деление на ноль невозможно"
7. Закрыть приложение "Калькулятор"
def test_division_by_zero():
driver = webdriver.Remote(
command_executor='http://127.0.0.1:4723',
desired_capabilities={"app": "C:WindowsSystem32calc.exe"})
driver.find_element_by_name("Три").click()
driver.find_element_by_name("Разделить на").click()
driver.find_element_by_name("Ноль").click()
driver.find_element_by_name("Равно").click()
actual_result = driver.find_element_by_accessibility_id("CalculatorResults")
assert actual_result.text == "Деление на ноль невозможно"
driver.quit()
Inspect — получаем ID элементов
https://msdn.microsoft.com/en-us/library/windows/desktop/dd318521(v=vs.85).aspx
Inspect — получаем ID элементов
Client API Locator Strategy Matched Attribute in inspect.exe Example
FindElementByAccessibilityId accessibility id AutomationId AppNameTitle
FindElementByClassName class name ClassName TextBlock
FindElementByName name Name Calculator
FindElementById id RuntimeId (decimal) 42.333896.3.1
FindElementByTagName tag name LocalizedControlType (upper camel case) Text
FindElementByXPath xpath Any //Button[0]
Проблемы:
● Запуск приложения, если поменяется
директория или порт WinAppDriver
@pytest.fixture(scope="module")
def driver():
driver = webdriver.Remote(
command_executor='http://127.0.0.1:4723',
desired_capabilities={"app": "C:WindowsSystem32calc.exe"})
yield driver
driver.quit()
Fixtures = Pre-condition + Post-condition
Pre-condition:
Открыть приложение "Калькулятор"
Steps:
1. Нажать кнопку "Три"
2. Нажать кнопку "Разделить"
3. Нажать кнопку "Ноль"
4. Нажать кнопку "Равно"
5. Проверить что показалось сообщение
"Деление на ноль невозможно"
Post-condition:
Закрыть приложение "Калькулятор"
@pytest.fixture(scope="module")
def driver():
driver = webdriver.Remote(
command_executor='http://127.0.0.1:4723',
desired_capabilities={"app": "C:WindowsSystem32calc.exe"})
yield driver
driver.quit()
Fixtures = Pre-condition + Post-condition
Pre-condition:
Открыть приложение "Калькулятор"
Steps:
1. Нажать кнопку "Три"
2. Нажать кнопку "Разделить"
3. Нажать кнопку "Ноль"
4. Нажать кнопку "Равно"
5. Проверить что показалось сообщение
"Деление на ноль невозможно"
Post-condition:
Закрыть приложение "Калькулятор"
@pytest.fixture(scope="module")
def driver():
driver = webdriver.Remote(
command_executor='http://127.0.0.1:4723',
desired_capabilities={"app": "C:WindowsSystem32calc.exe"})
yield driver
driver.quit()
Fixtures = Pre-condition + Post-condition
Pre-condition:
Открыть приложение "Калькулятор"
Steps:
1. Нажать кнопку "Три"
2. Нажать кнопку "Разделить"
3. Нажать кнопку "Ноль"
4. Нажать кнопку "Равно"
5. Проверить что показалось сообщение
"Деление на ноль невозможно"
Post-condition:
Закрыть приложение "Калькулятор"
test_calculator.py
def test_division_by_zero(driver):
driver.find_element_by_name("Три").click()
driver.find_element_by_name("Разделить на").click()
driver.find_element_by_name("Нуль").click()
driver.find_element_by_name("Равно").click()
actual_result = driver.find_element_by_accessibility_id("CalculatorResults").text
assert actual_result == "Деление на ноль невозможно"
Fixtures = Pre-condition + Post-condition
conftest.py
@pytest.fixture(scope="module")
def driver():
driver = webdriver.Remote(
command_executor='http://127.0.0.1:4723',
desired_capabilities={"app": "C:WindowsSystem32calc.exe"})
yield driver
driver.quit()
conftest.py
@pytest.fixture(scope="module")
def driver():
driver = webdriver.Remote(
command_executor='http://127.0.0.1:4723',
desired_capabilities={"app": "C:WindowsSystem32calc.exe"})
yield driver
driver.quit()
test_calculator.py
def test_division_by_zero(driver):
driver.find_element_by_name("Три").click()
driver.find_element_by_name("Разделить на").click()
driver.find_element_by_name("Нуль").click()
driver.find_element_by_name("Равно").click()
actual_result = driver.find_element_by_accessibility_id("CalculatorResults").text
assert actual_result == "Деление на ноль невозможно"
Fixtures = Pre-condition + Post-condition
Проблемы:
● Запуск приложения, если поменяется
директория или порт WinAppDriver
Рост кол-ва тестов и их размер
def test_weird(driver):
driver.find_element_by_name("Три").click()
driver.find_element_by_name("Разделить на").click()
driver.find_element_by_name("Нуль").click()
driver.find_element_by_name("Равно").click()
assert driver.find_element_by_accessibility_id("CalculatorResults").text == "Деление на ноль невозможно"
driver.find_element_by_name("Меню").click()
driver.find_element_by_name("Инженерный Калькулятор").click()
driver.find_element_by_name("Три").click()
driver.find_element_by_name("Десять в степени").click()
assert driver.find_element_by_accessibility_id("CalculatorResults").text == "1000"
driver.find_element_by_name("Меню").click()
driver.find_element_by_name("Обычный Калькулятор").click()
Рост кол-ва тестов и их размер
def test_weird(driver):
driver.find_element_by_name("Три").click()
driver.find_element_by_name("Разделить на").click()
driver.find_element_by_name("Нуль").click()
driver.find_element_by_name("Равно").click()
assert driver.find_element_by_accessibility_id("CalculatorResults").text == "Деление на ноль невозможно"
driver.find_element_by_name("Меню").click()
driver.find_element_by_name("Инженерный Калькулятор").click()
driver.find_element_by_name("Три").click()
driver.find_element_by_name("Десять в степени").click()
assert driver.find_element_by_accessibility_id("CalculatorResults").text == "1000"
driver.find_element_by_name("Меню").click()
driver.find_element_by_name("Обычный Калькулятор").click()
def test_addition(driver):
driver.find_element_by_name("Три").click()
driver.find_element_by_name("Плюс").click()
driver.find_element_by_name("Два").click()
driver.find_element_by_name("Равно").click()
assert driver.find_element_by_accessibility_id("CalculatorResults").text == "5"
driver.find_element_by_name("Очистить").click()
И что с этим всем делать?
Проблемы:
● Запуск приложения, если поменяется
директория или порт WinAppDriver
● В больших тестах сложно понять
на каком из экранов мы выполняем
действие
● Если изменится ID или имя элемента
нужно править в каждом тесте
Screen Object
standard.py
class Standard():
def __init__(self, driver):
self.driver = driver
def click_one_button(self):
self.driver.find_element_by_name("Один").click()
def click_two_button(self):
self.driver.find_element_by_name("Два").click()
def click_three_button(self):
self.driver.find_element_by_name("Три").click()
def click_four_button(self):
self.driver.find_element_by_name("Четыре").click()
def ...
Screen Object
engineer.py
class Engineer():
def __init__(self, driver):
self.driver = driver
def open_standard_calculator(self):
self.driver.find_element_by_name("Меню").click()
self.driver.find_element_by_name("Обычный Калькулятор").click()
def ...
Screen Object
test_calculator.py
def test_weird(driver):
standard = Standard(driver=driver)
engineer = Engineer(driver=driver)
standard.click_three_button()
standard.click_division_button()
standard.click_zero_button()
standard.click_equals_button()
standard.check_result("Деление на ноль невозможно")
standard.open_engineer_calculator()
engineer.click_three_button()
engineer.click_ten_in_degree_button()
engineer.check_result("1000")
engineer.open_standard_calculator()
Screen Object
class Base(): -> class Main(Base): -> class Standard(Main):
Совет:
Одинаковые методы выносите в Base класс,
используйте наследование
Проблемы:
● Запуск приложения, если поменяется
директория или порт WinAppDriver
● В больших тестах сложно понять
на каком из экранов мы выполняем
действие
● Если изменится ID или имя элемента
нужно править в каждом тесте
@pytest.fixture(scope="module")
def driver():
driver = webdriver.Remote(
command_executor='http://127.0.0.1:4723',
desired_capabilities={"app": "C:App"})
yield driver
driver.quit()
Хочу читаемые тесты
test_calculator.py
def test_weird(driver):
standard = Standard(driver=driver)
engineer = Engineer(driver=driver)
standard.click_three_button()
standard.click_division_button()
standard.click_zero_button()
standard.click_equals_button()
standard.check_result("Деление на ноль невозможно")
standard.open_engineer_calculator()
engineer.click_three_button()
engineer.click_ten_in_degree_button()
engineer.check_result("1000")
engineer.open_standard_calculator()
Хочу читаемые тесты
test_calculator.py
def test_weird(driver):
standard = Standard(driver=driver)
engineer = Engineer(driver=driver)
standard.click_three_button()
standard.click_division_button()
standard.click_zero_button()
standard.click_equals_button()
standard.check_result("Деление на ноль невозможно")
standard.open_engineer_calculator()
engineer.click_three_button()
engineer.click_ten_in_degree_button()
engineer.check_result("1000")
engineer.open_standard_calculator()
test_calculator.py
def test_weird(driver):
standard = Standard(driver=driver)
engineer = Engineer(driver=driver)
standard
.click_three_button()
.click_division_button()
.click_zero_button()
.click_equals_button()
.check_result("Деление на ноль невозможно")
.open_engineer_calculator()
engineer
.click_three_button()
.click_ten_in_degree_button()
.check_result("1000")
.open_standard_calculator()
Проблемы:
● Запуск приложения, если поменяется
директория или порт WinAppDriver
● В больших тестах сложно понять
на каком из экранов мы выполняем
действие
● Если изменится ID или имя элемента
нужно править в каждом тесте
● Тесты недостаточно читаемые!
Хочу читаемые тесты
engineer.py
class Engineer():
def __init__(self, driver):
self.driver = driver
def click_three_button(self):
self.driver.find_element_by_name("Три").click()
def open_engineer_calculator(self):
self.driver.find_element_by_name("Меню").click()
self.driver.find_element_by_name("Обычный Калькулятор").click()
Хочу читаемые тесты
engineer.py
class Engineer():
def __init__(self, driver):
self.driver = driver
def click_three_button(self):
self.driver.find_element_by_name("Три").click()
return self - добавить после шагов
def open_engineer_calculator(self):
self.driver.find_element_by_name("Меню").click()
self.driver.find_element_by_name("Обычный Калькулятор").click()
return self - добавить после шагов
Chains
standard.click_three_button()
standard.click_division_button()
standard.click_zero_button()
standard.click_equals_button()
standard.check_result("Деление на ноль невозможно")
standard.open_engineer_calculator()
standard
.click_three_button()
.click_division_button()
.click_zero_button()
.click_equals_button()
.check_result("Деление на ноль невозможно")
.open_engineer_calculator()
standard.click_three_button().click_division_button().click_zero_button().click_equals_button().....
Проблемы:
● Запуск приложения, если поменяется
директория или порт WinAppDriver
● В больших тестах сложно понять
на каком из экранов мы выполняем
действие
● Если изменится ID или имя элемента
нужно править в каждом тесте
● Тесты недостаточно читаемые!
Проблемы:
● Запуск приложения, если поменяется
директория или порт WinAppDriver
● В больших тестах сложно понять
на каком из экранов мы выполняем
действие
● Если изменится ID или имя элемента
нужно править в каждом тесте
● Тесты недостаточно читаемые!
● Отчеты сложно анализировать
Хочу удобные и понятные отчеты
engineer.py
class Engineer():
def __init__(self, driver):
self.driver = driver
def click_three_button(self):
self.driver.find_element_by_name("Три").click()
return self
def open_engineer_calculator(self):
self.driver.find_element_by_name("Меню").click()
self.driver.find_element_by_name("Обычный Калькулятор").click()
return self
engineer.py
class Engineer():
def __init__(self, driver):
self.driver = driver
def click_three_button(self):
self.driver.find_element_by_name("Три").click()
return self
def open_engineer_calculator(self):
self.driver.find_element_by_name("Меню").click()
self.driver.find_element_by_name("Обычный Калькулятор").click()
return self
Хочу удобные и понятные отчеты
engineer.py
class Engineer():
def __init__(self, driver):
self.driver = driver
def click_three_button(self):
self.driver.find_element_by_name("Три").click()
return self
def open_engineer_calculator(self):
self.driver.find_element_by_name("Меню").click()
self.driver.find_element_by_name("Обычный Калькулятор").click()
return self
engineer.py
class Engineer():
def __init__(self, driver):
self.driver = driver
def click_three_button(self):
with allure.step('Нажать кнопку "Три"'): - добавить перед шагами
self.driver.find_element_by_name("Три").click()
return self
def open_engineer_calculator(self):
with allure.step('Открыть "Обычный калькулятор"'): - добавить перед шагами
self.driver.find_element_by_name("Меню").click()
self.driver.find_element_by_name("Обычный Калькулятор").click()
return self
Хочу удобные и понятные отчеты
engineer.py
class Engineer():
def __init__(self, driver):
self.driver = driver
def click_three_button(self):
with allure.step('Нажать кнопку "Три"'):
self.driver.find_element_by_name("Три").click()
return self
def open_engineer_calculator(self):
with allure.step('Открыть "Обычный калькулятор"'):
self.driver.find_element_by_name("Меню").click()
self.driver.find_element_by_name("Обычный Калькулятор").click()
return self
Хочу удобные и понятные отчеты
engineer.py
class Engineer():
def __init__(self, driver):
self.driver = driver
def check_result(self, result):
with allure.step('Проверить что результат равен "{}"'.format(result)):
allure.attach(self.driver.get_screenshot_as_png(), 'ScreenShotName', attachment_type=allure.attachment_type.PNG)
actual_result = self.driver.find_element_by_accessibility_id("CalculatorResults").text
assert actual_result == result, 'Полученный результат "{}" не равен ожидаемому "{}"'.format(actual_result, result)
return self
Хочу удобные и понятные отчеты
engineer.py
class Engineer():
def __init__(self, driver):
self.driver = driver
def check_result(self, result):
with allure.step('Проверить что результат равен "{}"'.format(result)):
allure.attach(self.driver.get_screenshot_as_png(), 'ScreenShotName', attachment_type=allure.attachment_type.PNG)
actual_result = self.driver.find_element_by_accessibility_id("CalculatorResults").text
assert actual_result == result, 'Полученный результат "{}" не равен ожидаемому "{}"'.format(actual_result, result)
return self
Хочу удобные и понятные отчеты
@allure.feature('Standard')
@allure.story('Math')
class TestCalculator:
def test_addition(self, driver):
standard = Standard(driver=driver)
standard
.click_three_button()
.click_plus_button() 
.click_three_button()
.click_equals_button()
.check_result("6")
def test_subtraction(self, driver):
standard = Standard(driver=driver)
standard 
.click_three_button() 
.click_minus_button() 
.click_one_button() 
.click_equals_button() 
.check_result("2")
https://youtu.be/hbhHoWqPqIo
Проблемы:
● Запуск приложения, если поменяется
директория или порт WinAppDriver
● В больших тестах сложно понять
на каком из экранов мы выполняем
действие
● Если изменится ID или имя элемента
нужно править в каждом тесте
● Тесты недостаточно читаемые!
● Отчеты сложно анализировать
Проблемы:
● Запуск приложения, если поменяется
директория или порт WinAppDriver
● В больших тестах сложно понять
на каком из экранов мы выполняем
действие
● Если изменится ID или имя элемента
нужно править в каждом тесте
● Тесты недостаточно читаемые!
● Отчеты сложно анализировать
● WinAppDriver используем указатель
мыши для действия с элементами
Jenkins, запуск тестов
Зачем он нужен?
● Запуск по расписанию или после
push-а изменений в git репозиторий
● Можно пользоваться мышью
в момент прогона тестов
● Интеграция отчетов
● Continuous Integration
Oracle VM VirtualBox
VBoxHeadlessTray
Настроенная среда
для тестов
http://www.toptensoftware.com/vboxheadlesstray/
Проблемы:
● Запуск приложения, если поменяется
директория или порт WinAppDriver
● В больших тестах сложно понять
на каком из экранов мы выполняем
действие
● Если изменится ID или имя элемента
нужно править в каждом тесте
● Тесты недостаточно читаемые!
● Отчеты сложно анализировать
● WinAppDriver используем указатель
мыши для действия с элементами
Сложности с которыми столкнулись,
в реальном проекте
● Правильные локаторы
● Переключение между окнами
● Ожидание появления элементов
● Откат приложения в исходное состояние
Правильные локаторы
driver.find_element s_by_name('Continue')[1].click()
driver.find_element s_by_accessibility_id( 'TextBox')[2].send_keys( price)
driver.find_element_by_accessibility_id( 'JournalContinueButton' ).click()
driver.find_element_by_accessibility_id( 'CalculatorPriceTextBox' ).send_keys( price)
Вывод: Правильные локаторы = Взаимодействие с разработчиками
test.py
menu
.open_category('Фрукты')
.add_product_to_cart('Яблоко')
1. Open "Фрукты" category
2. Add product "Яблоко" to cart
menu.py
def add_product_to_cart(self, product):
with allure.step('Add product "' + product + '" to cart'):
try:
self.driver.find_element_by_accessibility_id(product).click()
except NoSuchElementException:
+ добавить скриншот
raise NoSuchElementException(
'Product "{}" is not found'.format(product))
return self
Правильные локаторы
AutomationID — упрощает работу
Для списков “продуктов”, AutomationID = Название продукта
Переключение между окнами
def open_file_menu (driver):
driver.find_element_by_name( "Файл").click()
driver.switch_to.window( driver.current_window_handle)
Переключение между окнами
driver.switch_to.window( driver.window_handles[ 0])
Login
Login screen
Logout
Application
Переключение между окнами
driver.switch_to.window( driver.window_handles[ 0])
Login
Login screen
Logout
ApplicationЗагрузка
Работа с умными ожиданиями
def wait_for_element_to_appear(self, element, delay=15):
i = 0
while i < delay:
try:
self.driver.switch_to.window( self.driver.window_handles[0])
self.driver.find_element_by_accessibility_id(element)
break
except Exception as exception:
time.sleep(0.2)
i += 0.2
return self
https://youtu.be/cA1A2DzZGGI
Добавляем скриншоты, выводим коды ошибки,
получаем супер умное ожидание
- переключиться на активное окно
- попробуй найти элемент
- все хорошо выйти из цикла
- если не найден, подождать
и снова попробовать найти элемент
● Проверка на открытое окно, если открыто закрыть
● Взаимодействуйте с разработчиками
● Используйте RPC (Remote Procedure Call)
● Подключение по SSH, консольные команды
Откат приложения
в исходное состояние
Советы
Сложно писать тесты
- Используйте Test Data
Недостаточно отладочной информации
- Используйте print()
- Или logging
- Получаем полезную информацию в консоль
Тесты должны показывать результат
- Портите тесты, смотрите результаты
Решайте проблемы по мере их появления
Не изобретайте свой велосипед
● Быстро внедрили автоматизацию
● Тесты стабильные
и их легко поддерживать
● Тесты быстро пишутся
● Предоставляет понятные отчеты
Что получили в итоге
и выводы
Спасибо! Вопросы?
Стульников Алексей
QA Tech Lead at
a.stulnikov@mobidev.biz

More Related Content

What's hot

Введение в тестирование с использованием закодированных автоматических тестов...
Введение в тестирование с использованием закодированных автоматических тестов...Введение в тестирование с использованием закодированных автоматических тестов...
Введение в тестирование с использованием закодированных автоматических тестов...
Александр Шамрай
 
Диагностика проблем в промышленной среде с помощью Intelli Trace и Visual Stu...
Диагностика проблем в промышленной среде с помощью Intelli Trace и Visual Stu...Диагностика проблем в промышленной среде с помощью Intelli Trace и Visual Stu...
Диагностика проблем в промышленной среде с помощью Intelli Trace и Visual Stu...
Александр Шамрай
 
Визулизация ветвления и объединения в Visual Studio Team Foundation Server 2012
Визулизация ветвления и объединения в Visual Studio Team Foundation Server 2012Визулизация ветвления и объединения в Visual Studio Team Foundation Server 2012
Визулизация ветвления и объединения в Visual Studio Team Foundation Server 2012
Александр Шамрай
 
Модульное тестирование с помощью visual studio 2012 MS Test, Nunit, X-unit.ne...
Модульное тестирование с помощью visual studio 2012 MS Test, Nunit, X-unit.ne...Модульное тестирование с помощью visual studio 2012 MS Test, Nunit, X-unit.ne...
Модульное тестирование с помощью visual studio 2012 MS Test, Nunit, X-unit.ne...
Александр Шамрай
 
Разработка оптимального ПО - создание раскадровок и сбор отзывов от заинтерес...
Разработка оптимального ПО - создание раскадровок и сбор отзывов от заинтерес...Разработка оптимального ПО - создание раскадровок и сбор отзывов от заинтерес...
Разработка оптимального ПО - создание раскадровок и сбор отзывов от заинтерес...
Александр Шамрай
 
Гибкое управление проектами в Visual Studio Team Foundation Server 2012
Гибкое управление проектами в Visual Studio Team Foundation Server 2012Гибкое управление проектами в Visual Studio Team Foundation Server 2012
Гибкое управление проектами в Visual Studio Team Foundation Server 2012
Александр Шамрай
 
kranonit S11E01 Андрей Пономарёв: Тренинг по TDD в Java
kranonit S11E01 Андрей Пономарёв: Тренинг по TDD в Javakranonit S11E01 Андрей Пономарёв: Тренинг по TDD в Java
kranonit S11E01 Андрей Пономарёв: Тренинг по TDD в Java
Krivoy Rog IT Community
 

What's hot (20)

Введение в тестирование с использованием закодированных автоматических тестов...
Введение в тестирование с использованием закодированных автоматических тестов...Введение в тестирование с использованием закодированных автоматических тестов...
Введение в тестирование с использованием закодированных автоматических тестов...
 
Moxy. Из чего состоит и как этим пользоваться
Moxy. Из чего состоит и как этим пользоватьсяMoxy. Из чего состоит и как этим пользоваться
Moxy. Из чего состоит и как этим пользоваться
 
Диагностика проблем в промышленной среде с помощью Intelli Trace и Visual Stu...
Диагностика проблем в промышленной среде с помощью Intelli Trace и Visual Stu...Диагностика проблем в промышленной среде с помощью Intelli Trace и Visual Stu...
Диагностика проблем в промышленной среде с помощью Intelli Trace и Visual Stu...
 
Dependency Injection на примере Unity и NInject
Dependency Injection на примере Unity и NInjectDependency Injection на примере Unity и NInject
Dependency Injection на примере Unity и NInject
 
Визулизация ветвления и объединения в Visual Studio Team Foundation Server 2012
Визулизация ветвления и объединения в Visual Studio Team Foundation Server 2012Визулизация ветвления и объединения в Visual Studio Team Foundation Server 2012
Визулизация ветвления и объединения в Visual Studio Team Foundation Server 2012
 
Модульное тестирование с помощью visual studio 2012 MS Test, Nunit, X-unit.ne...
Модульное тестирование с помощью visual studio 2012 MS Test, Nunit, X-unit.ne...Модульное тестирование с помощью visual studio 2012 MS Test, Nunit, X-unit.ne...
Модульное тестирование с помощью visual studio 2012 MS Test, Nunit, X-unit.ne...
 
Разработка оптимального ПО - создание раскадровок и сбор отзывов от заинтерес...
Разработка оптимального ПО - создание раскадровок и сбор отзывов от заинтерес...Разработка оптимального ПО - создание раскадровок и сбор отзывов от заинтерес...
Разработка оптимального ПО - создание раскадровок и сбор отзывов от заинтерес...
 
Behavior Driven Development
Behavior Driven DevelopmentBehavior Driven Development
Behavior Driven Development
 
«Как я научился не волноваться и полюбил Android-MVP», Никита Бартишок, ABBYY
«Как я научился не волноваться и полюбил Android-MVP», Никита Бартишок, ABBYY«Как я научился не волноваться и полюбил Android-MVP», Никита Бартишок, ABBYY
«Как я научился не волноваться и полюбил Android-MVP», Никита Бартишок, ABBYY
 
Гибкое управление проектами в Visual Studio Team Foundation Server 2012
Гибкое управление проектами в Visual Studio Team Foundation Server 2012Гибкое управление проектами в Visual Studio Team Foundation Server 2012
Гибкое управление проектами в Visual Studio Team Foundation Server 2012
 
kranonit S11E01 Андрей Пономарёв: Тренинг по TDD в Java
kranonit S11E01 Андрей Пономарёв: Тренинг по TDD в Javakranonit S11E01 Андрей Пономарёв: Тренинг по TDD в Java
kranonit S11E01 Андрей Пономарёв: Тренинг по TDD в Java
 
Build a VR Pawn with Unreal Engine Luis Cataldi Russian
Build a VR Pawn with Unreal Engine   Luis Cataldi RussianBuild a VR Pawn with Unreal Engine   Luis Cataldi Russian
Build a VR Pawn with Unreal Engine Luis Cataldi Russian
 
C# Web. Занятие 11.
C# Web. Занятие 11.C# Web. Занятие 11.
C# Web. Занятие 11.
 
Введение в Android-разработку (Lecture 06 – basics)
Введение в Android-разработку (Lecture 06 – basics)Введение в Android-разработку (Lecture 06 – basics)
Введение в Android-разработку (Lecture 06 – basics)
 
BDD girls Battle: Cucumber VS. JBehave
BDD girls Battle: Cucumber VS. JBehaveBDD girls Battle: Cucumber VS. JBehave
BDD girls Battle: Cucumber VS. JBehave
 
Unit tests final
Unit tests finalUnit tests final
Unit tests final
 
Бодрящий микс из Selenium и TestNG- регрессионное тестирование руками разрабо...
Бодрящий микс из Selenium и TestNG- регрессионное тестирование руками разрабо...Бодрящий микс из Selenium и TestNG- регрессионное тестирование руками разрабо...
Бодрящий микс из Selenium и TestNG- регрессионное тестирование руками разрабо...
 
Автоматизация функционального тестирования REST API
Автоматизация функционального тестирования REST APIАвтоматизация функционального тестирования REST API
Автоматизация функционального тестирования REST API
 
Системы автоматизированной сборки (Lecture 05 – gradle)
Системы автоматизированной сборки (Lecture 05 – gradle)Системы автоматизированной сборки (Lecture 05 – gradle)
Системы автоматизированной сборки (Lecture 05 – gradle)
 
Михаил Левин: Автоматизация в мобильном тестировании
Михаил Левин: Автоматизация в мобильном тестированииМихаил Левин: Автоматизация в мобильном тестировании
Михаил Левин: Автоматизация в мобильном тестировании
 

Similar to Олексій Стульніков “WinAppDriver – автоматизація Desktop ніколи не була такою простою”

Липский Павел
Липский ПавелЛипский Павел
Липский Павел
Ontico
 
10 задач администрирования Active directory, решаемых с помощью power shell
10 задач администрирования Active directory, решаемых с помощью power shell10 задач администрирования Active directory, решаемых с помощью power shell
10 задач администрирования Active directory, решаемых с помощью power shell
Andrey Markin
 
Introduction into Test Driven Development
Introduction into Test Driven DevelopmentIntroduction into Test Driven Development
Introduction into Test Driven Development
Ivan Dyachenko
 
Эволюционный дизайн. Joker Students Day 2016
Эволюционный дизайн. Joker Students Day 2016Эволюционный дизайн. Joker Students Day 2016
Эволюционный дизайн. Joker Students Day 2016
Кирилл Толкачёв
 
Mobile automation uamobile
Mobile automation uamobileMobile automation uamobile
Mobile automation uamobile
UA Mobile
 

Similar to Олексій Стульніков “WinAppDriver – автоматизація Desktop ніколи не була такою простою” (20)

Липский Павел
Липский ПавелЛипский Павел
Липский Павел
 
Automation testing desktop applications
Automation testing desktop applicationsAutomation testing desktop applications
Automation testing desktop applications
 
Как сейчас тесты в Android пишут, Денис Неклюдов, Google Dev Expert, Москва
 Как сейчас тесты в Android пишут, Денис Неклюдов, Google Dev Expert, Москва  Как сейчас тесты в Android пишут, Денис Неклюдов, Google Dev Expert, Москва
Как сейчас тесты в Android пишут, Денис Неклюдов, Google Dev Expert, Москва
 
Load testing with Tsung
Load testing with TsungLoad testing with Tsung
Load testing with Tsung
 
Jbreak 2016: Твой личный Spring Boot Starter
Jbreak 2016: Твой личный Spring Boot StarterJbreak 2016: Твой личный Spring Boot Starter
Jbreak 2016: Твой личный Spring Boot Starter
 
Mva stf module 5 - rus
Mva stf module 5 - rusMva stf module 5 - rus
Mva stf module 5 - rus
 
E2E-тестирование мобильных приложений
E2E-тестирование мобильных приложенийE2E-тестирование мобильных приложений
E2E-тестирование мобильных приложений
 
Алексей Андросов - Debugger: Отладка кода
Алексей Андросов - Debugger: Отладка кодаАлексей Андросов - Debugger: Отладка кода
Алексей Андросов - Debugger: Отладка кода
 
10 задач администрирования Active directory, решаемых с помощью power shell
10 задач администрирования Active directory, решаемых с помощью power shell10 задач администрирования Active directory, решаемых с помощью power shell
10 задач администрирования Active directory, решаемых с помощью power shell
 
iOS and Android Mobile Test Automation
iOS and Android Mobile Test AutomationiOS and Android Mobile Test Automation
iOS and Android Mobile Test Automation
 
Introduction into Test Driven Development
Introduction into Test Driven DevelopmentIntroduction into Test Driven Development
Introduction into Test Driven Development
 
Артем Розуменко - "Как и зачем разрабатывать собственный фреймворк?"
Артем Розуменко - "Как и зачем разрабатывать собственный фреймворк?"Артем Розуменко - "Как и зачем разрабатывать собственный фреймворк?"
Артем Розуменко - "Как и зачем разрабатывать собственный фреймворк?"
 
Sencha Complete: Kharkiv JS #1
Sencha Complete: Kharkiv JS #1Sencha Complete: Kharkiv JS #1
Sencha Complete: Kharkiv JS #1
 
Mobile automation with Appium
Mobile automation with AppiumMobile automation with Appium
Mobile automation with Appium
 
Тестирование параллельных программ
Тестирование параллельных программТестирование параллельных программ
Тестирование параллельных программ
 
Appium для народа
Appium для народаAppium для народа
Appium для народа
 
Continious integration-Automated Testing-Solid-Agile
Continious integration-Automated Testing-Solid-AgileContinious integration-Automated Testing-Solid-Agile
Continious integration-Automated Testing-Solid-Agile
 
Эволюционный дизайн. Joker Students Day 2016
Эволюционный дизайн. Joker Students Day 2016Эволюционный дизайн. Joker Students Day 2016
Эволюционный дизайн. Joker Students Day 2016
 
Mobile automation uamobile
Mobile automation uamobileMobile automation uamobile
Mobile automation uamobile
 
Plugin for plugin, or extending android new build system
Plugin for plugin, or extending android new build systemPlugin for plugin, or extending android new build system
Plugin for plugin, or extending android new build system
 

More from Dakiry

More from Dakiry (20)

НАРЦИСИЗМ ЯК ПАСИВНЕ КУРІННЯ
НАРЦИСИЗМ ЯК ПАСИВНЕ КУРІННЯНАРЦИСИЗМ ЯК ПАСИВНЕ КУРІННЯ
НАРЦИСИЗМ ЯК ПАСИВНЕ КУРІННЯ
 
МАНІПУЛЯЦІЇ: ХТО КОГО І ДЛЯ ЧОГО? - Інна Тіторенко
МАНІПУЛЯЦІЇ: ХТО КОГО І ДЛЯ ЧОГО? - Інна ТіторенкоМАНІПУЛЯЦІЇ: ХТО КОГО І ДЛЯ ЧОГО? - Інна Тіторенко
МАНІПУЛЯЦІЇ: ХТО КОГО І ДЛЯ ЧОГО? - Інна Тіторенко
 
How to run a discovery workshop
How to run a discovery workshopHow to run a discovery workshop
How to run a discovery workshop
 
З понеділка йду на новий проект. The tester’s version - Олександра Зубаль
З понеділка йду на новий проект. The tester’s version - Олександра ЗубальЗ понеділка йду на новий проект. The tester’s version - Олександра Зубаль
З понеділка йду на новий проект. The tester’s version - Олександра Зубаль
 
Робота з текстом: від чернетки до опублікування
Робота з текстом: від чернетки до опублікуванняРобота з текстом: від чернетки до опублікування
Робота з текстом: від чернетки до опублікування
 
Контентна стратегія в ІТ: від статті до першого ліда
Контентна стратегія в ІТ: від статті до першого лідаКонтентна стратегія в ІТ: від статті до першого ліда
Контентна стратегія в ІТ: від статті до першого ліда
 
Oleh Shpyrna "Security Testing Basics: Check your Webapp for gaps before l_unch"
Oleh Shpyrna "Security Testing Basics: Check your Webapp for gaps before l_unch"Oleh Shpyrna "Security Testing Basics: Check your Webapp for gaps before l_unch"
Oleh Shpyrna "Security Testing Basics: Check your Webapp for gaps before l_unch"
 
Stepan Shykerynets "Power of QA (A Journey: From Hell to Heaven. Story of gr...
Stepan Shykerynets "Power of QA (A Journey: From Hell to Heaven.  Story of gr...Stepan Shykerynets "Power of QA (A Journey: From Hell to Heaven.  Story of gr...
Stepan Shykerynets "Power of QA (A Journey: From Hell to Heaven. Story of gr...
 
Микола Солопій "Selenium рулить, однак..."
Микола Солопій "Selenium рулить, однак..."Микола Солопій "Selenium рулить, однак..."
Микола Солопій "Selenium рулить, однак..."
 
Oleksandra Zubal "Project starters: test automation view"
Oleksandra Zubal "Project starters: test automation view"Oleksandra Zubal "Project starters: test automation view"
Oleksandra Zubal "Project starters: test automation view"
 
Vladyslav Romanchenko "How to keep high code quality without e2e tests"
Vladyslav Romanchenko "How to keep high code quality without e2e tests"Vladyslav Romanchenko "How to keep high code quality without e2e tests"
Vladyslav Romanchenko "How to keep high code quality without e2e tests"
 
Діана Пінчук "Як відрізнити авторизацію від аутентифікації та перестати бояти...
Діана Пінчук "Як відрізнити авторизацію від аутентифікації та перестати бояти...Діана Пінчук "Як відрізнити авторизацію від аутентифікації та перестати бояти...
Діана Пінчук "Як відрізнити авторизацію від аутентифікації та перестати бояти...
 
Yuriy Malyi "E2E testing organization in multi-system projects"
Yuriy Malyi "E2E testing organization in multi-system projects"Yuriy Malyi "E2E testing organization in multi-system projects"
Yuriy Malyi "E2E testing organization in multi-system projects"
 
Petro Tarasenko "You've become a TL. What's next?"
 Petro Tarasenko "You've become a TL. What's next?" Petro Tarasenko "You've become a TL. What's next?"
Petro Tarasenko "You've become a TL. What's next?"
 
Roman Yakymchuk "Дослідницьке тестування. Перезапуск"
Roman Yakymchuk "Дослідницьке тестування. Перезапуск"Roman Yakymchuk "Дослідницьке тестування. Перезапуск"
Roman Yakymchuk "Дослідницьке тестування. Перезапуск"
 
Maryna Shulga "Mission Impossible. Впровадити тест процеси, якщо ніхто цього ...
Maryna Shulga "Mission Impossible. Впровадити тест процеси, якщо ніхто цього ...Maryna Shulga "Mission Impossible. Впровадити тест процеси, якщо ніхто цього ...
Maryna Shulga "Mission Impossible. Впровадити тест процеси, якщо ніхто цього ...
 
Олексій Брошков "Мистецтво Дослідницького Тестування"
Олексій Брошков "Мистецтво Дослідницького Тестування"Олексій Брошков "Мистецтво Дослідницького Тестування"
Олексій Брошков "Мистецтво Дослідницького Тестування"
 
Альона Тудан " Життя QA в ажурі"
Альона Тудан " Життя QA в ажурі"Альона Тудан " Життя QA в ажурі"
Альона Тудан " Життя QA в ажурі"
 
Андрій Степура "Тренди в публічних виступах"
Андрій Степура "Тренди в публічних виступах"Андрій Степура "Тренди в публічних виступах"
Андрій Степура "Тренди в публічних виступах"
 
Зоряна Борбулевич "Підхід, який трансформував компанію Microsoft: ННК і його...
Зоряна Борбулевич "Підхід, який трансформував компанію Microsoft:  ННК і його...Зоряна Борбулевич "Підхід, який трансформував компанію Microsoft:  ННК і його...
Зоряна Борбулевич "Підхід, який трансформував компанію Microsoft: ННК і його...
 

Олексій Стульніков “WinAppDriver – автоматизація Desktop ніколи не була такою простою”

  • 1.
  • 2. План доклада ● Вводное слово, о проекте, цели ● Что такое WinAppDriver ● Напишим наш первый тест, от простого к сложному ● Сложности в реальном проекте ● Советы и подведем итоги
  • 3. Для кого этот доклад, о проекте ● Проекту 5 лет ● 4 сервер разработчика + 2 клиент разработчика ● 2 тестировщика ● POS терминал .NET Framework 4.5, WPF ● Релизы: ○ крупные раз в 2-3 месяца ○ мелкие раз в 2-3 недели ● Требования меняются постоянно
  • 4. Тесты должны ● Быстро писаться ● Легко читаться ● Легко поддерживаться ● Стабильно работать ● Давать понятные отчеты
  • 5. Регрессия это скучно — автоматизация это весело Тесты должны ● Быстро писаться ● Легко читаться ● Легко поддерживаться ● Стабильно работать ● Давать понятные отчеты
  • 6.
  • 7.
  • 8. https://github.com/Microsoft/WinAppDriver WinAppDriver Если вы искали лучшую поддержку для использования Appium для тестирования приложений Windows, эта услуга для вас!
  • 9. Что нужно знать? Минимум: ● Понимание ООП ● Функции, Классы ● Понимание работы Selenium WebDriver
  • 10. Что нужно знать? Минимум: ● Понимание ООП ● Функции, Классы ● Понимание работы Selenium WebDriver Идеально: ● Один из языков программирования поддерживаемых WinAppDriver ● Паттерны Page Object, ... ● Опыт работы с Selenium или Appium ● Опыт работы с Jenkins, Allure
  • 13. - Переходие https://github.com/Microsoft/WinAppDriver/releases - Скачиваете WindowsApplicationDriver.msi - Устанавливайте - Включите Режим Разработчика под Windows! - Запускаеме cmd.exe - Запускаете WinAppDriver.exe с номером порта на котором хотите его использовать cd "C:Program Files (x86)Windows Application Driver" WinAppDriver.exe 4723 WinAppDriver установка и запуск
  • 14.
  • 15. Наш первый тест Тест - Деление на ноль: 1. Открыть приложение "Калькулятор" 2. Нажать кнопку "Три" 3. Нажать кнопку "Разделить" 4. Нажать кнопку "Ноль" 5. Нажать кнопку "Равно" 6. Проверить что показалось сообщение "Деление на ноль невозможно" 7. Закрыть приложение "Калькулятор"
  • 16. Наш первый тест Тест - Деление на ноль: 1. Открыть приложение "Калькулятор" 2. Нажать кнопку "Три" 3. Нажать кнопку "Разделить" 4. Нажать кнопку "Ноль" 5. Нажать кнопку "Равно" 6. Проверить что показалось сообщение "Деление на ноль невозможно" 7. Закрыть приложение "Калькулятор" def test_division_by_zero(): driver = webdriver.Remote( command_executor='http://127.0.0.1:4723', desired_capabilities={"app": "C:WindowsSystem32calc.exe"}) driver.find_element_by_name("Три").click() driver.find_element_by_name("Разделить на").click() driver.find_element_by_name("Ноль").click() driver.find_element_by_name("Равно").click() actual_result = driver.find_element_by_accessibility_id("CalculatorResults") assert actual_result.text == "Деление на ноль невозможно" driver.quit()
  • 17. Наш первый тест Тест - Деление на ноль: 1. Открыть приложение "Калькулятор" 2. Нажать кнопку "Три" 3. Нажать кнопку "Разделить" 4. Нажать кнопку "Ноль" 5. Нажать кнопку "Равно" 6. Проверить что показалось сообщение "Деление на ноль невозможно" 7. Закрыть приложение "Калькулятор" def test_division_by_zero(): driver = webdriver.Remote( command_executor='http://127.0.0.1:4723', desired_capabilities={"app": "C:WindowsSystem32calc.exe"}) driver.find_element_by_name("Три").click() driver.find_element_by_name("Разделить на").click() driver.find_element_by_name("Ноль").click() driver.find_element_by_name("Равно").click() actual_result = driver.find_element_by_accessibility_id("CalculatorResults") assert actual_result.text == "Деление на ноль невозможно" driver.quit()
  • 18. Наш первый тест Тест - Деление на ноль: 1. Открыть приложение "Калькулятор" 2. Нажать кнопку "Три" 3. Нажать кнопку "Разделить" 4. Нажать кнопку "Ноль" 5. Нажать кнопку "Равно" 6. Проверить что показалось сообщение "Деление на ноль невозможно" 7. Закрыть приложение "Калькулятор" def test_division_by_zero(): driver = webdriver.Remote( command_executor='http://127.0.0.1:4723', desired_capabilities={"app": "C:WindowsSystem32calc.exe"}) driver.find_element_by_name("Три").click() driver.find_element_by_name("Разделить на").click() driver.find_element_by_name("Ноль").click() driver.find_element_by_name("Равно").click() actual_result = driver.find_element_by_accessibility_id("CalculatorResults") assert actual_result.text == "Деление на ноль невозможно" driver.quit()
  • 19. Наш первый тест Тест - Деление на ноль: 1. Открыть приложение "Калькулятор" 2. Нажать кнопку "Три" 3. Нажать кнопку "Разделить" 4. Нажать кнопку "Ноль" 5. Нажать кнопку "Равно" 6. Проверить что показалось сообщение "Деление на ноль невозможно" 7. Закрыть приложение "Калькулятор" def test_division_by_zero(): driver = webdriver.Remote( command_executor='http://127.0.0.1:4723', desired_capabilities={"app": "C:WindowsSystem32calc.exe"}) driver.find_element_by_name("Три").click() driver.find_element_by_name("Разделить на").click() driver.find_element_by_name("Ноль").click() driver.find_element_by_name("Равно").click() actual_result = driver.find_element_by_accessibility_id("CalculatorResults") assert actual_result.text == "Деление на ноль невозможно" driver.quit()
  • 20. Наш первый тест Тест - Деление на ноль: 1. Открыть приложение "Калькулятор" 2. Нажать кнопку "Три" 3. Нажать кнопку "Разделить" 4. Нажать кнопку "Ноль" 5. Нажать кнопку "Равно" 6. Проверить что показалось сообщение "Деление на ноль невозможно" 7. Закрыть приложение "Калькулятор" def test_division_by_zero(): driver = webdriver.Remote( command_executor='http://127.0.0.1:4723', desired_capabilities={"app": "C:WindowsSystem32calc.exe"}) driver.find_element_by_name("Три").click() driver.find_element_by_name("Разделить на").click() driver.find_element_by_name("Ноль").click() driver.find_element_by_name("Равно").click() actual_result = driver.find_element_by_accessibility_id("CalculatorResults") assert actual_result.text == "Деление на ноль невозможно" driver.quit()
  • 21. Наш первый тест Тест - Деление на ноль: 1. Открыть приложение "Калькулятор" 2. Нажать кнопку "Три" 3. Нажать кнопку "Разделить" 4. Нажать кнопку "Ноль" 5. Нажать кнопку "Равно" 6. Проверить что показалось сообщение "Деление на ноль невозможно" 7. Закрыть приложение "Калькулятор" def test_division_by_zero(): driver = webdriver.Remote( command_executor='http://127.0.0.1:4723', desired_capabilities={"app": "C:WindowsSystem32calc.exe"}) driver.find_element_by_name("Три").click() driver.find_element_by_name("Разделить на").click() driver.find_element_by_name("Ноль").click() driver.find_element_by_name("Равно").click() actual_result = driver.find_element_by_accessibility_id("CalculatorResults") assert actual_result.text == "Деление на ноль невозможно" driver.quit()
  • 22. Наш первый тест Тест - Деление на ноль: 1. Открыть приложение "Калькулятор" 2. Нажать кнопку "Три" 3. Нажать кнопку "Разделить" 4. Нажать кнопку "Ноль" 5. Нажать кнопку "Равно" 6. Проверить что показалось сообщение "Деление на ноль невозможно" 7. Закрыть приложение "Калькулятор" def test_division_by_zero(): driver = webdriver.Remote( command_executor='http://127.0.0.1:4723', desired_capabilities={"app": "C:WindowsSystem32calc.exe"}) driver.find_element_by_name("Три").click() driver.find_element_by_name("Разделить на").click() driver.find_element_by_name("Ноль").click() driver.find_element_by_name("Равно").click() actual_result = driver.find_element_by_accessibility_id("CalculatorResults") assert actual_result.text == "Деление на ноль невозможно" driver.quit()
  • 23. Наш первый тест Тест - Деление на ноль: 1. Открыть приложение "Калькулятор" 2. Нажать кнопку "Три" 3. Нажать кнопку "Разделить" 4. Нажать кнопку "Ноль" 5. Нажать кнопку "Равно" 6. Проверить что показалось сообщение "Деление на ноль невозможно" 7. Закрыть приложение "Калькулятор" def test_division_by_zero(): driver = webdriver.Remote( command_executor='http://127.0.0.1:4723', desired_capabilities={"app": "C:WindowsSystem32calc.exe"}) driver.find_element_by_name("Три").click() driver.find_element_by_name("Разделить на").click() driver.find_element_by_name("Ноль").click() driver.find_element_by_name("Равно").click() actual_result = driver.find_element_by_accessibility_id("CalculatorResults") assert actual_result.text == "Деление на ноль невозможно" driver.quit()
  • 24. Наш первый тест Тест - Деление на ноль: 1. Открыть приложение "Калькулятор" 2. Нажать кнопку "Три" 3. Нажать кнопку "Разделить" 4. Нажать кнопку "Ноль" 5. Нажать кнопку "Равно" 6. Проверить что показалось сообщение "Деление на ноль невозможно" 7. Закрыть приложение "Калькулятор" def test_division_by_zero(): driver = webdriver.Remote( command_executor='http://127.0.0.1:4723', desired_capabilities={"app": "C:WindowsSystem32calc.exe"}) driver.find_element_by_name("Три").click() driver.find_element_by_name("Разделить на").click() driver.find_element_by_name("Ноль").click() driver.find_element_by_name("Равно").click() actual_result = driver.find_element_by_accessibility_id("CalculatorResults") assert actual_result.text == "Деление на ноль невозможно" driver.quit()
  • 25. Inspect — получаем ID элементов Тест - Деление на ноль: 1. Открыть приложение "Калькулятор" 2. Нажать кнопку "Три" 3. Нажать кнопку "Разделить" 4. Нажать кнопку "Ноль" 5. Нажать кнопку "Равно" 6. Проверить что показалось сообщение "Деление на ноль невозможно" 7. Закрыть приложение "Калькулятор" def test_division_by_zero(): driver = webdriver.Remote( command_executor='http://127.0.0.1:4723', desired_capabilities={"app": "C:WindowsSystem32calc.exe"}) driver.find_element_by_name("Три").click() driver.find_element_by_name("Разделить на").click() driver.find_element_by_name("Ноль").click() driver.find_element_by_name("Равно").click() actual_result = driver.find_element_by_accessibility_id("CalculatorResults") assert actual_result.text == "Деление на ноль невозможно" driver.quit()
  • 26. Inspect — получаем ID элементов https://msdn.microsoft.com/en-us/library/windows/desktop/dd318521(v=vs.85).aspx
  • 27. Inspect — получаем ID элементов Client API Locator Strategy Matched Attribute in inspect.exe Example FindElementByAccessibilityId accessibility id AutomationId AppNameTitle FindElementByClassName class name ClassName TextBlock FindElementByName name Name Calculator FindElementById id RuntimeId (decimal) 42.333896.3.1 FindElementByTagName tag name LocalizedControlType (upper camel case) Text FindElementByXPath xpath Any //Button[0]
  • 28. Проблемы: ● Запуск приложения, если поменяется директория или порт WinAppDriver
  • 29. @pytest.fixture(scope="module") def driver(): driver = webdriver.Remote( command_executor='http://127.0.0.1:4723', desired_capabilities={"app": "C:WindowsSystem32calc.exe"}) yield driver driver.quit() Fixtures = Pre-condition + Post-condition Pre-condition: Открыть приложение "Калькулятор" Steps: 1. Нажать кнопку "Три" 2. Нажать кнопку "Разделить" 3. Нажать кнопку "Ноль" 4. Нажать кнопку "Равно" 5. Проверить что показалось сообщение "Деление на ноль невозможно" Post-condition: Закрыть приложение "Калькулятор"
  • 30. @pytest.fixture(scope="module") def driver(): driver = webdriver.Remote( command_executor='http://127.0.0.1:4723', desired_capabilities={"app": "C:WindowsSystem32calc.exe"}) yield driver driver.quit() Fixtures = Pre-condition + Post-condition Pre-condition: Открыть приложение "Калькулятор" Steps: 1. Нажать кнопку "Три" 2. Нажать кнопку "Разделить" 3. Нажать кнопку "Ноль" 4. Нажать кнопку "Равно" 5. Проверить что показалось сообщение "Деление на ноль невозможно" Post-condition: Закрыть приложение "Калькулятор"
  • 31. @pytest.fixture(scope="module") def driver(): driver = webdriver.Remote( command_executor='http://127.0.0.1:4723', desired_capabilities={"app": "C:WindowsSystem32calc.exe"}) yield driver driver.quit() Fixtures = Pre-condition + Post-condition Pre-condition: Открыть приложение "Калькулятор" Steps: 1. Нажать кнопку "Три" 2. Нажать кнопку "Разделить" 3. Нажать кнопку "Ноль" 4. Нажать кнопку "Равно" 5. Проверить что показалось сообщение "Деление на ноль невозможно" Post-condition: Закрыть приложение "Калькулятор"
  • 32. test_calculator.py def test_division_by_zero(driver): driver.find_element_by_name("Три").click() driver.find_element_by_name("Разделить на").click() driver.find_element_by_name("Нуль").click() driver.find_element_by_name("Равно").click() actual_result = driver.find_element_by_accessibility_id("CalculatorResults").text assert actual_result == "Деление на ноль невозможно" Fixtures = Pre-condition + Post-condition conftest.py @pytest.fixture(scope="module") def driver(): driver = webdriver.Remote( command_executor='http://127.0.0.1:4723', desired_capabilities={"app": "C:WindowsSystem32calc.exe"}) yield driver driver.quit()
  • 33. conftest.py @pytest.fixture(scope="module") def driver(): driver = webdriver.Remote( command_executor='http://127.0.0.1:4723', desired_capabilities={"app": "C:WindowsSystem32calc.exe"}) yield driver driver.quit() test_calculator.py def test_division_by_zero(driver): driver.find_element_by_name("Три").click() driver.find_element_by_name("Разделить на").click() driver.find_element_by_name("Нуль").click() driver.find_element_by_name("Равно").click() actual_result = driver.find_element_by_accessibility_id("CalculatorResults").text assert actual_result == "Деление на ноль невозможно" Fixtures = Pre-condition + Post-condition
  • 34. Проблемы: ● Запуск приложения, если поменяется директория или порт WinAppDriver
  • 35. Рост кол-ва тестов и их размер def test_weird(driver): driver.find_element_by_name("Три").click() driver.find_element_by_name("Разделить на").click() driver.find_element_by_name("Нуль").click() driver.find_element_by_name("Равно").click() assert driver.find_element_by_accessibility_id("CalculatorResults").text == "Деление на ноль невозможно" driver.find_element_by_name("Меню").click() driver.find_element_by_name("Инженерный Калькулятор").click() driver.find_element_by_name("Три").click() driver.find_element_by_name("Десять в степени").click() assert driver.find_element_by_accessibility_id("CalculatorResults").text == "1000" driver.find_element_by_name("Меню").click() driver.find_element_by_name("Обычный Калькулятор").click()
  • 36. Рост кол-ва тестов и их размер def test_weird(driver): driver.find_element_by_name("Три").click() driver.find_element_by_name("Разделить на").click() driver.find_element_by_name("Нуль").click() driver.find_element_by_name("Равно").click() assert driver.find_element_by_accessibility_id("CalculatorResults").text == "Деление на ноль невозможно" driver.find_element_by_name("Меню").click() driver.find_element_by_name("Инженерный Калькулятор").click() driver.find_element_by_name("Три").click() driver.find_element_by_name("Десять в степени").click() assert driver.find_element_by_accessibility_id("CalculatorResults").text == "1000" driver.find_element_by_name("Меню").click() driver.find_element_by_name("Обычный Калькулятор").click() def test_addition(driver): driver.find_element_by_name("Три").click() driver.find_element_by_name("Плюс").click() driver.find_element_by_name("Два").click() driver.find_element_by_name("Равно").click() assert driver.find_element_by_accessibility_id("CalculatorResults").text == "5" driver.find_element_by_name("Очистить").click()
  • 37. И что с этим всем делать?
  • 38. Проблемы: ● Запуск приложения, если поменяется директория или порт WinAppDriver ● В больших тестах сложно понять на каком из экранов мы выполняем действие ● Если изменится ID или имя элемента нужно править в каждом тесте
  • 39. Screen Object standard.py class Standard(): def __init__(self, driver): self.driver = driver def click_one_button(self): self.driver.find_element_by_name("Один").click() def click_two_button(self): self.driver.find_element_by_name("Два").click() def click_three_button(self): self.driver.find_element_by_name("Три").click() def click_four_button(self): self.driver.find_element_by_name("Четыре").click() def ...
  • 40. Screen Object engineer.py class Engineer(): def __init__(self, driver): self.driver = driver def open_standard_calculator(self): self.driver.find_element_by_name("Меню").click() self.driver.find_element_by_name("Обычный Калькулятор").click() def ...
  • 41. Screen Object test_calculator.py def test_weird(driver): standard = Standard(driver=driver) engineer = Engineer(driver=driver) standard.click_three_button() standard.click_division_button() standard.click_zero_button() standard.click_equals_button() standard.check_result("Деление на ноль невозможно") standard.open_engineer_calculator() engineer.click_three_button() engineer.click_ten_in_degree_button() engineer.check_result("1000") engineer.open_standard_calculator()
  • 42. Screen Object class Base(): -> class Main(Base): -> class Standard(Main): Совет: Одинаковые методы выносите в Base класс, используйте наследование
  • 43. Проблемы: ● Запуск приложения, если поменяется директория или порт WinAppDriver ● В больших тестах сложно понять на каком из экранов мы выполняем действие ● Если изменится ID или имя элемента нужно править в каждом тесте
  • 44. @pytest.fixture(scope="module") def driver(): driver = webdriver.Remote( command_executor='http://127.0.0.1:4723', desired_capabilities={"app": "C:App"}) yield driver driver.quit() Хочу читаемые тесты test_calculator.py def test_weird(driver): standard = Standard(driver=driver) engineer = Engineer(driver=driver) standard.click_three_button() standard.click_division_button() standard.click_zero_button() standard.click_equals_button() standard.check_result("Деление на ноль невозможно") standard.open_engineer_calculator() engineer.click_three_button() engineer.click_ten_in_degree_button() engineer.check_result("1000") engineer.open_standard_calculator()
  • 45. Хочу читаемые тесты test_calculator.py def test_weird(driver): standard = Standard(driver=driver) engineer = Engineer(driver=driver) standard.click_three_button() standard.click_division_button() standard.click_zero_button() standard.click_equals_button() standard.check_result("Деление на ноль невозможно") standard.open_engineer_calculator() engineer.click_three_button() engineer.click_ten_in_degree_button() engineer.check_result("1000") engineer.open_standard_calculator() test_calculator.py def test_weird(driver): standard = Standard(driver=driver) engineer = Engineer(driver=driver) standard .click_three_button() .click_division_button() .click_zero_button() .click_equals_button() .check_result("Деление на ноль невозможно") .open_engineer_calculator() engineer .click_three_button() .click_ten_in_degree_button() .check_result("1000") .open_standard_calculator()
  • 46. Проблемы: ● Запуск приложения, если поменяется директория или порт WinAppDriver ● В больших тестах сложно понять на каком из экранов мы выполняем действие ● Если изменится ID или имя элемента нужно править в каждом тесте ● Тесты недостаточно читаемые!
  • 47. Хочу читаемые тесты engineer.py class Engineer(): def __init__(self, driver): self.driver = driver def click_three_button(self): self.driver.find_element_by_name("Три").click() def open_engineer_calculator(self): self.driver.find_element_by_name("Меню").click() self.driver.find_element_by_name("Обычный Калькулятор").click()
  • 48. Хочу читаемые тесты engineer.py class Engineer(): def __init__(self, driver): self.driver = driver def click_three_button(self): self.driver.find_element_by_name("Три").click() return self - добавить после шагов def open_engineer_calculator(self): self.driver.find_element_by_name("Меню").click() self.driver.find_element_by_name("Обычный Калькулятор").click() return self - добавить после шагов
  • 49. Chains standard.click_three_button() standard.click_division_button() standard.click_zero_button() standard.click_equals_button() standard.check_result("Деление на ноль невозможно") standard.open_engineer_calculator() standard .click_three_button() .click_division_button() .click_zero_button() .click_equals_button() .check_result("Деление на ноль невозможно") .open_engineer_calculator() standard.click_three_button().click_division_button().click_zero_button().click_equals_button().....
  • 50. Проблемы: ● Запуск приложения, если поменяется директория или порт WinAppDriver ● В больших тестах сложно понять на каком из экранов мы выполняем действие ● Если изменится ID или имя элемента нужно править в каждом тесте ● Тесты недостаточно читаемые!
  • 51.
  • 52. Проблемы: ● Запуск приложения, если поменяется директория или порт WinAppDriver ● В больших тестах сложно понять на каком из экранов мы выполняем действие ● Если изменится ID или имя элемента нужно править в каждом тесте ● Тесты недостаточно читаемые! ● Отчеты сложно анализировать
  • 53.
  • 54. Хочу удобные и понятные отчеты engineer.py class Engineer(): def __init__(self, driver): self.driver = driver def click_three_button(self): self.driver.find_element_by_name("Три").click() return self def open_engineer_calculator(self): self.driver.find_element_by_name("Меню").click() self.driver.find_element_by_name("Обычный Калькулятор").click() return self engineer.py class Engineer(): def __init__(self, driver): self.driver = driver def click_three_button(self): self.driver.find_element_by_name("Три").click() return self def open_engineer_calculator(self): self.driver.find_element_by_name("Меню").click() self.driver.find_element_by_name("Обычный Калькулятор").click() return self
  • 55. Хочу удобные и понятные отчеты engineer.py class Engineer(): def __init__(self, driver): self.driver = driver def click_three_button(self): self.driver.find_element_by_name("Три").click() return self def open_engineer_calculator(self): self.driver.find_element_by_name("Меню").click() self.driver.find_element_by_name("Обычный Калькулятор").click() return self engineer.py class Engineer(): def __init__(self, driver): self.driver = driver def click_three_button(self): with allure.step('Нажать кнопку "Три"'): - добавить перед шагами self.driver.find_element_by_name("Три").click() return self def open_engineer_calculator(self): with allure.step('Открыть "Обычный калькулятор"'): - добавить перед шагами self.driver.find_element_by_name("Меню").click() self.driver.find_element_by_name("Обычный Калькулятор").click() return self
  • 56. Хочу удобные и понятные отчеты engineer.py class Engineer(): def __init__(self, driver): self.driver = driver def click_three_button(self): with allure.step('Нажать кнопку "Три"'): self.driver.find_element_by_name("Три").click() return self def open_engineer_calculator(self): with allure.step('Открыть "Обычный калькулятор"'): self.driver.find_element_by_name("Меню").click() self.driver.find_element_by_name("Обычный Калькулятор").click() return self
  • 57. Хочу удобные и понятные отчеты engineer.py class Engineer(): def __init__(self, driver): self.driver = driver def check_result(self, result): with allure.step('Проверить что результат равен "{}"'.format(result)): allure.attach(self.driver.get_screenshot_as_png(), 'ScreenShotName', attachment_type=allure.attachment_type.PNG) actual_result = self.driver.find_element_by_accessibility_id("CalculatorResults").text assert actual_result == result, 'Полученный результат "{}" не равен ожидаемому "{}"'.format(actual_result, result) return self
  • 58. Хочу удобные и понятные отчеты engineer.py class Engineer(): def __init__(self, driver): self.driver = driver def check_result(self, result): with allure.step('Проверить что результат равен "{}"'.format(result)): allure.attach(self.driver.get_screenshot_as_png(), 'ScreenShotName', attachment_type=allure.attachment_type.PNG) actual_result = self.driver.find_element_by_accessibility_id("CalculatorResults").text assert actual_result == result, 'Полученный результат "{}" не равен ожидаемому "{}"'.format(actual_result, result) return self
  • 59. Хочу удобные и понятные отчеты @allure.feature('Standard') @allure.story('Math') class TestCalculator: def test_addition(self, driver): standard = Standard(driver=driver) standard .click_three_button() .click_plus_button() .click_three_button() .click_equals_button() .check_result("6") def test_subtraction(self, driver): standard = Standard(driver=driver) standard .click_three_button() .click_minus_button() .click_one_button() .click_equals_button() .check_result("2")
  • 61. Проблемы: ● Запуск приложения, если поменяется директория или порт WinAppDriver ● В больших тестах сложно понять на каком из экранов мы выполняем действие ● Если изменится ID или имя элемента нужно править в каждом тесте ● Тесты недостаточно читаемые! ● Отчеты сложно анализировать
  • 62. Проблемы: ● Запуск приложения, если поменяется директория или порт WinAppDriver ● В больших тестах сложно понять на каком из экранов мы выполняем действие ● Если изменится ID или имя элемента нужно править в каждом тесте ● Тесты недостаточно читаемые! ● Отчеты сложно анализировать ● WinAppDriver используем указатель мыши для действия с элементами
  • 63. Jenkins, запуск тестов Зачем он нужен? ● Запуск по расписанию или после push-а изменений в git репозиторий ● Можно пользоваться мышью в момент прогона тестов ● Интеграция отчетов ● Continuous Integration Oracle VM VirtualBox VBoxHeadlessTray Настроенная среда для тестов http://www.toptensoftware.com/vboxheadlesstray/
  • 64. Проблемы: ● Запуск приложения, если поменяется директория или порт WinAppDriver ● В больших тестах сложно понять на каком из экранов мы выполняем действие ● Если изменится ID или имя элемента нужно править в каждом тесте ● Тесты недостаточно читаемые! ● Отчеты сложно анализировать ● WinAppDriver используем указатель мыши для действия с элементами
  • 65. Сложности с которыми столкнулись, в реальном проекте ● Правильные локаторы ● Переключение между окнами ● Ожидание появления элементов ● Откат приложения в исходное состояние
  • 66. Правильные локаторы driver.find_element s_by_name('Continue')[1].click() driver.find_element s_by_accessibility_id( 'TextBox')[2].send_keys( price) driver.find_element_by_accessibility_id( 'JournalContinueButton' ).click() driver.find_element_by_accessibility_id( 'CalculatorPriceTextBox' ).send_keys( price) Вывод: Правильные локаторы = Взаимодействие с разработчиками
  • 67. test.py menu .open_category('Фрукты') .add_product_to_cart('Яблоко') 1. Open "Фрукты" category 2. Add product "Яблоко" to cart menu.py def add_product_to_cart(self, product): with allure.step('Add product "' + product + '" to cart'): try: self.driver.find_element_by_accessibility_id(product).click() except NoSuchElementException: + добавить скриншот raise NoSuchElementException( 'Product "{}" is not found'.format(product)) return self Правильные локаторы AutomationID — упрощает работу Для списков “продуктов”, AutomationID = Название продукта
  • 68. Переключение между окнами def open_file_menu (driver): driver.find_element_by_name( "Файл").click() driver.switch_to.window( driver.current_window_handle)
  • 69. Переключение между окнами driver.switch_to.window( driver.window_handles[ 0]) Login Login screen Logout Application
  • 70. Переключение между окнами driver.switch_to.window( driver.window_handles[ 0]) Login Login screen Logout ApplicationЗагрузка
  • 71. Работа с умными ожиданиями def wait_for_element_to_appear(self, element, delay=15): i = 0 while i < delay: try: self.driver.switch_to.window( self.driver.window_handles[0]) self.driver.find_element_by_accessibility_id(element) break except Exception as exception: time.sleep(0.2) i += 0.2 return self https://youtu.be/cA1A2DzZGGI Добавляем скриншоты, выводим коды ошибки, получаем супер умное ожидание - переключиться на активное окно - попробуй найти элемент - все хорошо выйти из цикла - если не найден, подождать и снова попробовать найти элемент
  • 72. ● Проверка на открытое окно, если открыто закрыть ● Взаимодействуйте с разработчиками ● Используйте RPC (Remote Procedure Call) ● Подключение по SSH, консольные команды Откат приложения в исходное состояние
  • 73. Советы Сложно писать тесты - Используйте Test Data Недостаточно отладочной информации - Используйте print() - Или logging - Получаем полезную информацию в консоль Тесты должны показывать результат - Портите тесты, смотрите результаты Решайте проблемы по мере их появления Не изобретайте свой велосипед
  • 74. ● Быстро внедрили автоматизацию ● Тесты стабильные и их легко поддерживать ● Тесты быстро пишутся ● Предоставляет понятные отчеты Что получили в итоге и выводы