O que aprendi sobre cobertura de testes

O que aprendi sobre cobertura de testes

Gostaria de compartilhar o que aprendi sobre avaliar e considerar a cobertura ao criar testes para o projeto.


O que é cobertura de testes (code coverage)?

Cobertura de testes é uma métrica usada para medir o quanto do código de um software foi testado pelos testes automatizados. A ideia é que, ao escrever testes automatizados para um software, se possa verificar se as funcionalidades e comportamentos esperados estão sendo atendidos.

A cobertura de testes pode ser expressa em percentual e indica a proporção do código que foi coberta pelos testes. Por exemplo, se um software tem 100 linhas de código e os testes automatizados cobriram 80 dessas linhas, então a cobertura de testes é de 80%.

A cobertura de testes é importante porque ela ajuda a avaliar a qualidade dos testes automatizados e pode indicar áreas do código que precisam de mais atenção nos testes. Uma cobertura de testes alta não garante que o software não contenha bugs, mas ajuda a reduzir a possibilidade de erros não detectados durante o processo de desenvolvimento e aumenta a confiança no software.


Qual a importância da cobertura de testes?

Redução de riscos: Quando a cobertura de testes é alta, há uma maior probabilidade de que o software tenha sido testado de forma adequada e, portanto, tenha menos bugs e problemas de funcionamento. Isso reduz os riscos para os usuários e para a empresa.

Identificação de problemas: Ao avaliar a cobertura de testes, é possível identificar áreas do software que não foram adequadamente testadas. Isso permite que os desenvolvedores foquem nesses pontos e criem novos testes para garantir que essas áreas funcionem corretamente.

Confiança no software: Uma cobertura de testes alta ajuda a aumentar a confiança no software, tanto para os usuários finais quanto para os desenvolvedores. Isso permite que a equipe de desenvolvimento trabalhe com mais segurança, sabendo que o software passou por testes adequados.

Facilita manutenção: Quando o software é bem testado, torna-se mais fácil fazer manutenções e alterações no código, já que a equipe de desenvolvimento pode ter mais confiança de que as alterações feitas não irão introduzir novos bugs ou problemas de funcionamento.


Somente o percentual de cobertura é relevante?

Acredito que não. O percentual é um número muito relevante. Ele indica efetivamente quanto do seu código foi testado e principalmente o que falta testar. Porém, somente isto, foi testado. Não indica se os dois estão corretos.

Para nós os testes devem responder mais que isto. Devem responder a perguntas importantes como:

  • Os dados retornados estão corretos?
  • A estrutura dos dados retornados está correta?
  • Em funções que possuem listeners, eles são executados e alteram corretamente os dados que precisam ser alterados
  • Considerando as regras de negócio relacionadas a restrições, os dados retornados estão corretos?
  • Exportações para excel por exemplo retornam as informações necessárias?
  • Quando há notificações, elas são despachadas corretamente?

Há inúmeros outros casos em que a simples informação da cobertura não está relacionada diretamente ao correto funcionamento do sistema.


Uma boa orientação do que testar

Para nós a cobertura de testes é ótima como indicador de direção. Ela consegue demonstrar de forma simples quais funções não tem nenhuma cobertura. Algumas bibliotecas possuem isto pronto. No nosso caso são os riscos do projeto.

Não foi fornecido texto alternativo para esta imagem


Desta forma conseguimos identificar facilmente o que não possui nada de cobertura de testes.

Este sim, é o pior dos casos, não ter nenhum teste que ao menos execute a função.


A dificuldade dos 100%

Quem não trabalha com cobertura de testes pode achar que 100% não é tão difícil assim. Mas acredite, é muito difícil.

Imagine uma função de castro de usuário escrita da seguinte forma:

Recepção dos dados

Se não informado nome, retorna erro

Se não informado email, retorna erro

Se não informado senha, retorna erro

Se não informado … retorna erro

Dependendo de como for escrita a função, ela precisaria de 4 testes diferentes para ter 100% de cobertura. Isto provavelmente deixaria sua aplicação com mais linhas de testes que a própria função possui. A quantidade em si não é um problema, mas o custo para a implementação destes testes pode ser.

