Nessa palestra relato minha experiência não como um desenvolvedor de software altamente sinistro com duzentos anos de experiência e mil livros publicados - mas sim como um "mero mortal", um desenvolvedor "de verdade", do "mundo real" aplicando a teoria que aprendeu d...
Nessa palestra relato minha experiência não como um desenvolvedor de software altamente sinistro com duzentos anos de experiência e mil livros publicados - mas sim como um "mero mortal", um desenvolvedor "de verdade", do "mundo real" aplicando a teoria que aprendeu do TDD.
Size: 1.88 MB
Language: pt
Added: Aug 17, 2013
Slides: 99 pages
Slide Content
TDD para “meros mortais”TDD para “meros mortais”
Porque a vida real é mais que Fibonacci!Porque a vida real é mais que Fibonacci!
Quem sou eu?Quem sou eu?
Thiago BaptistaThiago Baptista
Desenvolvedor há uns 3 anos (principalmente Java)Desenvolvedor há uns 3 anos (principalmente Java)
Entusiasta do Software Livre e do Movimento ÁgilEntusiasta do Software Livre e do Movimento Ágil
Tarado por Computação e estudar novas tecnologias...Tarado por Computação e estudar novas tecnologias...
Quem sou eu?Quem sou eu?
...UM “MERO MORTAL”!!!...UM “MERO MORTAL”!!!
Não sei nem 40% do que Não sei nem 40% do que ACHOACHO que sei que sei
Não sei nem 30% do que eu Não sei nem 30% do que eu DEVERIADEVERIA saber saber
Vivo no “mundo real”Vivo no “mundo real”
Como assim, “mundo real”?Como assim, “mundo real”?
Agilidade é (ainda) desconhecidaAgilidade é (ainda) desconhecida
Empresas são “fábricas de software”Empresas são “fábricas de software”
Relação cliente-empresa é conflituosaRelação cliente-empresa é conflituosa
Prazos estouram, retrabalho, código “macarrônico” etc.Prazos estouram, retrabalho, código “macarrônico” etc.
Maioria dos projetos é manutenção de código legadoMaioria dos projetos é manutenção de código legado
Desenvolvedores do “mundo Desenvolvedores do “mundo
real”real”
Não têm larga experiênciaNão têm larga experiência
Se concentram em Se concentram em umauma tecnologia tecnologia
Foram educados em Foram educados em umauma metodologia de trabalho metodologia de trabalho
Na faculdade vivem um mundo Na faculdade vivem um mundo totalmente distantetotalmente distante do do
mercado de trabalho (Swing?? Dicionário de dados??? mercado de trabalho (Swing?? Dicionário de dados???
UML é “novidade”?!?)UML é “novidade”?!?)
O trabalho do desenvolvedor na O trabalho do desenvolvedor na
“vida real”“vida real”
Empresas que há Empresas que há muitosmuitos anos trabalham da mesma forma anos trabalham da mesma forma
Gerentes e chefes que desconhecem o ofícioGerentes e chefes que desconhecem o ofício
Ou, quando conhecem, estão Ou, quando conhecem, estão MUITOMUITO desatualizados desatualizados
Num constante clima de correria e prazos estouradosNum constante clima de correria e prazos estourados
Sem tempo ou recursos para se atualizarSem tempo ou recursos para se atualizar
Sem incentivo para se atualizarSem incentivo para se atualizar
Dialética do desenvolvimento de Dialética do desenvolvimento de
softwaresoftware
Tese: de um lado, essa “vida real”Tese: de um lado, essa “vida real”
Antítese: do outro, novas e muito melhores técnicas, Antítese: do outro, novas e muito melhores técnicas,
metodologias e tecnologiasmetodologias e tecnologias
Síntese: Síntese: ??????
Desenvolvedor “ágil” hoje: meu Desenvolvedor “ágil” hoje: meu
casocaso
Li e estudei bastante sobre issoLi e estudei bastante sobre isso
Vi na prática acontecer e dar certoVi na prática acontecer e dar certo
Defendo e procuro aplicar issoDefendo e procuro aplicar isso
Porém...Porém...
Desenvolvedor “ágil” hoje: meu Desenvolvedor “ágil” hoje: meu
casocaso
...SOU UM MERO MORTAL!!!...SOU UM MERO MORTAL!!!
Conheço bem a teoria, mas tenho pouca experiência Conheço bem a teoria, mas tenho pouca experiência
práticaprática
Portanto, sei Portanto, sei muito menosmuito menos do que eu do que eu ACHOACHO que sei que sei
Tive pouquíssimas oportunidades de colocar em práticaTive pouquíssimas oportunidades de colocar em prática
TDD para “meros mortais”TDD para “meros mortais”
Estudo de caso: um “mero mortal” aplicando a teoria do Estudo de caso: um “mero mortal” aplicando a teoria do
TDD na prática!TDD na prática!
Revisando a teoria...Revisando a teoria...
Desenvolvimento (ou design) guiado por testesDesenvolvimento (ou design) guiado por testes
Escreve-se um teste Escreve-se um teste primeiroprimeiro, e só depois o código “real”, e só depois o código “real”
Código “real” é sempre fruto de se fazer um teste escrito Código “real” é sempre fruto de se fazer um teste escrito
previamente passarpreviamente passar
Test-Driven Development/DesignTest-Driven Development/Design
TDD em essênciaTDD em essência
Segundo Kent Beck, “autor” da técinca:Segundo Kent Beck, “autor” da técinca:
Escreva um teste automatizado que falhe antes de Escreva um teste automatizado que falhe antes de
escrever qualquer outro códigoescrever qualquer outro código
Escreva um código para fazer esse teste passarEscreva um código para fazer esse teste passar
Remova a duplicaçãoRemova a duplicação
TDD em essênciaTDD em essência
Segundo Kent Beck, “autor” da técinca:Segundo Kent Beck, “autor” da técinca:
Escreva um teste automatizado que falhe antes de Escreva um teste automatizado que falhe antes de
escrever qualquer outro código escrever qualquer outro código [VERMELHO][VERMELHO]
Escreva um código para fazer esse teste passar Escreva um código para fazer esse teste passar [VERDE][VERDE]
Remova a duplicação Remova a duplicação [REFATORAR][REFATORAR]
...repetir o processo......repetir o processo...
Conceitos importantesConceitos importantes
Só pode haver código “real” se houver antes um teste que Só pode haver código “real” se houver antes um teste que
falhefalhe
Deve-se avançar com “passinhos de bebê” (Deve-se avançar com “passinhos de bebê” (baby stepsbaby steps))
Só se adiciona um novo teste que falhe após todos os Só se adiciona um novo teste que falhe após todos os
outros testes estarem “verdes”outros testes estarem “verdes”
Baby stepsBaby steps
Faz-se o Faz-se o mínimomínimo necessário para o teste ficar “verde” necessário para o teste ficar “verde”
Após o “verde”, refatora-se para eliminar a redundânciaApós o “verde”, refatora-se para eliminar a redundância
Cria-se um novo teste para “quebrar” novamenteCria-se um novo teste para “quebrar” novamente
Faz-se o Faz-se o mínimomínimo necessário para ambos os testes necessário para ambos os testes
passarempassarem
Refatora-se de novoRefatora-se de novo
Repete-se o processo até ter código “real” funcionando “de Repete-se o processo até ter código “real” funcionando “de
verdade”verdade”
Clássico exemplo: multiplicar por Clássico exemplo: multiplicar por
22
Funcionalidade: um método que receba um inteiro como Funcionalidade: um método que receba um inteiro como
argumento e retorne o produto deste por 2argumento e retorne o produto deste por 2
Exemplos:Exemplos:
multiplicar(5) == 10multiplicar(5) == 10
multiplicar(13) == 26multiplicar(13) == 26
multiplicar(0) == 0multiplicar(0) == 0
Clássico exemplo: multiplicar por Clássico exemplo: multiplicar por
22
Primeiro passo: um teste que falhaPrimeiro passo: um teste que falha
Clássico exemplo: multiplicar por Clássico exemplo: multiplicar por
22Segundo passo: implementar o Segundo passo: implementar o mínimo absolutomínimo absoluto pro teste pro teste
passarpassar
Clássico exemplo: multiplicar por Clássico exemplo: multiplicar por
22
Terceiro passo: novo teste que falha e “quebra” o códigoTerceiro passo: novo teste que falha e “quebra” o código
Clássico exemplo: multiplicar por Clássico exemplo: multiplicar por
22Quarto passo: implementar, novamente, o mínimo para os Quarto passo: implementar, novamente, o mínimo para os
doisdois testes passarem testes passarem
Clássico exemplo: multiplicar por Clássico exemplo: multiplicar por
22
Quinto passo: refatorar para eliminar a redundânciaQuinto passo: refatorar para eliminar a redundância
Clássico exemplo: multiplicar por Clássico exemplo: multiplicar por
22Enésimo passo: repetir até ter a segurança para Enésimo passo: repetir até ter a segurança para
implementar o código “de verdade”, de produçãoimplementar o código “de verdade”, de produção
Conclusões e benefíciosConclusões e benefícios
TDD é como a rede de proteção dos malabaristas no circoTDD é como a rede de proteção dos malabaristas no circo
De quebra, ainda te dá uma cobertura de testesDe quebra, ainda te dá uma cobertura de testes
Garante que o código faça o mínimo necessárioGarante que o código faça o mínimo necessário
Manter esse código: mel na chupeta!Manter esse código: mel na chupeta!
É só continuar com o processo do TDD de onde parouÉ só continuar com o processo do TDD de onde parou
Garante a aprendizagem do códigoGarante a aprendizagem do código
Aprendizagem do código??Aprendizagem do código??
Desenvolvimento de softwareDesenvolvimento de software
NÃO É MANUFATURA!!!NÃO É MANUFATURA!!!
NÃO É MANUFATURA!!!NÃO É MANUFATURA!!!
Na manufatura...Na manufatura...
Você sabe de antemão o resultado que quer (você tem o Você sabe de antemão o resultado que quer (você tem o
“molde”)“molde”)
O processo de construção é O processo de construção é determinísticodeterminístico
Para cada resultado esperado, um processo determinadoPara cada resultado esperado, um processo determinado
f(x) = yf(x) = y
O processo de construção é conhecido previamenteO processo de construção é conhecido previamente
O processo de construção pode ser replicadoO processo de construção pode ser replicado
...agora, digamos, na arte......agora, digamos, na arte...
Desenvolver software éDesenvolver software é
traduzirtraduzir
CONHECIMENTOS DE NEGÓCIOCONHECIMENTOS DE NEGÓCIO
parapara
ALGORÍTMOS COMPUTACIONAISALGORÍTMOS COMPUTACIONAIS
ALGORÍTMOS COMPUTACIONAISALGORÍTMOS COMPUTACIONAIS
ALGORÍTMOS COMPUTACIONAISALGORÍTMOS COMPUTACIONAIS
ALGORÍTMOS COMPUTACIONAISALGORÍTMOS COMPUTACIONAIS
ALGORÍTMOS COMPUTACIONAISALGORÍTMOS COMPUTACIONAIS
Como??Como??
VOCÊ NÃO SABE!!!!VOCÊ NÃO SABE!!!!
Você não sabe:Você não sabe:
Sobre o negócio, tão bem quanto o clienteSobre o negócio, tão bem quanto o cliente
Sobre a real necessidade de um requisito na “hora H”Sobre a real necessidade de um requisito na “hora H”
Se o cliente sabe o que quer ou se você o entendeu direitoSe o cliente sabe o que quer ou se você o entendeu direito
Se no futuro os requisitos mudarãoSe no futuro os requisitos mudarão
Se você está traduzindo o conhecimento direitoSe você está traduzindo o conhecimento direito
Se você sabe desenvolver softwareSe você sabe desenvolver software
Lição número 1Lição número 1
TDD é sobre o TDD é sobre o aprendizado do códigoaprendizado do código
Aprendizado??Aprendizado??
Mas eu sei multiplicar um número por 2...Mas eu sei multiplicar um número por 2...
Mas eu sei multiplicar um número por 2...Mas eu sei multiplicar um número por 2...
TDD na “vida real”TDD na “vida real”
““Multiplicar por 2”, Fibonacci, Fatorial etc. são exemplos Multiplicar por 2”, Fibonacci, Fatorial etc. são exemplos
conceituaisconceituais
A “vida real” é muito mais complexaA “vida real” é muito mais complexa
CRUDs que lidam com persistênciaCRUDs que lidam com persistência
Aplicações web que lidam com a camada HTTPAplicações web que lidam com a camada HTTP
Threads, computação assíncrona etc.Threads, computação assíncrona etc.
Estudo de caso: cliente para o Estudo de caso: cliente para o
WebPagetestWebPagetest
Estudo de caso: cliente para o Estudo de caso: cliente para o
WebPagetestWebPagetest
http://www.webpagetest.orghttp://www.webpagetest.org
Aplicação web para testar desempenho de sitesAplicação web para testar desempenho de sites
Fornece uma API REST, mediante inscrição (gratuita)Fornece uma API REST, mediante inscrição (gratuita)
https://sites.google.com/a/webpagetest.org/docs/advanhttps://sites.google.com/a/webpagetest.org/docs/advan
ced-features/webpagetest-restful-apisced-features/webpagetest-restful-apis
Gera relatórios na web, via XML ou JSONGera relatórios na web, via XML ou JSON
O desafio:O desafio:
Cliente de linha de comando (shell) para o WebPagetestCliente de linha de comando (shell) para o WebPagetest
Para rodar de tempos em tempos (cron)Para rodar de tempos em tempos (cron)
Deve iniciar um teste para um site específicoDeve iniciar um teste para um site específico
Deve aguardar o teste terminar e saber quando isso Deve aguardar o teste terminar e saber quando isso
aconteceracontecer
Deve obter o relatório do teste e exibir os dados conforme Deve obter o relatório do teste e exibir os dados conforme
requeridorequerido
Os obstáculos:Os obstáculos:
API com número reduzido de chamadas permitidasAPI com número reduzido de chamadas permitidas
Só 200 testes num período de 24hsSó 200 testes num período de 24hs
Ter que usar a camada HTTPTer que usar a camada HTTP
Trabalhar com XMLs (API JSON muito limitada na época)Trabalhar com XMLs (API JSON muito limitada na época)
Trabalhar com a linha de comandoTrabalhar com a linha de comando
Para chamar a aplicação e iniciar o testePara chamar a aplicação e iniciar o teste
Para exibir os resultados do testePara exibir os resultados do teste
Salvar resultados no sistema de arquivos (em logs)Salvar resultados no sistema de arquivos (em logs)
As ferramentas:As ferramentas:
Plataforma JavaPlataforma Java
GroovyGroovy
API HTTP nativaAPI HTTP nativa
API de XML nativaAPI de XML nativa
API de testes nativaAPI de testes nativa
API nativa para trabalhar com a linha de comando (Groovy CLI)API nativa para trabalhar com a linha de comando (Groovy CLI)
TDDTDD
Como fazer isso??Como fazer isso??
TDD me ensinou!TDD me ensinou!
Tá, mas... por Tá, mas... por ondeonde começar?? começar??
Aplicando o TDDAplicando o TDD
Minha principal dúvida: por Minha principal dúvida: por ondeonde começar um projeto da começar um projeto da
“vida real”“vida real”
Qual classe? Qual caso de uso ou história do usuário? Qual classe? Qual caso de uso ou história do usuário?
Qual método? Qual funcionalidade?Qual método? Qual funcionalidade?
Se uso um framework, devo começar o testando Se uso um framework, devo começar o testando
também?também?
Maior “defeito” do ensino do TDD - onde se começaMaior “defeito” do ensino do TDD - onde se começa
E por falar em “começos”...E por falar em “começos”...
Testes “tradicionais” e TDDTestes “tradicionais” e TDD
““Teste”, tradicionalmente, faz parte da linguagem do Teste”, tradicionalmente, faz parte da linguagem do controle controle
de qualidadede qualidade (“Quality Assurance” - QA) (“Quality Assurance” - QA)
Testa-se para saber se algo que Testa-se para saber se algo que já existejá existe se conforma a se conforma a
padrões esperados de comportamento e qualidadepadrões esperados de comportamento e qualidade
Todo um mundo de metodologias, técnicas, certificações Todo um mundo de metodologias, técnicas, certificações
etc.etc.
Todo um linguajar próprio:Todo um linguajar próprio:
Teste de unidade, de integração, de regressão, de Teste de unidade, de integração, de regressão, de
aceitaçãoaceitação
Teste “caixa-preta”, “caixa-branca”, “caixa-cinza” etc.Teste “caixa-preta”, “caixa-branca”, “caixa-cinza” etc.
Testes “tradicionais” e TDDTestes “tradicionais” e TDD
O profissional de QA planeja a execução dos testes O profissional de QA planeja a execução dos testes
conforme os requisitos, testa e, então, gera seus conforme os requisitos, testa e, então, gera seus artefatosartefatos
TDD não é sobre QA!TDD não é sobre QA!
QA é QA é muitomuito importante, mas não importante, mas não
é disso que estamos falando...é disso que estamos falando...
TDD e “tipos de teste”TDD e “tipos de teste”
O linguajar sobre testes, em TDD, quer dizer coisas O linguajar sobre testes, em TDD, quer dizer coisas
diferentesdiferentes do que quer dizer em QA do que quer dizer em QA
Teste de unidade geralmente se refere à “testar classes”Teste de unidade geralmente se refere à “testar classes”
Teste de integração/aceitação geralmente se refere a Teste de integração/aceitação geralmente se refere a
testar funcionalidadestestar funcionalidades
Então, por que o “T”?Então, por que o “T”?
Na verdade, o “teste” representa uma Na verdade, o “teste” representa uma expectativaexpectativa, um , um
propósitopropósito que o código deve atender que o código deve atender
O propósito desse método é multiplicar a entarda por 2O propósito desse método é multiplicar a entarda por 2
O propósito dessa classe é se conectar a um SGBDO propósito dessa classe é se conectar a um SGBD
O propósito desse módulo é ser um adaptador de uma O propósito desse módulo é ser um adaptador de uma
API externa para nossaAPI externa para nossa
Etc.Etc.
Sendo assim, é realmente um Sendo assim, é realmente um
“T”?“T”?
Um propósito é o reflexo de uma Um propósito é o reflexo de uma necessidadenecessidade que o código que o código
deve atenderdeve atender
Fazemos escolhas Fazemos escolhas de projetode projeto (design) do código para (design) do código para
atender essa necessidadeatender essa necessidade
É um “teste” na medida em que garante que o projeto do É um “teste” na medida em que garante que o projeto do
nosso código atenda a essa necessidadenosso código atenda a essa necessidade
Portanto, não é sobre “teste”...Portanto, não é sobre “teste”...
...é sobre ...é sobre projetoprojeto!!
Lição número 2Lição número 2
TDD é sobre o TDD é sobre o projetoprojeto, sobre o , sobre o designdesign do código do código
Estamos destacando a palavra Estamos destacando a palavra
errada...errada...
TESTTEST Driven Design Driven Design
Test Driven Test Driven DESIGNDESIGN
Sobre por onde começarSobre por onde começar
Segundo a teoria: de “cima para baixo”Segundo a teoria: de “cima para baixo”
Do ponto de vista do usuárioDo ponto de vista do usuário
Com um “teste de aceitação” que representa uma Com um “teste de aceitação” que representa uma
funcionalidadefuncionalidade
Teste que só passaria com a integração de Teste que só passaria com a integração de todotodo o o
sistemasistema
Ou seja: do HTML à JPA, passando pelo modeloOu seja: do HTML à JPA, passando pelo modelo
Mas e se não der pra ser assim?Mas e se não der pra ser assim?
Começe de onde der pra Começe de onde der pra
começar!!!começar!!!
Lição número 3Lição número 3
Quando em dúvida, começe o TDD de onde você se Quando em dúvida, começe o TDD de onde você se
sentir sentir mais confortávelmais confortável
Começando pelo mais Começando pelo mais
confortávelconfortável
Pelo elemento mais básico do código que resolva o Pelo elemento mais básico do código que resolva o
problema em questãoproblema em questão
A classe mais óbviaA classe mais óbvia
O método mais fácil de se fazerO método mais fácil de se fazer
O módulo com menos dependênciasO módulo com menos dependências
Exemplo prático: cliente Exemplo prático: cliente
WebPagetestWebPagetest
O começo mais óbvio de qualquer código... é ele existir!O começo mais óbvio de qualquer código... é ele existir!
Deve haver um objeto que represente o sistema que Deve haver um objeto que represente o sistema que
queremos construir - o queremos construir - o WPTClientWPTClient
Exemplo prático: cliente Exemplo prático: cliente
WebPagetestWebPagetest
Próximo passo: deve fazer o óbvio!Próximo passo: deve fazer o óbvio!
Nosso objeto deve ser capaz de executar sua Nosso objeto deve ser capaz de executar sua
funcionalidade mais básica.funcionalidade mais básica.
Opa! Opa!
Redundância Redundância
no código do no código do
teste!!teste!!
O segundo teste O segundo teste
claramente “cobre” o claramente “cobre” o
propósito do primeiro - propósito do primeiro -
garantir que exista um garantir que exista um
objeto objeto WPTClientWPTClient..
Portanto...Portanto...
Portanto...Portanto...
Portanto...Portanto...
...elimina-se a redundância!...elimina-se a redundância!
Opa! O código do teste Opa! O código do teste tambémtambém
evoluiu!evoluiu!
Lição número 4Lição número 4
O código do “teste” também “é código” e, portanto, O código do “teste” também “é código” e, portanto,
também evoluitambém evolui
Teste também “é código”!Teste também “é código”!
O código do teste também progride conforme o O código do teste também progride conforme o
aprendizado do código progrideaprendizado do código progride
““É código”, portanto: atenção às boas práticas!É código”, portanto: atenção às boas práticas!
Código limpoCódigo limpo
Eliminar “bad smells”Eliminar “bad smells”
OO “de verdade”OO “de verdade”
WPTClient e evolução do códigoWPTClient e evolução do código
Com o tempo, a classe Com o tempo, a classe WPTClientWPTClient passou a ter muitas passou a ter muitas
responsabilidades:responsabilidades:
ExistirExistir
Iniciar o testeIniciar o teste
Se conectar à camada HTTPSe conectar à camada HTTP
Acessar a URI correta e mandar a requisição correta à API Acessar a URI correta e mandar a requisição correta à API
do WebPagetest...do WebPagetest...
WPTClient: e os métodos WPTClient: e os métodos
“internos”“internos”
Dúvida muito comum: como fazer TDD de métodos Dúvida muito comum: como fazer TDD de métodos
privados? Ou de algoritmos internos a um método privados? Ou de algoritmos internos a um método voidvoid??
Resposta geral: testa-se o Resposta geral: testa-se o estadoestado que o método “interno” que o método “interno”
alteraaltera
Se o resultado do cálculo matemático está corretoSe o resultado do cálculo matemático está correto
Se o HTML está corretamente formatadoSe o HTML está corretamente formatado
Se a lista tem o número de membros esperadoSe a lista tem o número de membros esperado
WPTClient inicia teste numa URLWPTClient inicia teste numa URL
WTPClient deve iniciar um teste numa URL válidaWTPClient deve iniciar um teste numa URL válida
WPTClient não deve iniciar um teste numa URL inválidaWPTClient não deve iniciar um teste numa URL inválida
WPTClient inicia teste numa URLWPTClient inicia teste numa URL
Supondo que estejamos prontos pra criar a implementação Supondo que estejamos prontos pra criar a implementação
“de verdade”, isso implica em:“de verdade”, isso implica em:
Acessar a API HTTP do Groovy “de verdade”Acessar a API HTTP do Groovy “de verdade”
Preparar a chamada à API “de verdade”Preparar a chamada à API “de verdade”
WPTClient inicia teste numa URLWPTClient inicia teste numa URL
Opa! Se conectar à web Opa! Se conectar à web de verdadede verdade??
A API tem um número limitado de chamadas permitidasA API tem um número limitado de chamadas permitidas
Se trata da Se trata da integraçãointegração com uma parte “externa” a essa com uma parte “externa” a essa
“unidade”“unidade”
E se no dia a Internet cair?E se no dia a Internet cair?
E se der errado, como vou saber que é problema do meu E se der errado, como vou saber que é problema do meu
código, e não da infraestrutura de redes?código, e não da infraestrutura de redes?
Evoluindo o código: novas Evoluindo o código: novas
classesclasses
Solução: refatorar o método iniciarTeste() para usar Solução: refatorar o método iniciarTeste() para usar novos novos
objetosobjetos
Transferir essas Transferir essas responsabilidadesresponsabilidades para os devidos objetos para os devidos objetos
Com isso:Com isso:
Testa-se os objetos, e não um método “fechado”Testa-se os objetos, e não um método “fechado”
Elimina-se o Elimina-se o acoplamentoacoplamento da classe WPTClient da classe WPTClient
Fomos disso...Fomos disso...
...para isso......para isso...
...e também ...e também
ganhamos ganhamos
isso!isso!
Lição número 5Lição número 5
TDD é sobre projeto de código TDD é sobre projeto de código evolutivoevolutivo, que cresce e se , que cresce e se
desenvolve como um desenvolve como um organismo vivoorganismo vivo
Código evolutivoCódigo evolutivo
TDD permite TDD permite cultivarcultivar o código, como uma planta que cresce o código, como uma planta que cresce
Seu “DNA” - os requisitos, o Seu “DNA” - os requisitos, o propósitopropósito a qual o código a qual o código
serveserve
Novas classes surgem como novas célulasNovas classes surgem como novas células
Desenvolvimento Desenvolvimento não linearnão linear do código do código
Novas classes surgem conforme a necessidadeNovas classes surgem conforme a necessidade
Novos Novos testestestes surgem conforme a necessidade surgem conforme a necessidade
O O códigocódigo “fala” “fala”
contigo, dizendo contigo, dizendo
pra onde você pra onde você
deve ir!deve ir!
Evolução do código: onde Evolução do código: onde
ocorre?ocorre?
Só pode haver evolução se há testes (propósitos) sendo Só pode haver evolução se há testes (propósitos) sendo
atendidosatendidos
É fruto de atender É fruto de atender melhormelhor a esses propósitos a esses propósitos
Assim, ocorre com a Assim, ocorre com a refatoraçãorefatoração
Portanto, a etapa da refatoração Portanto, a etapa da refatoração não pode ser negligenciadanão pode ser negligenciada!!
Lição número 6Lição número 6
É É impossívelimpossível o código evoluir sem haver a o código evoluir sem haver a refatoraçãorefatoração
Refatoração e evolução do Refatoração e evolução do
códigocódigo
É onde os É onde os padrões de projeto OOpadrões de projeto OO são postos em prática são postos em prática
É onde se identifica a necesidade de se evoluir o códigoÉ onde se identifica a necesidade de se evoluir o código
É onde se É onde se descobredescobre os “ganchos” para isso acontecer os “ganchos” para isso acontecer
Exemplo: motor de videojogoExemplo: motor de videojogo
Classe Classe WalkerGameObjectWalkerGameObject, desenvolvida com TDD, desenvolvida com TDD
Testes passando (VERDE)Testes passando (VERDE)
If...else...if...else...if... OO mandou lembranças...If...else...if...else...if... OO mandou lembranças...
Exemplo: refatorando para Exemplo: refatorando para
padrõespadrões
E por falar em qualidade do E por falar em qualidade do
código...código...
Voltando aos métodos privados...Voltando aos métodos privados...
Métodos privados ou com “algoritmos internos” não são Métodos privados ou com “algoritmos internos” não são
facilmente testáveisfacilmente testáveis
Testando essa classe...Testando essa classe...
Como eu sei se o Produto recebido está ou não nulo?Como eu sei se o Produto recebido está ou não nulo?
Como eu sei que Como eu sei que getNotNullProperties()getNotNullProperties() só retornou só retornou
propriedades não nulas?propriedades não nulas?
Como eu sei se consegui criar direito um Como eu sei se consegui criar direito um
DataSourceConnectionDataSourceConnection??
Como eu sei se o método Como eu sei se o método filter()filter() realmente filtrou? realmente filtrou?
Como eu sei se o método Como eu sei se o método replaceProperties()replaceProperties() funcionou? funcionou?
Epa! E não é só isso!Epa! E não é só isso!
A classe ProductParser...A classe ProductParser...
Tem mais de uma responsabilidadeTem mais de uma responsabilidade
Assegurar que o Porduto não seja nuloAssegurar que o Porduto não seja nulo
Criar e gerenciar uma classe que faz conexão com o Criar e gerenciar uma classe que faz conexão com o
sistema de arquivossistema de arquivos
Gerenciar e alterar as propriedades do ProdutoGerenciar e alterar as propriedades do Produto
Está altissimamente Está altissimamente acopladaacoplada às suas dependências às suas dependências
Ou seja...Ou seja...
É difícil de testar...É difícil de testar...
EE
...é mal escrita...é mal escrita
(alto acoplamento, várias (alto acoplamento, várias
responsabilidades...)responsabilidades...)
(alto acoplamento, várias (alto acoplamento, várias
responsabilidades...)responsabilidades...)
(alto acoplamento, várias (alto acoplamento, várias
responsabilidades...)responsabilidades...)
(alto acoplamento, várias (alto acoplamento, várias
responsabilidades...)responsabilidades...)
...coincidência?...coincidência?
NÃO!!!NÃO!!!
É consequência!É consequência!
O principal problema da “testabilidade” do código é que ele O principal problema da “testabilidade” do código é que ele
é mal projetadoé mal projetado
Segundo Michael Feathers, alto acoplamento é a maior dor Segundo Michael Feathers, alto acoplamento é a maior dor
de cabeça de se lidar com código legadode cabeça de se lidar com código legado
Portanto: código projetado pra “ser testável” é código Portanto: código projetado pra “ser testável” é código bem bem
projetadoprojetado!!
Lição número 7Lição número 7
TDD garante o TDD garante o melhor projetomelhor projeto de código; se um código de código; se um código
não é “testável”, ele está não é “testável”, ele está erradoerrado
TDD e qualidade de códigoTDD e qualidade de código
Não lute contra a dificuldade de se criar um teste!Não lute contra a dificuldade de se criar um teste!
Provavelmente, significa que há uma forma melhor de se Provavelmente, significa que há uma forma melhor de se
projetar o códigoprojetar o código
Exemplo: testar a existência do loop principal de um Exemplo: testar a existência do loop principal de um
videojogovideojogo
WPTClient e qualidade de códigoWPTClient e qualidade de código
Exemplo: trabalhar com o XML de resposta do testeExemplo: trabalhar com o XML de resposta do teste
Possível solução: API de XML do Possível solução: API de XML do
GroovyGroovy
Porém...Porém...
E se essa API não funcionar para o que eu quero?E se essa API não funcionar para o que eu quero?
E se a API mudar no futuro?E se a API mudar no futuro?
E se o XML de resposta mudar no futuro?E se o XML de resposta mudar no futuro?
O código ficara O código ficara acopladoacoplado a essa API! a essa API!
O que diz o TDD mesmo...?O que diz o TDD mesmo...?
Código “real” é Código “real” é sempresempre fruto de se fazer um teste fruto de se fazer um teste escrito escrito
previamentepreviamente passar passar
Portanto...Portanto...
Criemos o teste para haver a classe Resposta!Criemos o teste para haver a classe Resposta!
Ao seguirmos o TDD “à risca”...Ao seguirmos o TDD “à risca”...
Ganhamos a classe RespostaGanhamos a classe Resposta
Desacoplamos nossa implementação das Desacoplamos nossa implementação das duasduas APIs (de APIs (de
XML e do WebPagetest)XML e do WebPagetest)
Garantimos a cobertura de testesGarantimos a cobertura de testes
Tornamos a futura manutenção dessa classe um “passeio Tornamos a futura manutenção dessa classe um “passeio
no parque”no parque”
Lição número 9Lição número 9
TDD é um processo TDD é um processo contínuocontínuo que, pra funcionar, que, pra funcionar, não deve não deve
ser interrompidoser interrompido
Se você para de usar TDD numa Se você para de usar TDD numa
parte do código, o parte do código, o sistema todosistema todo
pode ruir!pode ruir!
Afinal, TDD é sobre Afinal, TDD é sobre DESIGNDESIGN, não , não
sobre testes!sobre testes!
WPTClient e o código WPTClient e o código
“macarrônico”“macarrônico”
Por pura negligência, fiz a parte da linha de comando Por pura negligência, fiz a parte da linha de comando semsem
TDD...TDD...
É a parte mais horrenda do códigoÉ a parte mais horrenda do código
Mantê-la será um pesadelo para a heroina ou o herói que Mantê-la será um pesadelo para a heroina ou o herói que
se habilitar...se habilitar...
Resultado:Resultado:
Erro na hora de imprimir no shell o resultado dos testesErro na hora de imprimir no shell o resultado dos testes
Erro ao salvar o arquivo dos testes no sistema de arquivosErro ao salvar o arquivo dos testes no sistema de arquivos
Gastei Gastei horashoras pra resolver a questão dos parâmetros da linha pra resolver a questão dos parâmetros da linha
de comandode comando
Percebi que li a API errada e tive que refazer umas 60 linhas Percebi que li a API errada e tive que refazer umas 60 linhas
de código!de código!
TDD como processo contínuoTDD como processo contínuo
Ou o código é fruto da Ou o código é fruto da certezacerteza de que ele atende um de que ele atende um
propósito, ou ele é código incertopropósito, ou ele é código incerto
Segundo Michael Feathers: código legado é Segundo Michael Feathers: código legado é todotodo código código
sem teste!sem teste!
Mesmo o código que você Mesmo o código que você acabouacabou de escrever de escrever
Lição número 10Lição número 10
Nunca, Nunca, jamaisjamais subestime a necessidade dos baby steps subestime a necessidade dos baby steps
WPTClient: herança da classe WPTClient: herança da classe
RespostaResposta
Na API do WebPagetest, há um Na API do WebPagetest, há um únicoúnico XML de resposta, XML de resposta,
porém ela pode ser:porém ela pode ser:
De falha ao iniciar o testeDe falha ao iniciar o teste
De teste iniciadoDe teste iniciado
De teste em andamentoDe teste em andamento
De teste concluidoDe teste concluido
O relatório em si do testeO relatório em si do teste
WPTClient: a classe RespostaWPTClient: a classe Resposta
Desenvolvida por TDDDesenvolvida por TDD
Também com o “Também com o “if-else hellif-else hell”...”...
Jogando o TDD pro espaço...Jogando o TDD pro espaço...
Sem seguir o processo de baby steps, criei toda uma Sem seguir o processo de baby steps, criei toda uma
hierarquia de classes “Resposta”hierarquia de classes “Resposta”
Interface “Resposta”Interface “Resposta”
Classe “TesteIniciado”Classe “TesteIniciado”
Classe “TestePendente”Classe “TestePendente”
Etc.Etc.
O sistema O sistema inteirointeiro “quebrou”!! “quebrou”!!
Passinhos de bebê... Passinhos de bebê... jupteriano!jupteriano!
Resultado?Resultado?
Tive que desfazer Tive que desfazer todastodas as alterações as alterações
Tive que garantir que todos os testes continuassem Tive que garantir que todos os testes continuassem
passandopassando
Aprendi a liçãoAprendi a lição
Mas... e a qualidade do código? E Mas... e a qualidade do código? E
as “boas práticas”?as “boas práticas”?
Lição número 11Lição número 11
TDD garante a qualidade TDD garante a qualidade funcionalfuncional do código, e não do código, e não
necessariamente a “estética”necessariamente a “estética”
TDD sem “purismos”TDD sem “purismos”
Código “dentro dos padrões” é Código “dentro dos padrões” é consequênciaconsequência no TDD, não o no TDD, não o
objetivo primordialobjetivo primordial
Padrões de projeto, por si só, não garantem um código Padrões de projeto, por si só, não garantem um código
funcionalfuncional
Se no futuro for necessário, o TDD garante a “beleza” do Se no futuro for necessário, o TDD garante a “beleza” do
código - código - refatoraçãorefatoração
TDD e integraçãoTDD e integração
Como fazer TDD em sistemas com Como fazer TDD em sistemas com
integrações/dependências externas?integrações/dependências externas?
CRUDs com JPACRUDs com JPA
Aplicações webAplicações web
Teste unitário? De integração? De aceitação?Teste unitário? De integração? De aceitação?
TESTTEST Driven Design...? Driven Design...?
Test Driven Test Driven DESIGNDESIGN!!
A “integração” é um A “integração” é um propósito em propósito em
sisi do código! do código!
Lição número 12Lição número 12
Integração de sistemas/módulos em TDD é função do Integração de sistemas/módulos em TDD é função do
projetoprojeto do código, do código, e não do “tipo” de testee não do “tipo” de teste
TDD e integraçãoTDD e integração
A responsabilidade de uma classe é um A responsabilidade de uma classe é um propósitopropósito::
A classe A classe FormatadorDeStringFormatadorDeString formata strings... formata strings...
A classe A classe ProdutoComparatorProdutoComparator compara produtos... compara produtos...
A classe A classe URLValidatorURLValidator valida URLs... valida URLs...
E a integração com um sistema/módulo externo E a integração com um sistema/módulo externo também é também é
um propósitoum propósito!!
WPTClient e integraçãoWPTClient e integração
Exemplo prático de integração: WPTClient e requisições Exemplo prático de integração: WPTClient e requisições
HTTPHTTP
Se conectar “de verdade” à web é um Se conectar “de verdade” à web é um requisitorequisito......
...portanto um ...portanto um propósitopropósito......
...portanto deve ser projetada ...portanto deve ser projetada guiando-se em testesguiando-se em testes..
WPTClient e integraçãoWPTClient e integração
Duas coisas Duas coisas distintasdistintas a se testar: a se testar:
Se a classe WPTClient é capaz de se conectar à camada Se a classe WPTClient é capaz de se conectar à camada
HTTP - a “HTTP - a “unidadeunidade””
Se a integração do nosso sistema com o HTTP funciona Se a integração do nosso sistema com o HTTP funciona
“de verdade” - a ““de verdade” - a “integraçãointegração””
De onde surge essa distinção? De onde surge essa distinção? Dos testesDos testes..
WPTClient e integraçãoWPTClient e integração
Testando a “unidade”, obtivemos isso:Testando a “unidade”, obtivemos isso:
WPTClient e integraçãoWPTClient e integração
Para testar a “unidade”, fizemos isso:Para testar a “unidade”, fizemos isso:
WPTClient e integraçãoWPTClient e integração
E, para testar a “integração”, obtivemos isso:E, para testar a “integração”, obtivemos isso:
E depois dessa experiência?E depois dessa experiência?
Continuo um “mero mortal”...Continuo um “mero mortal”...
Como fazer TDD em código legado?Como fazer TDD em código legado?
TDD em equipe: como evitar “quebrar” o processo?TDD em equipe: como evitar “quebrar” o processo?
TDD “avançado”: threads, computação assíncrona etc.TDD “avançado”: threads, computação assíncrona etc.
TDD vs BDDTDD vs BDD
BibliografiaBibliografia
BECK, Kent. “BECK, Kent. “TDD by ExampleTDD by Example””
FREEMAN, Steve & PRICE, Nat. “FREEMAN, Steve & PRICE, Nat. “Growing OO Software Growing OO Software
Guided by TestsGuided by Tests””
FEATHERS, Michael. “FEATHERS, Michael. “Working Effectively with Legacy CodeWorking Effectively with Legacy Code””
KOSKELA, Lasse. “KOSKELA, Lasse. “Test Driven: TDD and Acceptance TDD for Test Driven: TDD and Acceptance TDD for
Java DevelopersJava Developers””
Obrigado!Obrigado! [email protected]@gmail.com
blog.thiagobaptista.com (fora do ar...)blog.thiagobaptista.com (fora do ar...)
github.com/thiagobaptistagithub.com/thiagobaptista