¿Es usted un evaluador de control de calidad y está ansioso por sumergirse en las pruebas de rendimiento sin la necesidad de tener una amplia experiencia en programación? En este artículo, exploraremos una forma accesible para que los no programadores realicen algún tipo de prueba de carga en las API de aplicaciones en la nube usando Python . Pruebas de carga sin necesidad de codificación compleja: descubra cómo incluso los evaluadores de control de calidad habituales pueden utilizar Python para encontrar errores graves y descubrir posibles cuellos de botella en el rendimiento.
Las pruebas de rendimiento son un aspecto crítico para garantizar que sus aplicaciones puedan manejar las demandas del mundo real. Intentaré explicar mi enfoque y los scripts de Python diseñados para probar la carga de un servicio en la nube que administra navegadores.
Escenario de prueba de carga Imagine un servicio en la nube responsable de administrar los perfiles del navegador (navegadores para desguace web). Los usuarios interactúan vía API con el servicio para crear, iniciar, detener, eliminar, etc. perfiles. Mi secuencia de comandos Python simula este escenario, aplicando carga al servicio en la nube realizando estas acciones repetidamente.
# 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
recupera perfiles de navegador existentes del servicio, simulando un escenario en el que los usuarios solicitan información. 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}')
La función principal organiza los ciclos de prueba de carga, iterando a través de perfiles y ejecutando tareas asincrónicas. Cada ciclo representa una interacción de usuario simulada, creación, uso y eliminación de perfiles de navegador.
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
Este script muestra una base para que los controles de calidad adapten escenarios de pruebas de carga a sus aplicaciones. Al personalizar la cantidad de ciclos, ajustar las interacciones del usuario y modificar el script para que se ajuste a puntos finales de API específicos, los evaluadores pueden obtener información valiosa sobre el rendimiento de su aplicación bajo diferentes cargas. Aquí, necesitará herramientas de monitoreo esenciales para obtener información sobre los estados del servidor, evaluar la carga del servidor y realizar un seguimiento de la utilización de recursos y los registros. Utilice herramientas como Grafana, Kibana, Prometheus, etc., para un seguimiento integral. Además, esté atento a las respuestas que recibe su script, lo que garantiza una evaluación exhaustiva del rendimiento de su aplicación. Este enfoque es invaluable en sus pruebas de carga y análisis de rendimiento efectivos.
Además, para una simulación de carga más realista, considere abrir páginas específicas en su navegador. Si bien yo personalmente utilicé una página de inicio en mis navegadores, también puedes explorar opciones como Pyppeteer o Playwright para abrir varias pestañas y navegar por varias páginas. Este enfoque mejora la autenticidad de su escenario de prueba de carga, asemejándose mucho a las interacciones del usuario con su aplicación.
# 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)}')
Las capacidades asincrónicas de Python, junto con las bibliotecas HTTP, lo convierten en una herramienta versátil para probar la carga de sistemas basados en la nube. Este ejemplo sirve como punto de partida para los ingenieros de control de calidad que buscan conocer el poder de Python en sus intentos de pruebas de carga.
NOTA
En mi escenario, el guión descrito resultó ser sólido e impactante. Sirvió como herramienta útil para identificar y abordar numerosas cuestiones. La naturaleza agresiva del script estuvo bien al identificar problemas críticos, facilitar una depuración efectiva y abrir el camino para una experiencia de usuario mejorada y sin problemas, lo cual es bastante bueno para un control de calidad.
A continuación, analizaré brevemente otro script que utiliza el módulo de multiprocesamiento de Python. Este enfoque tiene como objetivo mejorar la generación de carga mediante la ejecución simultánea de múltiples instancias del script de prueba. El objetivo principal del multiprocesamiento es paralelizar la ejecución de un script, permitiendo interacciones simultáneas con el servicio. Este enfoque contrasta con el enfoque asincrónico analizado anteriormente, donde las tareas se ejecutan de forma secuencial pero se administran al mismo tiempo. Esto se parece más a spam/ddos con las mismas solicitudes, pero también puede ser muy útil.
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()
El multiprocesamiento proporciona una estrategia para aplicaciones de prueba de carga. Permite a los ingenieros de control de calidad experimentar con diferentes metodologías basadas en las características únicas de sus aplicaciones. Si bien las pruebas asincrónicas ofrecen eficiencia en la gestión de tareas simultáneas, el multiprocesamiento sobresale al paralelizar todo el proceso de prueba. Puede elegir el enfoque que mejor se alinee con sus objetivos específicos de pruebas de carga y requisitos de aplicación.
Un recordatorio rápido:
Esta demostración tiene como objetivo presentar conceptos básicos en un formato apto para principiantes, destacando la simplicidad de Python para los evaluadores de control de calidad que se aventuran en las pruebas de rendimiento.
Si tiene desafíos de programación, no dude en buscar en Google y preguntar a sus colegas, usar ChatGPT o herramientas similares y usar GitHub Copilot para obtener ayuda adicional al escribir sus scripts de prueba de carga.
También publicado aquí .