RSS
João Victor Oliveira

24 agosto de 2023

min para ler
Compartilhe

Testes unitários: o que você precisa saber antes de iniciar

"Dicas que parecem óbvias, dicas que me foram dadas e dicas que peguei com a prática."

 

Apresentarei algumas dicas e reflexões que tive até o momento trabalhando como desenvolvedor de software em um projeto onde os testes unitários são obrigatórios. Dicas que parecem óbvias, dicas que me foram dadas e dicas que peguei com a prática. 

Atualmente trabalho como desenvolvedor WEB front-end. Faço parte de um projeto de desenvolvimento em React e para os testes utilizamos React Testing Library com auxílio do Jest. 

Testes são uma documentação viva, é trabalhoso manter os testes, devem mudar juntamente com a regra de negócio, necessitam de manutenção, e por isso quebram constantemente. 

Provavelmente todo desenvolvedor passará várias horas escrevendo ou ajustando um teste. Essa grandeza é proporcional ao tamanho do projeto, quanto maior for o projeto, mais testes existirão para serem feitos e mantidos. Não existe uma quantidade certa ou errada. 

Queremos gastar mais tempo no início do desenvolvimento escrevendo testes do que lá na frente, tendo que investigar/corrigir features que funcionavam corretamente e quebraram de uma maneira que ninguém entende em um momento que ninguém sabe dizer. 

No projeto, quando começamos a dar mais importância para os testes, pude sentir que diminuímos nosso retrabalho com bugs em funcionalidades já entregues. Vi, na prática, a sua importância, tantas vezes que rodei os testes e vi que minha alteração no código teve impacto em lugares onde não imaginava. 

 

 

1. Os testes devem ser independentes 

 

Atente-se para escrever testes que passem a todo momento, não importando as circunstâncias. Se ele rodar sozinho, rodar antes de um teste X, depois de um teste X ou se por acaso estiver sem internet. 

Caso o teste necessite da utilização de um mock ou uma passagem de parâmetro, tenha certeza que essa variável ou estado esteja devidamente preparado para o comportamento esperado no teste. 

Já passei por momentos onde precisei usar um jest.clearMock (função do Jest) para limpar as chamadas de minha função. E já me atrapalhei com a referência de objetos JS na hora de fazer clones (Deep clone e Shallow clone). 

Nós não queremos fazer testes que estejam passando devido a cenários que aconteceram em outros testes. 

 

2. Coverage alto não deve ser sinônimo de segurança 

 

No meu atual projeto os testes são obrigatórios, e não é só isso, devemos no mínimo cobrir 70% do código. Para muitas pessoas (principalmente para quem não é desenvolvedor) coverage alto é para garantir previsibilidade e segurança, mas não é necessariamente assim. 

Os testes vão fazer somente aquilo que você programou para ele fazer, então faça algo verdadeiramente útil. Pense mais no cenário e menos nas linhas de código que faltam cobrir. 

Por exemplo: trabalho com React. Imagine que tenho um componente A, e que A tem os componentes B e C como filhos. Se no meu teste eu renderizo A, então por consequência também renderizo B e C. 

Por conta da renderização de A, o teste já dará coverage em trechos de código em A, B e C. Como meu teste de A deve focar em A, eu não estou de fato testando B e C como deveria. Mas o coverage subiu! 

A dica que dou nesses casos é: sempre testar os componentes começando dos mais internos e terminando nos mais externos. 

 

3. Acostume-se a ir quebrando o teste (de propósito) quando estiver fazendo-o 

 

Para termos certeza que é exatamente aquele ponto que estamos testando e que temos o total controle do teste, podemos ir simulando casos onde o teste quebra na medida que vamos construindo o próprio teste. 

Nos familiarizamos com o erro do teste para então corrigi-lo e fazer com que todos os cenários sejam cobertos. 

Serve para nos acharmos e também ajuda a entendermos melhor o componente. Já imaginou se por acaso o teste não quebrar no local onde esperávamos? Sinal de que não entendemos corretamente o funcionamento daquilo que estamos testando. 

Podemos mexer tanto no teste como também no código que está sendo testado. E obviamente, corrigimos logo em seguida. 

 

4. Mock e responsabilidade do teste 

 

Mocks são objetos criados de uma forma controlada para imitar objetos reais. Por conta deles podemos simular qualquer comportamento e focar exclusivamente no nosso cenário de teste. Testar o if, o else, os casos de exceção e muito mais. 

Com todo esse poder nas mãos podemos nos perder, então tenha em mente que um teste bem feito deve ter um único objetivo. 

Antes de criarmos o teste já devemos saber o que esperamos dele. E enquanto escrevemos, o teste deve apresentar um título autoexplicativo, deve ser simples, enxuto e testar apenas um cenário (cada teste terá sua responsabilidade). 

O Mock nos faz testar muito além do caminho feliz. Cada cenário precisará de um teste diferente e possivelmente um mock diferente. 

 

5. Faça um código testável e teste 

 

Aqui eu poderia até falar de TDD, mas esse não é o objetivo desse post. Não é errado fazer testes após implementar, pior seria não fazer o teste. 

Um bom momento para fazer os testes (se não o tiver feito) é logo após terminar de desenvolver a funcionalidade. Nesse momento temos tudo que precisamos, pois, sabemos exatamente como o código foi feito, qual o comportamento esperado e a regra de negócio continua fresquinha na memória. 

Não faça testes simplesmente para seu componente passar. Mas sim componentes que passem nos testes. 

Não tenha vergonha se precisar voltar no desenvolvimento e mexer em algum trecho, às vezes precisamos mudar a forma que codificamos o componente para melhor testá-lo. O teste vai, sim, influenciar em algumas decisões que tomamos na hora do desenvolvimento. 

 

6. No fim das contas, você quer ver seu teste quebrar 

 

Testes foram feitos para serem quebrados! 

Quando você faz um teste, você está afirmando: caso tal coisa pare de ter exatamente esse comportamento, eu quero ser notificado de que isso mudou. 

E então, caso futuramente o teste quebre, cabe aos desenvolvedores entenderem o erro e decidirem se o ajuste deve ser feito no teste ou no componente, dependerá da regra de negócio.