В этом посте я бы хотел рассказать о разработанной микробиблиотеке SOM для jython, которую планирую применить для тестирования одного нативного легаси-проекта. SOM является враппером над Sikuli.
C нативными приложениями такая беда, что там нет selenium’a, который более менее частично решает проблемы автоматизации. Хорошо, если разработчики нативного приложения озаботились качеством и сделали инфраструктуру для функциональных тестов н-р на gtest. Плохо, когда это не так. Тогда и приходится выкручиться, используя такую библиотеку как Sikuli, которая базируется на распознавании изображений на экране и выполнении действий над распознанным участком экрана (посыл кликов или текста).
Поигравшись с sikuli и jython, стало понятно, что это довольно низкоуровневая библиотека и писать спагетти-код совсем не хочется. А хочется высокоуровневый API и интуитивно понятные методы. Так появился SOM.
Для контроля над элементом SOM использует контрольные точки - небольшие скриншоты элемента, которые его однозначно характеризуют. Используя sikuli, SOM определяет область экрана внутри которого лежат эти контрольные точки, и считает его областью элемента. При этом можно вкладывать один элемент в другой, и тогда SOM будет искать один элемент только внутри области другого, соблюдая иерархию.
Подробную информацию можно посмотреть в readme проекта.
Вот пример, как выглядит декларация приложения, шагов и тестов с использованием SOM и jython:
# application and elements registration
def create_ff():
som.Element.set_elements_dir(
os.path.join(os.getcwd(), "example", "elements"))
ff = som.Application("firefox")
ff.set_children(
address_bar=som.Element("address-bar"),
yandex=som.Element("yandex"),
github=som.Element("github"))
return ff
# steps to manage application
class Steps(object):
def __init__(self):
som.load_sikuli(tuneup_sikuli)
self._ff = create_ff()
def launch_firefox(self):
self._ff.launch()
def open_web_page(self, url):
self._ff.address_bar.set_text(url, enter=True)
if url.startswith("https://yandex"):
self._ff.yandex.wait_for_visible()
self._ff.yandex.screenshot()
if url.startswith("https://github"):
self._ff.github.wait_for_visible()
self._ff.github.screenshot()
def close_firefox(self):
self._ff.close()
# tests
class MyTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
global S
S = steps.Steps()
def setUp(self):
S.launch_firefox()
def tearDown(self):
S.close_firefox()
def test_open_yandex(self):
S.open_web_page("https://yandex.ru")
def test_open_github(self):
S.open_web_page("https://github.com")
Видео с запуском тестов:
Такой подход с распознанием изображений на экране вряд ли когда-либо приблизится по скорости, стабильности и гибкости к тестам, которые являются частью проекта. Но думаю, что базовые кейсы покрыть удастся.