Playwright — запускаємо тести одночасно for fun

Усі статті, обговорення, новини про тестування — в одному місці. Підписуйтеся на QA DOU!

Привіт друзі! Нещодавно відкрив для себе новий інструмент для автоматизації тестування — Playwright. Точніше, читав про нього ще весною, але тоді він був ще сирий та працював тільки з JS. Зараз же повністю підтримується і для мови Python (моя основна мова програмування, наразі), що і змусило мене спробувати написати кілька тестів.

Ну я і спробував. А потім ще. А потім зробив невеликий проєкт на pytest — Супер! Страждань набагато менше, ніж зазвичай при роботі з Selenium. А ще круті фічі типу перехоплення мережевих запитів

Але сьогодні не про це. Коли читаєш документацію, перші ж приклади показуть, як працювати з інструментом синхронно та асинхронно. Приклади працюють однаково і відрізняються лише стилем написання.

«Синхронний варіант простіший» — подумав я. Менше коду, краща читабельність. «Напевне, асинхронний варіант мені ніколи не знадобиться. Така собі крута фіча, про яку всі говорять, але не використовують»...

Не пройшло і місяця, постає переді мною цікаве завдання — замовник хоче бути впевненим, що під час одночасного відкриття програми всі користувачі бачать коректні дані. Фізично.

І моя ж перша думка — чому б не зробити не дуже практичний, але дуже наглядний тест, знаю я один інструмент, що вміє в асинхронні операції ;) А ще не буде потреби робити OAuth 2.0 авторизацію.

Disclaimer. Я в курсі, що можна зробити крутий та ефективний тест навантаження за допомоги того ж JMeter, але то буде не так весело.

Для початку треба встановити playwright. Робив це за документацією (посилання вище).

Отже, для початку напишемо тест, а точніше 3 тести в одному:

  • Зайти на сайт
  • перейти на одну з трьох сторінок через меню навігації
  • перевірити назву сторінки
В оригіналі тест логінився унікальним користувачем в кожному потоці, але для того, щоб ви мали змогу скопіювати та запустити — я спростив його.
import asyncio
from playwright import async_playwright
from playwright.browser import Browser
import random

BASE_URL = 'https://qamania.org/'
PAGES = (('Home', 'QA Mania'), ('Blog', 'Blog'), ('Useful links', 'Useful links'))


# тут можна передати логін/пароль
async def open_test(browser: Browser, data: tuple, id: int):
   print(f'start #{id} thread')
   context = await browser.newContext()
   page = await context.newPage()
   await page.goto(BASE_URL)
   await page.click(f'text={data[0]}')
   title = await page.title()
   result = 'ok' if data[1] in title else 'not ok'
   print(f'Thread #{id}: result for page {data[0]} --> {result}')
   await page.close()
   await context.close()

Я створив функцію тесту, що приймає екземпляр браузеру і специфічні дані для тесту, робить описані кроки і закриває сторінку.

Тепер зробимо головну функцію, що буде запускати playwright (важливо, щоб він запускався лише 1 раз). Створюємо браузер, вказавши headless=False, щоб бачити процес виконання, та масив для задач, що будуть виконуватись одночасно. Масив заповнюємо викликом функції open_test. Якщо викликати її без аргументу await, то повернеться асинхронна задача, що має бути виконана.
Далі передаємо масив задач у функцію asyncio.gather, що, згідно документації, використовується для одночасного виконання. Не пропустіть, що масив треба передати з *, оскільки функція gather приймає *args

І відразу ж останній крок — сказати модулю asyncio виконати головну функцію. Все готово.

async def main():
   print('start main')
   async with async_playwright() as p:
       browser = await p.chromium.launch(headless=False)
       tasks = list()
       for thread in range(10):
           tasks.append(open_test(browser, random.choice(PAGES), thread))
       await asyncio.gather(*tasks)
       await browser.close()


asyncio.run(main())

Запускаємо і бачимо наступну красу:

Все працює! ОДНОЧАСНО! Сам не знаю чому, але мені дуже подобається, як це виглядає.

Також під час виконання стало цікаво, скільки ресурсів потребує такий тест?
Коли відкривається 1 сторінка браузеру Chromium, вона з’їдає 25-30 МБ оперативної пам’яті, Firefox — 30-50 МБ. Тож не треба розраховувати на проведення тестування навантаження таким чином.

Власне, це все, чим я хотів поділитись . Було цікаво?

👍ПодобаєтьсяСподобалось1
До обраногоВ обраному2
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Не пройшло і місяця, постає переді мною цікаве завдання — замовник хоче бути впевненим, що під час одночасного відкриття програми всі користувачі бачать коректні дані. Фізично.

Дуже дивний запит від замовника, що саме може піти не так?

І доречі ваш код працює НЕ паралельно.

yosefk.com/...​need-different-tools.html

тут ви мене підловили — дійсно, правильно було написати одночасно (concurrent), як це і називається в документації asyncio docs.python.org/...​unning-tasks-concurrently

І гарна сттаття, дякую!

Дуже цікаво, дякую, на днях треба спробувати.
А як щодо асинхронного виконання в pytest?

Я тестив — там є нюанси, ще не розібрався. До пайтест є плагін, але в мене працювати не став. Напишу інший допис, як розберусь :)

Встановив плагін pytest-xdist, все працює паралельно. Без змін в коді. Вже готую дописп про сетап пайтесту

Підписатись на коментарі