(Pergunta) Quando devo usar testes?
Estava tranquilo fazendo meu CRUD. Uma Todo List que pretendo personalizar para meu irmão. Por enquanto está bem genérica e não tenho certeza de até onde isso pode evoluir.
Quando o grosso já estava feito e funcionando comecei a pensar "Bom, e agora? Continuo criando features feito louco ou paro um pouco para consolidar meu progresso?".
Estou falando sobre testes.
Sempre que fazia uma mudança nas rotas ou nas funções em /models tinha que sair testando manualmente todas as funcionalidades.
Posso fazer testes automatizados para as funções antigas, que vão me avisar se eu quebrar uma função antiga, na teoria. Assim posso focar nas coisas novas sem ter medo de ser feliz.
Arreganhei as mangas e fui pesquisar sobre testes de unidade, de integração, end to end, jest, supertest, etc.
Basicamente o que eu tinha para testar na hora eram as rotas de um CRUD, que chamavam funções que faziam verificações simples com a requisição e chamavam outra função que fazia a query para o banco de dados.
Totalizando três camadas a serem testadas.
Aprendi o básico da sintaxe de Jest:
describe()test()beforeEach()beforeAll()
Tive algumas dificuldades configurando ele. Estava dando um problema sobre CommonJS e ES Modules. Resolvi alterando o comando dentro do package.json de "test": "jest" para "test": "NODE_OPTIONS=\"--experimental-vm-modules\" jest". Também havia a opção de usar um tal de babel para "transpilar"(??) meu código para CommonJS.
Sinceramente, só queria avançar, estava confuso com o funcionamento do Jest e não queria instalar mais uma biblioteca.
Em seguida fui pesquisar sobre mock para testar cada camada separadamente. Esse foi o principal motivo para fazer esse post. Tive diversos problemas para substituir as funções que fazem query para o BD por funções mockadas. Acontecia por causa que as funções de /models eram importadas pelo arquivo de teste antes de mockar as funções. Assim o mock não funcionava. Depois de perder quase uma tarde inteira lendo a documentação achei a solução pro meu problema.
Agora, livre para escrever meus testes em paz, depois de fazer os primeiros testes com ajuda da IA fui entendendo melhor a lógica por trás de mockar funções e como isso realmente funcionava (a lógica de dizer o que a função mockada vai retornar para a função que você está testando).
Mesmo tendo apenas duas tabelas no meu banco de dados, ainda foi um processo bem repetitivo e aparentemente inútil. Tive que fazer tantos mocks que cheguei a perder de vista o que estava realmente testando. E isso se deve a lógica simples das funções que estava testando.
Por exemplo, na função a seguir há uma validação mínima seguida de uma requisição ao banco de dados:
export async function login(req, res) {
const { email, password } = req.body;
if (!email || !password) return res.status(400).json({ error: 'Email e senha necessários' });
try {
const user = await findUserByEmail(email);
if (!user) return res.status(401).json({ error: 'Email ou senha inválidos' });
const match = await bcrypt.compare(password, user.password);
if (!match) return res.status(401).json({ error: 'Email ou senha inválidos' });
const token = jwt.sign({ id: user.id, email: user.email }, process.env.JWT_SECRET, { expiresIn: '7d' });
res.json({ token });
} catch (err) {
res.status(500).json({ error: 'Erro ao fazer login' });
}
}
Com certeza tirei vários aprendizados fazendo os testes. Passar por todos os possíveis fluxos de execução e lidar com cada um foi um deles.
Fora lidar com cada resposta possível da função, praticamente não tinha nada a ser testado.
Terminei com a sensação que foi um tempo desperdiçado. Imagino que testes se paguem no longo prazo, conforme o sistema cresce e fica mais complicado, você mantém tudo sobre controle.
Você tem um alerta para saber quando algo para de funcionar sem ter que manter o código inteiro na "RAM" junto com qual código interage com qual.
É essa a lógica por trás dos testes? Ou eu ainda estou perdendo de vista algo importante?