Tech Writers

Teste de unidade: Como identificar a eficácia de um teste? 

6 minutos

Um teste de unidade é um tipo de teste automatizado que verifica uma parte específica de um código de maneira rápida e isolada. O objetivo de um teste de unidade é garantir que o código esteja funcionando corretamente e que esteja fazendo o que é esperado dele. Ou seja, ele: 

  1. Verifica uma parte pequena do código;  
  1. De maneira rápida;  
  1. E de uma maneira isolada.   

Os desenvolvedores realizam os testes de unidade durante o processo de desenvolvimento do código, com o objetivo de identificar possíveis problemas ou erros de maneira rápida e precisa.  

Eles também são úteis para garantir que o código continue funcionando corretamente mesmo após alterações ou refatorações. 

Os testes de unidade são, geralmente, realizados em conjunto com outros tipos de testes, como testes de integração e testes de sistema, para garantir que a aplicação esteja funcionando de maneira adequada. 

Neste conteúdo, vamos ajudar você a entender quais parâmetros utilizar para identificar quando um teste de unidade é bom ou não. 

Princípios de um teste de unidade eficaz 

Mais do que verificar se o código "roda" ou não, é importante garantir que o comportamento esperado da aplicação vai ser realizado sem erros, atingindo o objetivo final do negócio.  

Dessa forma, é válido reiterar que testes automatizados não avaliam somente o código, mas o comportamento esperado daquele domínio de negócio.  

Hoje em dia, a importância dos testes automatizados é amplamente reconhecida nos projetos de software com objetivo de garantir escalabilidade com qualidade.  

Vladimir Khorikov, em seu livro Unit Testing: Principles, Practices and Patterns, propõe que é necessário pensar além de simplesmente fazer testes, mas também dar uma atenção especial para a qualidade, de maneira que os custos envolvidos na sua concepção e manutenção sejam os menores possíveis.   

Segundo o autor, essa necessidade surgiu pois a busca por uma meta de cobertura de testes de unidade nos projetos acaba gerando uma quantidade grande de testes, que em alguns casos não identificam possíveis bugs no sistema e comprometem uma parte significativa do tempo de desenvolvimento.  

Dessa forma, a seguir, apresentaremos os principais indicadores ao avaliar a eficácia de um teste de unidade ou não. 

4 principais indicadores de um teste de unidade eficaz 

Já trabalhou em um projeto onde, a cada mudança realizada, vários testes falham e você não identifica o porquê? Já teve que lidar com testes de difícil compreensão e foi necessário um tempo considerável para analisá-los?  

Esses são alguns indicativos que apontam ser necessário repensar os testes de um projeto.  

A seguir, vamos apresentar os quatro principais pontos, de acordo com Vladimir Khorikov, que nos ajudam a reconhecer bons testes de unidade.  

Proteção contra regressão 

A regressão é um bug no software e os testes devem ter capacidade de identificá-los. Quanto maior a quantidade de código de uma aplicação, mais exposta ela está a potenciais problemas.  

Para garantir essa proteção, é necessário que os testes executem o máximo de código possível, aumentando a chance de revelar uma regressão.  

Além disso, é necessário priorizar códigos de domínio do negócio e aqueles mais complexos, evitando avaliar comportamentos triviais da aplicação, por exemplo, métodos que só passam valores para propriedades de objetos.   

A imagem mostra um exemplo de um teste de comportamento trivial. Ele verifica um método que apenas atribui um valor string ao parâmetro Name de um objeto User. O próprio framework realiza essa atribuição.  

É necessário evitar esse tipo de teste e focar naqueles mais complexos ou que sejam realmente importantes para o negócio.   

Fig 1. Teste de Unidade de código considerado "trivial"  

Resistência a refatoração 

Refatorar significa mudar um código existente sem alterar o comportamento da aplicação. Muitas vezes, nos deparamos com projetos que tem uma alta cobertura de testes, que atendem nossos objetivos em um primeiro momento, mas a cada refatoração, a cada mínima melhoria, os testes falham.  

Nesses casos, é provável que em certo momento, essas falhas vão transformar o teste em um peso, o que está bem longe do seu objetivo.  

Para garantir essa resistência, é necessário evitar que o teste esteja acoplado ao código implementado. Ele deve estar focado em "o que" a aplicação deve fazer e não "como".   

A seguir vamos apresentar um teste que verifica o envio de uma expressão SQL correta para retornar um usuário com determinado ID. O teste é capaz de identificar bugs, mas existem outras expressões SQL que podem trazer o mesmo resultado.  

Uma mudança no código já acarreta em falhas no teste, mesmo que a aplicação retorne o mesmo usuário, ou seja, tenha o mesmo comportamento. É necessário evitar esse tipo de teste.   

Fig 2. Teste acoplado ao código implementado (Fonte: Vladimir Khorikov, Unit Testing: Principles, Practices and Patterns, 2020)  

Feedback rápido 

O feedback rápido é uma das propriedades básicas de qualquer teste de unidade. Quanto maior a velocidade de resposta, mais tempo você tem para lidar com atividades que importam.  

Testes longos também tornam a pipeline de Integração Contínua mais onerosa, já que, na maioria dos casos, há uma etapa para executar os testes do projeto. A consequência disso é atraso no deploy da aplicação e aumento nos custos.  

Não há um valor exato de tempo considerado bom ou ruim. Se o tempo de execução dos testes está tornando oneroso seu desenvolvimento, é um indício de testes mal construídos.  

Ser de fácil manutenção 

A manutenção é um elemento que deve sempre ser considerado, se queremos garantir a escalabilidade de nossas aplicações. Testes fáceis de se manter apresentam duas características:   

  • Ser fácil de ler: garantir a legibilidade do código para os desenvolvedores e especialistas no negócio é importante para um entendimento mais rápido do objetivo do teste e redução no custo de manutenção. Testes com menos linhas tendem a ser mais fáceis de serem compreendidos;   
  • Ser fácil de executar: é necessário criar uma infraestrutura para os testes, de forma que suas dependências (por exemplo, base de dados e APIs externas) se mantenham operacionais.   

Como vimos, é importante não só saber escrever testes como também fatorá-los de maneira a melhorar a qualidade e dar mais segurança às nossas aplicações.  

De qualquer maneira, é necessário avaliá-los a partir dessas quatro características. Isso garante o desenvolvimento de testes que sejam de baixo custo, fácil de se manter e que cumpram seu papel dentro da aplicação.   

Este artigo foi escrito baseado no capítulo 4 do livro “Unit Testing: Principles, Practices and Patterns”. Eu sugiro a leitura de todo o material para aqueles que querem se aprofundar sobre esse tema.   

*Agradecimento especial ao Valter Rodrigues, do Squad Hades, pelos apontamentos e revisão do texto*.  

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *