O Desenvolvimento orientado a testes – Test Driven Development (TDD) – é um conceito do desenvolvimento de software, usado principalmente quando falamos em QA (Quality Assurance). Também anda em conjunto com o desenvolvimento ágil, pois ele, juntamente com a integração contínua formam a base de manutenção do código em ambientes distribuídos.
Em teoria, times trabalhando no desenvolvimento dos testes ligados a um ambiente de integração com outros desenvolvedores contribui para que nenhuma funcionalidade deixe de cumprir seu papel, pois já foi testada de forma automatizada anteriormente.
O TDD não serve apenas para cobrir tua aplicação com testes automatizados. Ele guia o seu design.
Este artigo tenta reforçar a importância do desenvolvimento orientado a testes em um momento em que existe bastante controvérsias do uso ou não dele no desenvolvimento, principalmente quando não queremos “perder tempo”. Há quem diga que o TDD já morreu :/
Veja algumas opiniões:
- http://blog.caelum.com.br/mais-uma-vez-tdd-nao-e-bala-de-prata
- https://imasters.com.br/desenvolvimento/7-motivos-por-que-tdd-falhou-em-ser-mais-utilizado
A questão é que ele muda a forma de desenvolver e você precisa escolher a maneira que ele melhor se adapte para se tornar seu aliado, e não um inimigo.
Já vi diversas opiniões bastante controversas, dizendo que o TDD fez com que tivéssemos que produzir muito mais código de teste do que da própria aplicação. Muitas vezes sim, isto é verdade, mas não podemos ignorar que, quando aplicado de forma inteligente, ele pode fazer toda diferença na escalabilidade, mesmo sendo mais código, são menos Bugs, e código de teste não é código de produção, por isto muitas vezes as exigências com ele devem ser menores para não se tornar algo mais complicado que o código que ele testa em si.
E digo mais! Ele pode ser mais importante para o crescimento da sua aplicação do que próprias questões de infraestrutura, sobre qual linguagem escala mais etc. Vou falar posteriormente por que o Ruby é ainda a melhor linguagem para testes.
Uma das vantagens do TDD é testar funcionalidades e situações que você não tem uma forma fácil de testar de outra forma, como retornos de API’s complexas e situações de borda da sua aplicação. Sem contar ainda quando se fala de aplicações financeiras, o TDD para mim passa a ser essencial, pois testar pagamentos de forma manual é uma das tarefas mais custosas de manutenção e muitas vezes custa mais dinheiro do que evitar o TDD por “levar mais tempo”.
O TDD tem de ser simples
Quando a complexidade da aplicação aumenta, alguns testes e comportamentos que são difíceis de reproduzir se tornam códigos e dependências que também passam a ser difíceis de manter e acompanhar. Muitas vezes o problema dos testes está como eles evidenciam uma aplicação complicada demais e não flexível o suficiente para ser testada.
Os testes são ferramentas para contribuir e não para escravizar e impedir que mudanças rápidas sejam feitas. Aliás, ele nos dá mais segurança (quando não geramos falsos positivos) para sempre melhorar o código de forma contínua. O Refactoring é uma das etapas mais importantes do TDD.
As melhores linguagens e frameworks para teste
-
Ruby
O Ruby, principalmente no Rails ganha aqui não pela linguagem, mas pela sua comunidade que criaram ferramentas diversas para se testar e popularizou o BDD.
O BDD faz com seu código seja bastante claro em relação ao teste que você está fazendo (assertivo) e a facilidade de se interagir com o comportamento real do usuário.
- Python
Para mim é a melhor para testes juntamente com o Rails, ainda mais pela experiência que tive na Globo.com com a criação de Frameworks em Python em que contribuimos com a comunidade criando ferramentas de testes poderosas para realizar testes de interface utilizando linguagem natural. - React
O React, com o Jest e as bibliotecas que simulam o DOM fizeram com que ficasse muito fácil fazer asserções no conteúdo do DOM gerado pelo React. Também é bem prático testar componentes isolados e diferentes estados. Outro fator que surpreendi muito foi teste com react para aplicações nativas. O Jest tem também a ferramenta incrível de snapshot, que valida estados definidos em um determinado momento.
Práticas do TDD
O TDD para funcionar de forma eficiente precisa de muito pragmatismo pra se beneficiar de todo seu potencial. Precisamos definir também um escopo para ele. No fim, para mim não importa a quantidade de testes e cobertura e sim a resposta que você precisa para dar um passo a frente, e não se o teste é unitário, funcional ou de interface.
Então temos alguns motivos e práticas importantes quando utilizamos o TDD:
- O motivo de fazer o teste primeiro é perguntar para a máquina o retorno de algo que você precisa para seguir adiante com seu código.
- Não é burrice você fazer um teste sabendo que ele vai quebrar, mas esperar seu resultado antes de dar o próximo passo mas resolver um problema de cada vez.
- O TDD faz você entender melhor o código dos outros
- Conseguimos também relembrar melhor nosso código quando usamos TDD. Eu tento muitas vezes deixar um teste falhando para corrigir no outro dia como sendo o próximo passo que preciso seguir para completar um código.
- Com o TDD nós podemos testar situações que não precisamos reproduzir. Se o retorno de um request, por exemplo, for x, eu posso testar diferentes retornos sem necessariamente passar todos os estados
- Uma das questões mais difíceis de praticar o TDD são aplicações com comportamentos randômicos, ou situações que não conseguimos reproduzir no fluxo direto
Teste antes, mas não se mate por não testar depois
O TDD, como a própria definição sugere (driven), é desenvolvimento orientado a testes. Sendo assim, o teste passa a ser a primeira parte do código. O processo é basicamente:
- Crie o teste com a situação desejada
- Execute o código e veja que ele falha pelo motivo esperado
- Faça uma solução simples que garante que ele tenha o retorno desejado
- Execute o código e veja que o teste passa
- Mude a parte testada para que ele seja uma solução mais próxima da real
- Execute o código e veja que o teste passa
São 6 passos do fluxo do TDD para seguir adiante para cada funcionalidade que você precisa criar ou modificar. Estes testes correspondem a diferentes níveis da aplicação que reflete diferentes níveis, como funcional, integração e unitários. O nome e tipo de teste pode variar de empresa a empresa.
Você pode tirar todo o proveito destes passos, mas não se apegue a eles se alguma situação você precisar seguir de uma forma diferente e se algum passo se tornou muito difícil. Chega uma hora que você vai ver que o processo não tem como ser perfeito, mas ajudou e foi útil enquanto durou e você pode retomá-lo novamente. O TDD é sempre desafiante e questionado no desenvolvimento. Muitas vezes eu quero fazer prototipagem rápida e não vou comprometer a qualidade se não fiz os testes seguindo a risca o processo. Dizer que por isto o TDD tem que morrer e parar de ser usado já é ir para o outro extremo. Ele amadurece com a experiência.
O TDD na veia
O fato é que sempre teremos uma resistência natural a uma nova abordagem de desenvolvimento e o TDD pode parecer um pouco “radical”, mas depois que você se acostuma com o processo, vê que ele passa a fazer parte do dia a dia e gera uma certa “desconfiança” natural ao seu código. Isto por que naturalmente com o TDD você começa a ver que para fazer grandes mudanças e refazer certas partes do sistema, pensar em não ter testes se torna algo abominável e assustador.
Apesar de ver como algo essencial, não usar TDD não faz com que o código e a qualidade seja melhor, mas usá-lo de forma eficiente é uma garantia mínima e eficaz de automatizar os processos de teste. Sem o TDD, aplicações complexas são bastante questionáveis.
One Reply to “Os testes te guiam – Alguns motivos a mais para você usar TDD e BDD”