Зоряна Борбулевич "Підхід, який трансформував компанію Microsoft: ННК і його...
Олексій Стульніков “WinAppDriver – автоматизація Desktop ніколи не була такою простою”
1.
2. План доклада
● Вводное слово, о проекте, цели
● Что такое WinAppDriver
● Напишим наш первый тест, от простого к сложному
● Сложности в реальном проекте
● Советы и подведем итоги
3. Для кого этот доклад,
о проекте
● Проекту 5 лет
● 4 сервер разработчика + 2 клиент разработчика
● 2 тестировщика
● POS терминал .NET Framework 4.5, WPF
● Релизы:
○ крупные раз в 2-3 месяца
○ мелкие раз в 2-3 недели
● Требования меняются постоянно
4. Тесты должны
● Быстро писаться
● Легко читаться
● Легко поддерживаться
● Стабильно работать
● Давать понятные отчеты
5. Регрессия это скучно —
автоматизация это весело
Тесты должны
● Быстро писаться
● Легко читаться
● Легко поддерживаться
● Стабильно работать
● Давать понятные отчеты
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]
38. Проблемы:
● Запуск приложения, если поменяется
директория или порт WinAppDriver
● В больших тестах сложно понять
на каком из экранов мы выполняем
действие
● Если изменится ID или имя элемента
нужно править в каждом тесте
42. Screen Object
class Base(): -> class Main(Base): -> class Standard(Main):
Совет:
Одинаковые методы выносите в Base класс,
используйте наследование
43. Проблемы:
● Запуск приложения, если поменяется
директория или порт WinAppDriver
● В больших тестах сложно понять
на каком из экранов мы выполняем
действие
● Если изменится ID или имя элемента
нужно править в каждом тесте
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 или имя элемента
нужно править в каждом тесте
● Тесты недостаточно читаемые!
50. Проблемы:
● Запуск приложения, если поменяется
директория или порт WinAppDriver
● В больших тестах сложно понять
на каком из экранов мы выполняем
действие
● Если изменится ID или имя элемента
нужно править в каждом тесте
● Тесты недостаточно читаемые!
51.
52. Проблемы:
● Запуск приложения, если поменяется
директория или порт WinAppDriver
● В больших тестах сложно понять
на каком из экранов мы выполняем
действие
● Если изменится ID или имя элемента
нужно править в каждом тесте
● Тесты недостаточно читаемые!
● Отчеты сложно анализировать
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. Сложности с которыми столкнулись,
в реальном проекте
● Правильные локаторы
● Переключение между окнами
● Ожидание появления элементов
● Откат приложения в исходное состояние
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. ● Быстро внедрили автоматизацию
● Тесты стабильные
и их легко поддерживать
● Тесты быстро пишутся
● Предоставляет понятные отчеты
Что получили в итоге
и выводы