Вы тестировщик QA и хотите погрузиться в тестирование производительности без необходимости обширных знаний в области программирования? В этой статье мы рассмотрим доступный для непрограммистов способ проведения своего рода нагрузочного тестирования API облачных приложений с использованием Python . Нагрузочное тестирование без необходимости сложного кодирования — узнайте, как даже обычные тестировщики QA могут использовать Python для поиска серьезных ошибок и выявления потенциальных узких мест в производительности.
Тестирование производительности — важнейший аспект обеспечения способности ваших приложений соответствовать реальным требованиям. Я попытаюсь объяснить свой подход и сценарии Python, предназначенные для нагрузочного тестирования облачного сервиса, управляющего браузерами.
Сценарий нагрузочного тестирования Представьте себе облачный сервис, отвечающий за управление профилями браузеров (браузеры для очистки веб-страниц). Пользователи взаимодействуют через API с сервисом для создания, запуска, остановки, удаления и т. д. профилей. Мой сценарий Python имитирует этот сценарий, загружая облачный сервис путем многократного выполнения этих действий.
# Dependencies import asyncio import httpx # Configuration API_HOST = 'https://cloud.io' API_KEY = 'qatest' API_HEADERS = { "x-cloud-api-token": API_KEY, "Content-Type": "application/json" } CYCLES_COUNT = 3 # Browser profile configuration data_start = { "proxy": "http://127.0.0.1:8080", "browser_settings": {"inactive_kill_timeout": 120} }
get_profiles
извлекает существующие профили браузера из службы, имитируя сценарий, в котором пользователи запрашивают информацию. async def get_profiles(cl: httpx.AsyncClient): resp = await cl.get(f'{API_HOST}/profiles', params={'page_len': 10, 'page': 0}, headers=API_HEADERS) return resp.json()
async def start_profile(cl: httpx.AsyncClient, uuid): resp = await cl.post(f'{API_HOST}/profiles/{id}/start', json=data_start, headers=API_HEADERS) if error := resp.json().get('error'): print(f'Profile {id} not started with error {error}')
async def stop_profile(cl: httpx.AsyncClient, uuid): resp = await cl.post(f'{API_HOST}/profiles/{id}/stop', headers=API_HEADERS) if error := resp.json().get('error'): print(f'Profile {id} not stopped with error {error}') async def delete_profile(cl: httpx.AsyncClient, uuid): resp = await cl.delete(f'{API_HOST}/profiles/{id}', headers=API_HEADERS) if error := resp.json().get('error'): print(f'Profile {id} not stopped with error {error}')
for conn in cl._transport._pool.connections: if conn._connection._state.value != 1: continue print(f'Connection in progress: {conn}')
Функция main управляет циклами нагрузочного тестирования, проходя по профилям и выполняя асинхронные задачи. Каждый цикл представляет собой моделируемое взаимодействие пользователя, создание, использование и удаление профилей браузера.
async def main(): async with httpx.AsyncClient(timeout=httpx.Timeout(timeout=300)) as cl: for _ in range(CYCLES_COUNT): profiles = await get_profiles(cl) start_tasks = [asyncio.create_task(start_profile(cl, profile['id'])) for profile in profiles] await asyncio.gather(*start_tasks) active_browsers = await get_active_profiles(cl) stop_tasks = [asyncio.create_task(stop_profile(cl, active_browser['id'])) for active_browser in active_browsers['data']] await asyncio.gather(*stop_tasks) profiles = await get_profiles(cl) del_tasks = [asyncio.create_task(delete_profile(cl, profile['id'])) for profile in profiles] await asyncio.gather(*del_tasks) # Monitor active connections for insights into load impact
Этот сценарий показывает, как специалисты по обеспечению качества могут адаптировать сценарии нагрузочного тестирования к своим приложениям. Настраивая количество циклов, корректируя взаимодействие с пользователем и изменяя сценарий для соответствия конкретным конечным точкам API, тестировщики могут получить ценную информацию о производительности своего приложения при различных нагрузках. Здесь вам понадобятся необходимые инструменты мониторинга, чтобы получить информацию о состоянии сервера, оценить нагрузку на сервер и отслеживать использование ресурсов и журналы. Используйте такие инструменты, как Grafana, Kibana, Prometheus и т. д., для комплексного мониторинга. Кроме того, внимательно следите за ответами, которые получает ваш сценарий, чтобы обеспечить тщательную оценку производительности вашего приложения. Этот подход неоценим для эффективного нагрузочного тестирования и анализа производительности.
Кроме того, для более реалистичной симуляции загрузки рассмотрите возможность открытия определенных страниц в браузере. Хотя я лично использовал стартовую страницу в своих браузерах, вы также можете использовать такие параметры, как Pyppeteer или Playwright, чтобы открывать несколько вкладок и перемещаться по различным страницам. Такой подход повышает достоверность сценария нагрузочного тестирования, очень напоминающего взаимодействие пользователя с вашим приложением.
# Attempt to connect to the browser using the provided profile URL try: browser = await connect({'browserWSEndpoint': browser_url, 'defaultViewport': None}) except Exception as e: # Handle connection errors and print a message print(f'Error occurred when connecting to the browser: {str(e)}') return # Create a new page in the connected browser page = await browser.newPage() # Introduce a brief delay to ensure the page is ready await asyncio.sleep(2) # Set the viewport dimensions for the page width, height = 1920, 1080 await page.setViewport({'width': width, 'height': height}) # Try to navigate to a specific URL try: await page.goto('https://{your_website}') # Wait for 10 seconds to simulate user interaction await page.waitFor(10000) # Introduce another delay for additional stability await asyncio.sleep(5) except pyppeteer.errors.PageError as e: # Handle page navigation errors and print a message print(f'Error occurred during page navigation: {str(e)}') # Attempt to take a screenshot of the page try: await page.screenshot(path='screen.png', fullPage=True) # Print a success message if the screenshot is captured successfully print('Screenshot taken successfully.') except Exception as e: # Handle screenshot capture errors and print a message print(f'Error occurred during taking a screenshot: {str(e)}')
Асинхронные возможности Python в сочетании с библиотеками HTTP делают его универсальным инструментом для нагрузочного тестирования облачных систем. Этот пример служит отправной точкой для инженеров по контролю качества, желающих изучить возможности Python в своих попытках нагрузочного тестирования.
ПРИМЕЧАНИЕ
В моем сценарии описанный сценарий оказался надежным и эффективным. Он послужил полезным инструментом в выявлении и решении многочисленных проблем. Агрессивный характер сценария позволил выявить критические проблемы, облегчить эффективную отладку и проложить путь к беспрепятственному и улучшенному пользовательскому интерфейсу, что очень хорошо для QA.
В продолжении я кратко расскажу о другом сценарии, использующем многопроцессорный модуль Python. Этот подход направлен на улучшение генерации нагрузки за счет одновременного выполнения нескольких экземпляров сценария тестирования. Основная цель многопроцессорной обработки — распараллелить выполнение сценария, обеспечивая одновременное взаимодействие со службой. Этот подход контрастирует с обсуждавшимся ранее асинхронным подходом, в котором задачи выполняются последовательно, но управляются одновременно. Это больше похоже на спам/ддосы с теми же запросами, но тоже может быть очень полезно.
def get_profiles(): response = requests.get(url=f"{api}", params=PARAMS, headers=headers) return response
def start_profiles(list_of_profiles_uuids): for uuid in list_of_profiles_uuids: # ... (API request to start profile) def stop_profiles(internal_uuids): for uuid in internal_uuids: # ... (API request to stop profile) def run_script(): start_profiles(get_profile_ids()) stop_profiles(list_of_ids)
if __name__ == "__main__": for runs in range(0, 5): processes = [] for i in range(20): p = multiprocessing.Process(target=run_script) processes.append(p) p.start() for p in processes: p.join()
Многопроцессорность обеспечивает стратегию нагрузочного тестирования приложений. Это позволяет инженерам по обеспечению качества экспериментировать с различными методологиями, основанными на уникальных характеристиках их приложений. В то время как асинхронное тестирование обеспечивает эффективность управления параллельными задачами, многопроцессорность превосходно распараллеливает весь процесс тестирования. Вы можете выбрать подход, который лучше всего соответствует конкретным целям нагрузочного тестирования и требованиям приложений.
Краткое напоминание:
Целью этой демонстрации является представление основных понятий в формате, удобном для новичков, и подчеркивание простоты Python для тестировщиков QA, решающихся заняться тестированием производительности.
Если у вас есть проблемы с программированием, не стесняйтесь обращаться к Google и спрашивать коллег, используйте ChatGPT или аналогичные инструменты, а также используйте GitHub Copilot для получения дополнительной помощи в написании сценариев нагрузочного тестирования.
Также опубликовано здесь .