Você é um testador de controle de qualidade ansioso para mergulhar nos testes de desempenho sem a necessidade de amplo conhecimento em programação? Neste artigo, exploraremos uma maneira acessível para não-programadores realizarem uma espécie de teste de carga em APIs de aplicativos em nuvem usando Python . Teste de carga sem a necessidade de codificação complexa - descubra como até mesmo testadores regulares de controle de qualidade podem usar Python para encontrar bugs graves e descobrir possíveis gargalos de desempenho.
Os testes de desempenho são um aspecto crítico para garantir que seus aplicativos possam lidar com as demandas do mundo real. Tentarei explicar minha abordagem e scripts Python projetados para testar a carga de um serviço de nuvem que gerencia navegadores.
Cenário de teste de carga Imagine um serviço de nuvem responsável por gerenciar perfis de navegadores (navegadores para web scrapping). Os usuários interagem via API com o serviço para criar, iniciar, parar, excluir, etc. Meu script Python simula esse cenário, aplicando carga ao serviço de nuvem executando essas ações 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 perfis de navegador existentes do serviço, simulando um cenário em que os usuários solicitam informações. 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}')
A função principal orquestra os ciclos de teste de carga, iterando através de perfis e executando tarefas assíncronas. Cada ciclo representa uma interação simulada do usuário, criando, usando e excluindo perfis 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 mostra uma base para os QAs adaptarem cenários de teste de carga às suas aplicações. Ao personalizar o número de ciclos, ajustar as interações do usuário e modificar o script para se adequar a endpoints de API específicos, os testadores podem obter insights valiosos sobre o desempenho de seus aplicativos sob diferentes cargas. Aqui, você precisará de ferramentas de monitoramento essenciais para obter informações sobre os estados do servidor, avaliar a carga do servidor e rastrear a utilização de recursos e logs. Utilize ferramentas como Grafana, Kibana, Prometheus, etc, para monitoramento abrangente. Além disso, fique atento às respostas que seu script recebe, garantindo uma avaliação completa do desempenho da sua aplicação. Essa abordagem é inestimável em testes de carga e análises de desempenho eficazes.
Além disso, para uma simulação de carregamento mais realista, considere abrir páginas específicas no seu navegador. Embora eu pessoalmente tenha usado uma página inicial em meus navegadores, você também pode explorar opções como Pyppeteer ou Playwright para abrir várias guias e navegar por várias páginas. Essa abordagem aumenta a autenticidade do seu cenário de teste de carga, assemelhando-se muito às interações do usuário com o seu aplicativo.
# 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)}')
Os recursos assíncronos do Python, juntamente com bibliotecas HTTP, tornam-no uma ferramenta versátil para testes de carga de sistemas baseados em nuvem. Este exemplo serve como ponto de partida para engenheiros de controle de qualidade que buscam aprender o poder do Python em suas tentativas de teste de carga.
OBSERVAÇÃO
No meu cenário, o roteiro descrito mostrou-se robusto e impactante. Serviu como uma ferramenta útil para identificar e abordar inúmeras questões. A natureza agressiva do script foi adequada para identificar problemas críticos, facilitar a depuração eficaz e abrir caminho para uma experiência de usuário aprimorada e contínua, o que é muito bom para um controle de qualidade.
Na continuação, discutirei brevemente outro script que utiliza o módulo de multiprocessamento do Python. Esta abordagem visa aprimorar a geração de carga executando simultaneamente várias instâncias do script de teste. O objetivo principal do multiprocessamento é paralelizar a execução de um script, possibilitando interações simultâneas com o serviço. Esta abordagem contrasta com a abordagem assíncrona discutida anteriormente, onde as tarefas são executadas sequencialmente, mas gerenciadas simultaneamente. Isso é mais parecido com spam/ddos com as mesmas solicitações, mas também pode ser muito ú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()
O multiprocessamento fornece uma estratégia para aplicações de teste de carga. Ele permite que os engenheiros de controle de qualidade experimentem diferentes metodologias com base nas características exclusivas de suas aplicações. Embora o teste assíncrono ofereça eficiência no gerenciamento de tarefas simultâneas, o multiprocessamento é excelente para paralelizar todo o processo de teste. Você pode escolher a abordagem que melhor se alinha aos objetivos específicos de teste de carga e aos requisitos do aplicativo.
Um lembrete rápido:
Esta demonstração tem como objetivo apresentar conceitos básicos em um formato amigável para iniciantes, destacando a simplicidade do Python para testadores de controle de qualidade que se aventuram em testes de desempenho.
Se você tiver desafios de programação, não hesite em pesquisar coisas no Google e perguntar a colegas, use ChatGPT ou ferramentas semelhantes e use GitHub Copilot para obter assistência extra na escrita de seus scripts de teste de carga.
Também publicado aqui .