Voltando ao exemplo, claro que ele pode ser escrito se forma a concatenar todos os erros e retornar todos juntos. Porém, nem todas as funções permitem isto quando estamos falando de cálculos complexos, por exemplo. Cálculos que geram certos resultados necessários a execução de outros cálculos e a validação deve ocorrer também nestes resultados parciais.


O número ideal

É difícil dizer. Mas como primeira estratégia definimos o seguinte:

Os testes devem contemplar a execução de todas as funções do software, mesmo que não seja 100% do código da função.

A prioridade é testar o funcionamento de tal forma a validar o core função, não sendo necessário validar todos os possíveis erros, por exemplo.

Considerando estes dois pontos norteadores e outros que já escrevi anteriormente, o número deve girar em torno de 85%. Como mencionei, não é uma máxima, mínima ou exata, mas é um ponto onde a relação custo benefício tende a ser muito boa.


Resultados reais, testes e bugs

Temos vários casos distintos de cobertura de testes que podemos avaliar e comparar os resultados. Temos sistemas com 0%, 30%, 60% e acima de 85%.

Analisando nossos números podemos observar que a relação de testes e bugs segue o famoso diagrama de pareto.


O que é o diagrama de pareto?

O diagrama de Pareto é uma ferramenta de análise que permite identificar e priorizar os problemas ou causas mais relevantes em um conjunto de dados. Ele é baseado no princípio de que a maioria dos efeitos (resultados) é causada por um pequeno número de causas (fatores).


O que podemos observar foi que de 0 a 30% o impacto da cobertura de testes é muito alto. Sair do 0% para 30% gera uma diminuição grande no volume de bugs.

Já quando falamos de uma cobertura de 30% a 60% o impacto é mediano. Neste ponto você já testou as funções mais utilizadas do sistema e provavelmente está escrevendo testes para as demais funções que não são utilizadas com tanta frequência. Isto se traduz em número menor de bugs evitados. Mas aqui observamos algo importante. Neste ponto provavelmente você vai se preocupar mais em testar também as regras de negócios e funções críticas que não necessariamente são muito utilizadas, como relatórios e painéis gerenciais. Isto acaba gerando um resultados muito positivo também no impacto dos bugs.

De 60 a 85% o impacto no número de bugs é baixo. Neste ponto provavelmente você já está escrevendo testes pensando em aumentar o coverage, não necessariamente ou somente considerando a estrutura e riscos do projeto.

Acima de 85% o impacto tende em bugs tende a 0%. Isto porque neste ponto provavelmente todas as funções do sistema já estão testadas. Os testes escritos a partir deste ponto são para verificar retornos excepcionais como erros ou certas validações que devem ocorrer, não para o objetivo final daquele código.

Qual a estratégia a ser adotada?

Como sempre, depende do que você quer e de qual sua situação.

Você quer paz ou acredita que o tempo dedicado a suporte está alto?

Provavelmente sua cobertura deve estar muito baixa e ocorrem diversos bugs no seu software. Verifique quais são as funções mais utilizadas do sistema e escreva testes para elas. Após, avalie os riscos do projeto e eleve sua cobertura até cerca de 30% ao menos.

Não quer receber solicitações de erros do seu diretor ou o diretor do seu cliente informando que os dados não estão corretos?

É provável que você já tenha uma certa cobertura mas não tenha testado satisfatoriamente as regras de negócio. Esqueça um pouco a cobertura e altere seus testes para que contemplem as regras de negócio.

Tem cobertura mas existem erros insistentes em certas funções?

Uma boa estratégia e para cada bug que for corrigido, implementar um teste simulando aquela situação. Utilize TDD para isto. Primeiramente crie o teste para simular a situação. Rode o teste. Ele irá falhar. Corrija seu código. Rode novamente o testes. Ele irá passar. Desta forma você evita que este problema ocorra novamente.

Por fim, testes é um assunto que me interessa muito e pelo que tenho pesquisado possui pouco conteúdo se comparado ao desenvolvimento core das aplicações. Espero ter contribuído de alguma forma com este registros dos meus aprendizados até o momento. Obrigado pela leitura.

Entre para ver ou adicionar um comentário

Outras pessoas também visualizaram

Conferir tópicos