В данной статье отражена попытка применить модель детекции для UI-тестирования.
Предполагалось, что внедрение ML должно позволить (даже при полном изменении интерфейса) не переписывать автотесты и полностью исключить человеческий фактор при UI-тестировании.
Для автоматизации UI-тестировании использовались следующие инструменты:
Selenium – инструмент для автоматизации действий с браузером;
Pytest – инструмент для выполнения и проверки тестовых сценариев;
ML – обученная модель машинного обучения.
Для эксперимента была выбрана модель YOLOv8m. Для обучения модели применялся датасет от компании Ultralytics – Website Screenshots Datase, который представляет собой набор данных скриншотов 1 206 веб-сайтов. К большому сожалению в данном датасете наибольшую часть классов представляют собой button (кнопки), что сильно сказалось на качестве распознавания других классов.
Обучение модели:
!nvidia-smi
import os
HOME = os.getcwd()
print(HOME)
!pip install ultralytics==8.0.196
from IPython import display
display.clear_output()
import ultralytics
ultralytics.checks()
from ultralytics import YOLO
from IPython.display import display, Image
!mkdir {HOME}/datasets
!pip install roboflow --quiet
!pip install roboflow
from roboflow import Roboflow
rf = Roboflow(api_key="5Mar5Cz54g9Sq0KSRc8x")
project = rf.workspace("roboflow-gw7yv").project("website-screenshots")
dataset = project.version(1).download("yolov8")
!yolo task=detect mode=train model=yolov8m.pt data={dataset.location}/data.yaml epochs=50 imgsz=800 plots=True
!ls {HOME}/runs/detect/train/
Image(filename=f'{HOME}/runs/detect/train/confusion_matrix.png', width=600)
Image(filename=f'{HOME}/runs/detect/train/results.png', width=600)
Image(filename=f'{HOME}/runs/detect/train/val_batch0_pred.jpg', width=600)
!yolo task=detect mode=val model={HOME}/runs/detect/train/weights/best.pt data={dataset.location}/data.yaml
from google.colab import drive
drive.mount('/content/drive')
import shutil
import os
os.getcwd()
sourcePath = "/content/runs/detect/train/weights/best.pt"
destinationPath = "/content/drive/MyDrive/best.pt"
shutil.copyfile(sourcePath, destinationPath)
!yolo task=detect mode=predict model={HOME}/runs/detect/train/weights/best.pt conf=0.25 source={dataset.location}/test/images save=True
import glob
from IPython.display import Image, display
for image_path in glob.glob(f'{HOME}/runs/detect/predict/*.jpg')[:3]:
display(Image(filename=image_path, width=600))
print("\n")
project.version(dataset.version).deploy(model_type="yolov8", model_path=f"{HOME}/runs/detect/train/")
model = project.version(dataset.version).model
import os, random
test_set_loc = dataset.location + "/test/images/"
random_test_image = random.choice(os.listdir(test_set_loc))
print("running inference on " + random_test_image)
pred = model.predict(test_set_loc + random_test_image, confidence=40, overlap=30).json()
pred
from ultralytics import YOLO
model.export()
Упрощенно процесс автоматизации UI-тестирования выглядит следующим образом (на примере распознавания кнопок):
1. С помощью Selenium создается скриншот веб-сайта.
2. Полученный скриншот сохраняется, а затем передается в обученную модель.
3. Модель находит нужные классы.
4. Затем, модель определяет координаты всех распознанных изображе��ий и возвращает результат в виде json формата с указанием центра координат объекта – x и y и ширину и высоту распознанного объекта.
5. Найденные координаты передаются в Selenium и с помощью Pytest проверяется корректность работы найденного объекта.
Тестирование работы кнопки с помощью предварительно обученной модели YOLOv8m:
from selenium import webdriver
from selenium.webdriver.common.by import By
import time
from selenium.webdriver.common.action_chains import ActionChains
import pytest
import json
from PIL import Image
import easyocr
from ultralytics import YOLO
@pytest.fixture
def browser():
driver = webdriver.Firefox()
yield driver
driver.quit()
def test_ckic(browser):
browser.set_window_size(1024,768)
browser.get("https://guru.qahacking.ru")
path = "sait_1.png"
browser.save_screenshot(path)
model = YOLO('best.pt')
prediction = model.predict(path)
for r in prediction:
x=r.tojson()
elements = json.loads(x)
text=[]
button=[]
for i in elements:
if i['name']=='text':
text.append(i)
if i['name']=='button':
button.append(i)
im = Image.open(path)
for i in button:
x1=int(i['box']['x1'])
x2=int(i['box']['x2'])
y1=int(i['box']['y1'])
y2=int(i['box']['y2'])
im_crop = im.crop((x1, y1, x2, y2))
im_crop.save('imeg.png')
print(easyocr.Reader(["ru"]).readtext('imeg.png', detail=0, paragraph=True, text_threshold=0.8))
actions = ActionChains(browser)
actions.move_by_offset(x1, y1).perform()
time.sleep(5)
actions.click().perform()
time.sleep(5)
assert browser.current_url == 'https://ermita.one/matricy-kompetencij/'
Спасибо за внимание.