Cobertura de código explicada

Relatórios e métricas com Istanbul e o que elas significam!

Image for post
Image for post
Se não está em uso, deveria estar aqui?

Porquê?

Existe alguns problemas óbvios com isso:

  • Se não testado, o código perdido na sua base de código pode conter comportamentos desconhecidos, o famigerado bug.
  • Funcionalidades não testadas são mais difíceis de manter sem introduzir alguma mudança que quebre outra parte do sistema.
  • Código não testado traz desordem e acumula débitos técnicos, desperdiçando o seu tempo (e o da equipe também).

O que?

O resto desse artigo irá focar no uso prático, com um exemplo para nos guiar. Se você é completamente novo ao termo Cobertura de código, eu recomendo você dar uma lida breve no artigo em inglês no Wikipedia (não existe a tradução em Português, alguém se candidata?)

Istanbul, é um script de análise de cobertura de código que roda quando você executa seus testes. Ele é bem simples e prático, retornando ótimos relatórios em HTML.

Como?

Instalação

Vamos instalar o Istanbul como devDependencies em nosso projeto:

npm install istanbul --save-dev

Para verificar se foi instalado corretamente, podemos:

node_modules/.bin/istanbul help

Exemplo — Aquele bem simples

mkdir learn-istanbul
cd learn-istanbul
touch test.js

Iremos escrever:

x = 42;
if(false)
x =-1;

Agora, vamos usar o Istanbul para gerar o relatório de cobertura de testes:

node ./node_modules/.bin/istanbul cover test.js

Também podemos colocar um script no nosso package.json:

"coverage": "istanbul cover ./test.js"

E executar:

npm run coverage

Isso irá criar um diretório chamado coverage, onde você irá encontrar os relatórios gerados. No nosso caso, learn-istanbul/coverage/lcov-report/index.html. Abrindo o arquivo html, teremos um relatório visual sobre a cobertura do nosso código:

Image for post
Image for post

Istanbul nos retorna 4 métricas de cobertura de código:

  • Statements: A quantidade de statements que seu código executou.
  • Branches: A quantidade de condicionais criadas no seu código, que não foram executadas (ex: if / else). Essa métrica te mostra a quantidade de divisões que foi executada e o que ainda falta.
  • Functions: A proporção de função que foram definidas e quais foram chamadas.
  • Lines: A proporção de linhas do seu código que foram executadas.

Ao clicar em test.js, conseguimos ver o código em si:

Image for post
Image for post

Podemos observar 2 coisas do exemplo acima:

  • Nós só conseguimos 66.67% de cobertura de código porque apenas 2/3 do código foi executado.
  • A terceira linha, nunca foi executada porque false é sempre false!

Você pode falar que esse exemplo é meio besta, porém, ele mostra especificamente, aonde o código não utilizado está.

Exemplo — Aquele “vida real”

Image for post
Image for post

O que há de errado com a imagem abaixo?

Image for post
Image for post

Existem vários desenvolvedores/empresas que só conseguem sonhar em conseguir 96% de cobertura de código! E, no entanto, quando inspecionamos os detalhes, há algo grande acontecendo!

Image for post
Image for post

Nós temos 100% de cobertura de testes funcionais, mas apenas 50% de Branch. Isso significa que uma, ou mais condicionais, não estão sendo executadas.

A maior parte do tempo, é algo inocente, e se não prestarmos a atenção em algo como:

if(
employee.status === 'terminated' &&
employee.left - today() > 90
) {
selfDestuct();
}

Os 97% de cobertura, não parece mais tão animador…

E se nós adicionarmos um teste que siga aquela divisão de código meio suspeita? Nós podemos alcançar o mítico 100% de cobertura de código!

Image for post
Image for post

E se nós simplesmente permitimos que esse tipo código seja promovido sem novas verificações, o código suspeito estará em produção e logo será esquecido.

Image for post
Image for post

A solução aqui é não confiar (exclusivamente) em ferramentas como Istanbul para verificar seu código.

É essencial defender uma avaliação do código analisado, ainda não há substituto para uma boa revisão de código!

Image for post
Image for post

Serviços de Cobertura de Código

Por aqui, já utilizamos todos os serviços e descobrimos que o Codecov é o vencedor claro por 3 razões:

  1. Fácil integração com ferramentas de CI (ex: Travis-CI)
  2. Ótimas estatísticas e visualizações
  3. Mensagens no PR informando o que mudou na cobertura de código

Configurando Codecov

  1. Selecione um repositório no qual você deseje monitorar a cobertura de código
  2. Adicione as seguintes linhas na sua configuração de CI:
before_install:
- pip install --user codecov
after_success:
- codecov --file coverage/lcov.info --disable search

Isso irá instalar Codecov como ferramenta de relatório para o seu CI, que enviará o lcov.info (que é gerado pelo Istanbul) para Codecov.

Exemplo real usando .travis.yml nesse repositório

Agora, quando você criar um PR, o seu CI irá enviar o relatório de cobertura de código para Codecov e Codecov irá deixar um comentário parecido com:

Image for post
Image for post
Sim, é possível ter relativamente “grandes” com 100% de cobertura de código

Você pode ter uma dica de que o novo código está sendo adicionado sem testes:

Image for post
Image for post

Você pode configurar um mínimo para a cobertura de testes, fazendo com que o PR falhe:

Image for post
Image for post
Nota: Se você quiser evitar que pessoas (ou seu time) criem PR com a quantidade menor do que a combinada (ex: 100%!!), adicione um script como coverage no seu pre-commit hook. Não sabe o que é o pre-commit hook? Leia mais sobre aqui!

Adicionando a “medalha” no seu README

Image for post
Image for post

Depois, é só colar no seu arquivo markdown!

Finalizando

Obter 100% de cobertura de testes de código, não significa um código de boa qualidade, ou que seja de fácil manutenção. Utilize isso como um meio, não como um fim.

E vale lembrar, se você está usando Jest, na instalação padrão, já temos o Istanbul configurado, facilitando nossa vida!

Créditos

Written by

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store