O documento discute a metodologia de desenvolvimento de software Test-Driven Development (TDD). TDD envolve escrever testes unitários antes de escrever o código, seguindo os passos de escrever um teste que falhe, implementar o código para fazer o teste passar, e refatorar o código. TDD visa gerar código limpo e testado para melhorar a qualidade e reduzir bugs. Ferramentas como JUnit e Selenium podem ser usadas para automatizar testes.
54. Prática
Demonstração
• Testes unitários
– Calculadora com JUnit
• Teste web
– Pesquisa no Google com WebDriver (Internet)
– Navegação entre duas páginas
Por que você escolheu ser um desenvolvedor de software?
Eu sei que muita gente louca, como eu, faz isso porque gosta.
Mas precisamos pagar as contas. Esperamos ganhar dinheiro, certo?
Embora alguns achem que não dá tanto retorno
Como faturar mais com software?
É preciso vender e agradar os clientes. Como fazer isso?
Software de qualidade. Faz exatamente o que o cliente precisa. Apresentar o mínimo de erros.
Ele precisa funcionar!
O problema é que o software possui certas características o tornam inerentemente complexo.
Abstrato: ele não pode ser representado de forma visível. É um verdadeiro desafio mapear os requisitos (o que um software deve fazer).
Singular: cada software é diferente, se eu pedir para cada pessoa aqui criar uma calculadora, cada um fará algo diferente
Mutável: mude 1 bit e não temos mais o mesmo programa.
Complexo: Se você simplifica, ele perde suas características. Não dá pra ter tudo na cabeça. Podemos criar modelagens, mas sempre haverá um gap do modelo até o código concreto.
Desenvolvedores acham que conseguem pensar em todo o software, são otimistas. Mas quando implementam surgem os problemas.
Como fazer software com qualidade? Alguns dizem: "para o software funcionar, basta fazer direito."
Alguém já fez um programa que funcionou 100% corretamente da primeira vez?
Como você garante que ele realmente funciona?
Pensando no ciclo tradicional, nós deixamos o teste por último.
Mas mudanças acontecem. Imprevistos. Pessoas e negócios mudam.
A filosofia ágil: abrace as mudanças.
Gráfico do custo da manutenção. Quanto antes o código estiver coreto melhor. Ao testar depois, achamos problemas muito tarde. O custo de correção aumenta com o tempo que o bug está no sistema.
Para corrigir um bug no início do desenvolvimento, você simplesmente “pisa” nele.
Bugs não corrigidos vão voltar para assombrar você.
Como o TDD ajuda em tudo isso?
Colocamos o teste primeiro. Durante o design de uma funcionalidade, já é definido o comportamento esperado através de testes. Assim o bug tende a ser encontrado logo de início.
Convém uma discussão sobre definição de pronto. Quanto podemos dizer que terminados uma funcionalidade?
Podemos dizer que terminamos algo quando terminados de codificar? Geralmente a primeira versão do código tem gambiarras.
É preciso "limpar" o código (refatorar), removendo duplicidade, trechos desnecessários, simplificando e melhorando o desempenho.
Mas isso não basta. O que acontece quando o usuário ou testador encontrar um problema? Atraso e custo.
Testar é importante. Mas como você faz? Depurando todo o programa? Executando o programa manualmente e olhando o resultado? O que acontece quando algo precisa ser modificado e é necessário retestar tudo de novo?
Podemos automatizar os testes. Mas não é suficiente se levarmos horas e dias para conseguir enviar uma nova versão para o cliente. Ainda há riscos de problemas de configuração em "produção".
Automação na entrega (deploy) permite que uma funcionalidade implementada e testada possa ser colocada em produção sem mais atrasos. Mas não adianta entregar para o cliente sem a documentação.
Finalmente acrescentamos ainda a documentação. Lembrando que esta é apenas uma das definições de pronto. Cada projeto pode demandar algo diferente.
Ciclo de vida do TDD. Vermelho, Verde e Refatore! Esse é o ciclo de cada funcionalidade.
Os três passos são conhecidos como o "mantra" do TDD, que se repete até que o software esteja completa.
Primeiro você cira um teste e executa. Isso garante que o teste funciona e mostra a luz vermelha.
Em seguida, faça o código funcionar, do jeito mais direto, sem inventar. Não é código ruim, precisa ser código que funcione em "produção".
Porque separar as duas coisas: fazer simples e refatorar.
A primeira resposta: porque os programadores tendem a ignorar a segunda parte. Se já está funcionando, não mexa!
Benefícios do TDD:- Foco na qualidade- Documentação do código através dos testes (o que é esperado para cada funcionalidade)- Acaba com o medo de mudanças
Você vê um código feito e diz: não mexa, pode parar de funcionar.
O TDD dá coragem ao desenvolvedor. Permite a melhoria do sistema sem medo de mudar o que está lá, permite que outras pessoas saibam o que o seu código deve fazer.
Testes de regressão automatizados podem ser repetidos quantas vezes e quando se desejar. Você não precisa mais refazer todo o teste manualmente.
Poréns...
É preciso investir mais tempo para os testes. Embora na teoria os testes se paguem ao final do projeto, muitos clientes não estão dispostos a pagar por qualidade.
Indefinição: quando não se consegue saber exatamente quais os requisitos, onde se quer chegar. Como criar testes?
É necessário ter experiência (prática) e dedicação para conseguir criar bom design do software, além de software testável.
Os dois primeiros itens são fontes externas de problemas. O ponto que nós, como desenvolvedores precisamos atacar é a questão do projeto do software.
Há duas principais metáforas para o que é o desenvolvimento de software.
Alguns pensam como Engenheiros de Software, estudando essa disciplina sistematicamente, construindo a "ponte" entre o problema e a solução (próprio software). Eles tentam entender como produzir software "em escala"
Outros pensam como Artesãos de Software, já que cada software e cada desenvolvedor são únicos.
Ninguém nasce ou mesmo sai de uma faculdade sabendo.
Algumas pessoas tem jeito, mas aprender a projetar bem exige experiência e disciplina, como os artistas clássicos.
Para que o TDD funcione bem, o design ou a arquitetura do software conta muito. Ele vai ajudar na disciplina de sempre buscar a perfeição.
Os princípios de design orientado a objetos SOLID são:
Single Responsibility Principle: cada classe deve ter uma responsabilidade única. Ela só vai precisar ser modificada quando houver mudança nos requisitos relacionados a sua função.Open/close principle: as classes devem ser abertas para extensão e fechadas para modificação. Isso significa que novas funcionalidades devem ser adicionadas sem alterar as classes existentes. Isso geralmente é obtido através de herança e polimorfismo.Liskov substitution principle: objetos devem poder ser substituídos por subtipos sem quebrar o programa. Isso significa que que subclasses não podem quebrar o contrato da superclasse que estendem.Interface segregation principle: interfaces específicas são melhores do que uma interface genérica com vários métodos.Dependency inversion principle: uma classe não deve depender de outras classes concretas, mas de abstrações.
Não entrarei em detalhes, porque seria outra apresentação. Isso é apenas uma informação para o ouvinte buscar e aprender por si mesmo.
Se fosse possível resumir tudo isso em algo bem simples: temos que aprender a dividir as funcionalidades do software em componentes que sejam o mais independentes possível.
Ao dividir o software em componentes, podemos testá-lo individualmente para garantir que cada unidade funcione como esperado. Isso evita muita dor de cabeça na hora de "juntar tudo".
Os testes unitários devem evitar interferência (possíveis erros) e outras classes.
É comum iniciarmos testes somente executando código, sem realmente verificar a saída das rotinas. Porém, um teste automatizado somente possui valor real se ele puder por si mesmo determinar o sucesso ou falha.
Quanto há dependência de algo, uma saída é usar os mocks, que são objetos que simulam o real. Assim, defini-se o comportamento esperado das dependências de forma que o teste é mais rápido e independente dos outros componentes estarem corretos ou não.
Muitos argumentam que mocks são um quebra-galho e devem ser evitados. Um sinal de design ruim é justamente a necessidade de muitos mocks, pois significa que há um forte acoplamento entre os componentes.
Tipos de teste:
Integração: teste com que envolve vários componentes do sistema, para ver se a integração ocorre normalmente. Nível um pouco mais alto que o teste unitário.
Carga: quantos usuários o sistema consegue atender bem (carga máxima).
Estresse: até quanto o sistema consegue atender, mesmo que mal (sem travar).
Desempenho: o tempo de resposta até uma certa quantidade de usuários.
Resiliência: como o sistema se recupera de falhas ou utilização acima do limite (picos).
Aceitação: o usuário ou interessado verifica se o software faz o que foi pedido.
Cobertura: quais partes do código foram realmente testadas?
Regressão: repetição dos testes já executados para garantir que não houve regressão (algo parou de funcionar). Aqui o TDD com testes automatizados realmente brilha.
Ferramentas de automação de testes em Java:
- http://junit.org/
- http://testng.org/doc/index.html
- http://www.seleniumhq.org/
- http://htmlunit.sourceforge.net/
- http://www8.hp.com/us/en/software-solutions/unified-functional-testing-automation/ (fechado)
- https://github.com/mockito/mockito
- http://jmock.org/
- https://code.google.com/p/powermock/
- http://easymock.org/
Com exceção do UFT (Unified Functional Testing) da HP, todos os demais são de código-aberto e gratuitos.
Ferramentas de automação de testes em Java:
- http://www.eclemma.org/
Ferramentas de automação de testes em Java:
- http://www.eclemma.org/
TDD não é uma solução mágica. Você deve experimentar e chegar à conclusão do que funciona, quando funciona e onde funciona.
TDD is not about TDD. Todo processo seguido pelo processo, cegamente, mais atrapalha do que ajuda.
É um exercício diário para você. Qualidade em software é algo que exige dedicação, experiência e disciplina.
TDD é sobre como criar software de qualidade, que faz o que precisa fazer, seja entregue no tempo, e não seja um pesadelo para o programador. Ele tenta dar uma direção a ser seguida.
É preciso se aplicar e aperfeiçoar esses princípios que apenas começamos a ver.
Como fazer uma obra-prima ao invés de arte moderna? Como fazer um prédio que não cai?Pratique, só assim se alcança qualidade.