Testando a aplicação¶
Teste unitário¶
A implementação de testes unitários em projetos é crucial para garantir a qualidade da aplicação e identificar erros/falhas precocemente. Os testes possibilitam a verificação isolada e conjunta de cada parte do código, assegurando que a aplicação funcione conforme as especificações. Além disso, detectar problemas antecipadamente torna a manutenção do código mais fácil, reduzindo o tempo e o custo de desenvolvimento.
Para executar os testes unitários implementados no projeto, utilize o seguinte comando:
- No Java ⧉, é utilizado o Maven ⧉ para executar os testes, sendo que a opção
-Dspring.profiles.active=test
é usada para configurar o perfil de execução para o ambiente de testes.
Para tornar a execução dos testes unitários mais simples, é possível usar um script definido no arquivo <project root>/Makefile
do projeto.
- Esse comando ativa o script definido no arquivo Makefile ⧉, responsável por automatizar a execução dos testes unitários. Esse procedimento oferece aos desenvolvedores uma maneira ágil e simplificada de realizar os testes, sem a necessidade de digitar manualmente todos os argumentos/parâmetros requeridos para a execução dos testes.
Documentação em progresso
- No Python ⧉, é utilizado o framework Pytest ⧉ para executar os testes, sendo que as opções
--junit-xml
e--verbose
são utilizadas para gerar um relatório no formato JUnit XML e exibir informações detalhadas sobre a execução dos testes, respectivamente. Já a opção--color
é utilizada para colorir a saída do terminal.
- No Angular ⧉, é utilizado o gerenciador de pacotes Yarn ⧉ para executar os testes, sendo que o comando
yarn run test
, presente na seção de scripts do arquivopackage.json
⧉ do projeto, é usado para iniciar a execução dos testes.
Teste de integração¶
Os testes de integração são importantes para verificar se diferentes componentes de uma aplicação estão funcionando corretamente juntos. Eles permitem que os desenvolvedores detectem e corrijam erros de integração mais cedo no processo de desenvolvimento, melhorando a qualidade do software e aumentando a eficiência do processo. Além disso, os testes ajudam a garantir que a aplicação atenda aos requisitos do cliente e funcione conforme o esperado em ambientes reais.
Para executar os testes de integração implementados no projeto, use o seguinte comando:
- No Java ⧉, é utilizado o Maven ⧉ para gerenciar as dependências do projeto e executar os testes de integração. A opção
-Dsurefire.skip=true
é usada para pular a execução dos testes unitários e a opção-Dspring.profiles.active=test
sinaliza para o Spring ⧉ que deverá ser usado o perfil de teste. O comandoverify
é usado para compilar o código-fonte, executar os testes e empacotar o projeto em um arquivo JAR. O parâmetro-B
é usado para executar o Maven em modo de lote, o que significa que ele não exibe saída interativa.
Relatório de cobertura
Os relatórios de cobertura dos testes são gerados pela ferramenta JaCoCo Java Code Coverage Library ⧉ no diretório target/site e podem ser visualizados no navegador por meio do arquivo index.html
contido em target/site/jacoco.
pytest \
--cov=src \
--cov-report=term \
--cov-report=html:coverage/integration_test/report_html \
--cov-report=xml:coverage/integration_test/report.xml \
--color=yes \
--verbose \
tests/integration # (1)!
- No Python ⧉, é utilizado o framework Pytest ⧉ para executar os testes de integração localizados no diretório
tests/integration
do projeto. Além disso, esse comando gera um relatório de cobertura de código usando a opção--cov=src
para especificar o diretório do código-fonte e a opção--cov-report
para definir os formatos de relatório de cobertura, que incluem um relatório em texto (term
), um relatório em HTML (html:coverage/integration_test/report_html
) e um relatório em XML (xml:coverage/integration_test/report.xml
). A opção--color=yes
é usada para exibir o resultado do teste em cores e a opção--verbose
para exibir informações detalhadas sobre o teste.
Relatório de cobertura
Os relatórios de cobertura dos testes são gerados pela ferramenta PyTest Cov ⧉ no diretório coverage/integration_test e podem ser visualizados no navegador por meio do arquivo index.html
contido em coverage/integration_test/report_html.
Para simplificar a execução dos testes de integração, é possível utilizar um script definido no arquivo <project root>/Makefile
do projeto.
- Esse comando aciona o script definido no arquivo Makefile ⧉, que por sua vez automatiza a execução dos testes de integração. Esse processo proporciona aos desenvolvedores uma maneira ágil e simplificada de realizar os testes, dispensando a necessidade de digitar manualmente todos os argumentos/parâmetros necessários para a execução dos testes.
Documentação em progresso
Teste de desempenho¶
Documentação em progresso
O teste de performance é uma prática que permite aos desenvolvedores identificar gargalos e problemas de desempenho em diversas partes da aplicação, como no código, no banco de dados ou na rede. Com base nos resultados do teste, é possível otimizar a aplicação, melhorando o seu desempenho. Isso pode proporcionar aos usuários uma experiência mais satisfatória, além de trazer maior eficiência e redução de custos operacionais.
Além disso, os testes de performance são importantes para garantir que a aplicação possa lidar com picos de tráfego ou de uso, como durante eventos de vendas intensas (Black friday) ou quando há um aumento súbito na demanda. Essa prática ajuda a garantir que a aplicação possa funcionar sem problemas em situações críticas, o que é essencial para a reputação e o sucesso do projeto.
Para realizar o teste de performance no projeto utilizando a ferramenta Locust ⧉, basta executar o seguinte comando:
docker run \
--network host \
-v "${PWD}:/mnt/locust" \
-e LOCUST_HEADLESS="true" \
-e LOCUST_LOCUSTFILE="/mnt/locust/perf/locustfile.py" \
-e LOCUST_HOST="http://<host>:<port>" \
-e LOCUST_USERS="100" \
-e LOCUST_SPAWN_RATE="10" \
-e LOCUST_RUN_TIME="2m" \
-e LOCUST_ONLY_SUMMARY="true" \
-e LOCUST_CSV=".locust" \
-e LOCUST_HTML=".locust_report.html" \
-e MS_SSO_BASE_URL="<sso url>" \
locustio/locust # (1)!
Alternativamente, é possível executar o teste de performance através do script definido no arquivo <project root>/Makefile
do projeto:
- Esse comando ativa o script definido no arquivo Makefile ⧉, que automatiza a execução do teste de desempenho do projeto. Esse procedimento oferece aos desenvolvedores uma maneira rápida e simplificada de realizar o teste, eliminando a necessidade de inserir manualmente todos os argumentos e parâmetros necessários para o teste.
Documentação em progresso
Também é possível executar o teste de performance em modo interativo, utilizando a interface web do Locust:
Tipos de testes¶
Existem vários tipos de testes que permitem identificar o comportamento do sistema, onde é utilizada a mesma lógica mas com diferentes configurações de carga.
Smoke Test¶
Esse teste permite identificar se a aplicação suporta uma carga mínima, ajudando a determinar os seguintes aspectos:
- Se o script de teste não contém erros; e
- Se a aplicação não apresenta nenhum problema quando está sob carga mínima.
Execute o seguinte comando para iniciar o Locust ⧉ no modo web com estágios predefinidos (usuários e duração) por meio do arquivo smoke.py:
Se o relatório não apresentou nenhuma falha, você pode executar o load test para avaliar o desempenho da aplicação.
Load Test¶
O teste de carga preocupa-se principalmente com a avaliação de desempenho da aplicação em termos de usuários simultâneos ou requisições por segundo, auxiliando na identificação dos seguintes aspectos:
- Como a aplicação se comporta durante condições normais e os horários de pico; e
- Se o desempenho permanece inalterado após modificações no código-fonte e na infraestrutura.
Dica
Ao executar um teste de carga pela primeira vez, comece com poucos usuários e aumente gradualmente, pois a aplicação pode não ser tão resiliente quanto você pensa.
Para iniciar o Locust ⧉ no modo web com estágios predefinidos (número de usuários e duração), utilize o arquivo load.py e execute o seguinte comando:
Stress Test¶
Embora o load test se preocupe principalmente com a avaliação de desempenho da aplicação, o objetivo do stress test é avaliar a disponibilidade e a estabilidade da aplicação sob carga pesada, isto é, determinar os seguintes aspectos:
- Como a aplicação se comportará em condições extremas;
- Qual a capacidade máxima da aplicação em termos de usuários e tempo de resposta;
- O ponto de ruptura da aplicação e o modo de falha; e
- Capacidade de recuperação sem intervenção manual após o término do teste.
Nota
Esse tipo de teste visa descobrir o que acontece quando você ultrapassa os limites de desempenho da aplicação, portanto, não se preocupe em ser muito agressivo.
Agora, execute o comando abaixo para iniciar o Locust ⧉ em modo web com estágios predefinidos (usuários e duração) através do arquivo stress.py:
Spike Test¶
O spike test é uma variação do stress test, mas não aumenta gradativamente a carga. Em vez disso, atinge uma carga extrema em um período de tempo muito curto, permitindo identificar os seguintes aspectos:
- Como a aplicação funcionará sob um aumento repentino de tráfego; e
- Capacidade de recuperação assim que o tráfego diminuir.
As aplicações geralmente reagem de 4 maneiras diferentes:
- Excelente: o desempenho da aplicação não é degradado durante o aumento do tráfego. O tempo de resposta durante o tráfego baixo e alto é semelhante.
- Bom: o tempo de resposta é mais lento, mas a aplicação não apresenta erros. Todas as requisições são atendidas.
- Insatisfatório: a aplicação produz erros durante o aumento do tráfego, mas volta ao normal após a diminuição do tráfego.
- Ruim: a aplicação trava e não se recupera depois que o tráfego diminui.
Para executar esse tipo de teste, rode o comando abaixo para iniciar o Locust ⧉ em modo web com estágios predefinidos (usuários e duração) por meio do arquivo spike.py:
Soak Test¶
Esse tipo de teste visa revelar problemas de desempenho e confiabilidade decorrentes de uma sobrecarga por um longo período de tempo (horas), ajudando a determinar os seguintes aspectos:
- Se há bugs ou vazamento de memória (memory leak, em inglês), resultando em travamento ou reinicialização após várias horas de operação;
- Se durante as reinicializações a aplicação deixa de atender alguma requisição;
- Se existe problemas relacionados a race-conditions (+1 thread acessa o mesmo conteúdo ao mesmo tempo) que aparecem esporadicamente;
- Se o banco de dados utilizado não sofre com esgotamento de recursos (disco, memória e cpu), parando de atender as requisições; e
- Se os serviços externos (webservices, apis, integrações) não param de funcionar após a execução de uma certa quantidade de requisições.
Dica
É recomendado configurar a carga com 80% da capacidade máxima da aplicação, ou seja, se a aplicação aguenta 500 usuários simultâneos, configure o teste para 400 usuários. Além disso, é aconselhável iniciar o teste de 1 hora e uma vez bem-sucedido, estenda-o para várias horas, pois alguns erros estão relacionados ao tempo e não ao número total de requisições executadas.
Execute o comando abaixo para iniciar o Locust ⧉ em modo web com estágios predefinidos (usuários e duração) por meio do arquivo soak.py:
Limiares¶
Limites (thresholds, em inglês) são critérios definidos para aprovar ou reprovar as métricas de um teste de desempenho. Caso o Sistema Sob Teste (SUT) não atenda aos limites estabelecidos, o teste deve ser encerrado com um status de falha.
Normalmente, os limites são usados para definir objetivos de nível de serviço (SLOs ⧉). Por exemplo:
- Menos de 1% das requisições retornam com erro.
- 95% das requisições têm tempo de resposta abaixo de 100ms.
- 99% das requisições têm tempo de resposta abaixo de 200ms.
- Um endpoint específico sempre responde em 150ms.
- Quaisquer condições para uma métrica personalizada.
Os thresholds são essenciais para automação de testes de desempenho, pois permitem que você:
- Defina os critérios de aprovação/reprovação do teste.
- Automatize a execução do teste através de uma esteira DevOps ou agendamento.
- Configure alertas para serem enviados em caso de falhas.
Ao automatizar, você só precisa se preocupar em testar caso o SUT não atender as expectativas de desempenho.