paint-brush
Teste de desempenho baseado em Python para testadores de controle de qualidade: um guia para iniciantes em testes de carga de API em nuvempor@shad0wpuppet
27,071 leituras
27,071 leituras

Teste de desempenho baseado em Python para testadores de controle de qualidade: um guia para iniciantes em testes de carga de API em nuvem

por Konstantin Sakhchinskiy8m2024/01/19
Read on Terminal Reader
Read this story w/o Javascript

Muito longo; Para ler

Explore scripts Python para testadores de controle de qualidade conduzindo testes de carga em APIs de aplicativos em nuvem. O artigo aborda abordagens assíncronas e de multiprocessamento, oferecendo insights sobre personalização, seleção de metodologia e dicas práticas de monitoramento. Aproveite os recursos técnicos do Python para obter análises abrangentes de desempenho.
featured image - Teste de desempenho baseado em Python para testadores de controle de qualidade: um guia para iniciantes em testes de carga de API em nuvem
Konstantin Sakhchinskiy HackerNoon profile picture
0-item
1-item


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} }

Funções assíncronas: o coração dos meus testes de carga

  • Buscando perfis de navegador: a função 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()


  • Iniciando navegadores: o script inicia ciclos, cada um envolvendo o início de perfis de navegador de forma assíncrona. Isso emula um cenário em que um usuário cria vários navegadores simultaneamente e usa perfis de navegador.
 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}')


  • Parando navegadores e excluindo perfis: após iniciar os perfis, o script busca os perfis ativos e os interrompe, seguido pela exclusão de todos os perfis. Este cenário de carga avalia a capacidade de resposta do serviço em nuvem às mudanças dinâmicas e a sua eficiência na limpeza de recursos.
 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}')


  • Monitorando conexões: entendendo o impacto da carga O script termina verificando e relatando conexões ativas. Esta etapa é crucial para compreender o impacto da carga e identificar possíveis problemas relacionados ao monitoramento.
 for conn in cl._transport._pool.connections: if conn._connection._state.value != 1: continue print(f'Connection in progress: {conn}')

Teste de carga em ação

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

Adaptando testes de carga às suas necessidades

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.

Componentes chave

  • Função para recuperar perfis: semelhante ao script assíncrono, ainda precisamos buscar perfis de navegador existentes no serviço de nuvem.
 def get_profiles(): response = requests.get(url=f"{api}", params=PARAMS, headers=headers) return response


  • Funções: O núcleo do script gira em torno de duas funções: start_profiles e stop_profiles. Essas funções iniciam e encerram perfis de navegador, respectivamente.
 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)


  • Execução de multiprocessamento: o script utiliza o módulo de multiprocessamento para executar o ciclo de teste de carga várias vezes em paralelo. Para cada ciclo, um novo processo é gerado e a função run_script é executada simultaneamente.
 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()


Como gerar carga com multiprocessamento

  1. Execução paralela: Cada processo gerado pelo módulo de multiprocessamento opera de forma independente, executando a função run_script simultaneamente. Esta paralelização aumenta significativamente o número de solicitações enviadas ao serviço simultaneamente.
  2. Simulação de interações do usuário: Ao executar múltiplas instâncias do script em paralelo, simulamos um volume maior de usuários interagindo com o serviço de nuvem simultaneamente. Esta abordagem é particularmente útil para cenários onde o uso no mundo real envolve um grande número de usuários simultâneos.

Escolhendo a abordagem certa

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 .