Pular para conteúdo

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:

mvn -B test -Dspring.profiles.active=test # (1)!
  1. 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.

make unit_test # (1)!
  1. 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

pytest \
    --junit-xml=coverage/unit_test/junit.xml \
    --color=yes \
    --verbose \
    tests/unit # (1)!
  1. 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.
yarn run test # (1)!
  1. 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 arquivo package.json ⧉ do projeto, é usado para iniciar a execução dos testes.
npm run test # (1)!
yarn run test # (1)!

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:

mvn -B verify -Dspring.profiles.active=test # (1)!
  1. 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 comando verify é 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)!
  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.

make integration_test # (1)!
  1. 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)!
  1. Locust | Console com o resultado da execução do teste
locust \
    --headless \
    --locustfile=perf/locustfile.py \
    --host=http://<host>:<port> \
    --users=100 \
    --spawn-rate=10 \
    --run-time=2m \
    --only-summary \
    --csv=.locust \
    --html=.locust_report.html

Alternativamente, é possível executar o teste de performance através do script definido no arquivo <project root>/Makefile do projeto:

make performance_test # (1)!
  1. 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:

docker run \
    --network host \
    -v "${PWD}:/mnt/locust" \
    -e LOCUST_LOCUSTFILE="/mnt/locust/perf/locustfile.py" \
    -e MS_SSO_BASE_URL="<sso url>" \
    locustio/locust
locust -f locustfile.py
Exemplo de execução do teste de desempenho

Locust | Início de novo teste de carga

Locust | Estatística do teste

Locust | Total de requisições por segundo

Locust | Tempo de resposta

Locust | Número de usuários

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.

Diagrama | Tipos de testes

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:

docker run \
    --network host \
    -v "${PWD}:/mnt/locust" \
    -e LOCUST_LOCUSTFILE="/mnt/locust/perf/locustfile.py,/mnt/locust/perf/locustfiles/shapes/smoke.py" \
    -e MS_SSO_BASE_URL="<sso url>" \
    locustio/locust
make smoke_test
Exemplo de execução do smoke test

Locust | Relatório completo do Smoke Test

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:

docker run \
    --network host \
    -v "${PWD}:/mnt/locust" \
    -e LOCUST_LOCUSTFILE="/mnt/locust/perf/locustfile.py,/mnt/locust/perf/locustfiles/shapes/load.py" \
    -e MS_SSO_BASE_URL="<sso url>" \
    locustio/locust
make load_test
Exemplo de execução do load test

Locust | Relatório completo do Load Test

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:

docker run \
    --network host \
    -v "${PWD}:/mnt/locust" \
    -e LOCUST_LOCUSTFILE="/mnt/locust/perf/locustfile.py,/mnt/locust/perf/locustfiles/shapes/stress.py" \
    -e MS_SSO_BASE_URL="<sso url>" \
    locustio/locust
make stress_test
Exemplo de execução do stress test

Locust | Relatório completo do Stress Test

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:

docker run \
    --network host \
    -v "${PWD}:/mnt/locust" \
    -e LOCUST_LOCUSTFILE="/mnt/locust/perf/locustfile.py,/mnt/locust/perf/locustfiles/shapes/spike.py" \
    -e MS_SSO_BASE_URL="<sso url>" \
    locustio/locust
make spike_test
Exemplo de execução do spike test

Locust | Relatório completo do Spike Test

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:

docker run \
    --network host \
    -v "${PWD}:/mnt/locust" \
    -e LOCUST_LOCUSTFILE="/mnt/locust/perf/locustfile.py,/mnt/locust/perf/locustfiles/shapes/soak.py" \
    -e MS_SSO_BASE_URL="<sso url>" \
    locustio/locust
make soak_test
Exemplo de execução do soak test

Locust | Relatório completo do Soak Test

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ê:

  1. Defina os critérios de aprovação/reprovação do teste.
  2. Automatize a execução do teste através de uma esteira DevOps ou agendamento.
  3. 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.