Buscar

cdc test driven development teste e design no mundo real

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 194 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 194 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 194 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

86964
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
Essa	 talvez	 seja	 a	 seção	 mais	 difícil	 de	 se	 escrever,	 pois	 a
quantidade	de	pessoas	que	participaram	direta	ou	indiretamente	do
livro	é	muito	grande.
Vou	começar	agradecendo	a	meu	pai,	mãe	e	irmão,	que	a	todo
momento	me	apoiaram	na	decisão	de	fazer	um	mestrado,	entender
como	 ciência	 deve	 ser	 feita,	 e	 que	 sofreram	 junto	 comigo	 nos
momentos	de	grande	stress	(que	todo	mestrado	proporciona!).
Agradeço	também	ao	meu	orientador	de	mestrado	e	doutorado,
prof.	 Dr.	Marco	 Aurelio	 Gerosa,	 que	 me	 ensinou	 como	 as	 coisas
funcionam	"do	lado	de	lá".	Sem	ele,	acho	que	este	livro	seria	muito
diferente;	seria	mais	apaixonado,	porém	menos	verdadeiro.	Se	meu
texto	olha	para	o	TDD	de	uma	maneira	 fria	e	 imparcial,	 a	culpa	é
dele.
Os	srs.	Paulo	Silveira	e	Adriano	Almeida	também	merecem	uma
lembrança.	Mesmo	na	época	em	que	a	Casa	do	Código	não	existia
de	fato,	eles	 já	haviam	aceitado	a	 ideia	do	livro	de	TDD.	Obrigado
pela	confiança.
Todas	as	pessoas	das	últimas	empresas	em	que	atuei	também	me
ajudaram	muito	com	as	 incontáveis	conversas	de	corredor	sobre	o
assunto.	Isso	com	certeza	enriqueceu	muito	o	texto.
Agradeço	 também	 aos	 amigos	 José	 Donizetti,	 Guilherme
Moreira	 e	Rafael	Ferreira,	que	gastaram	 tempo	 lendo	o	 livro	e	me
dando	sugestões	de	como	melhorar.
Por	fim,	obrigado	a	você	que	está	lendo	este	livro.	Espero	que	ele
ajude.
AGRADECIMENTOS
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
Impresso	e	PDF:	978-85-66250-04-6	EPUB:	978-85-66250-73-2
Você	 pode	 discutir	 sobre	 este	 livro	 no	 Fórum	 da	 Casa	 do
Código:	http://forum.casadocodigo.com.br/.
Caso	 você	 deseje	 submeter	 alguma	 errata	 ou	 sugestão,	 acesse
http://erratas.casadocodigo.com.br.
ISBN
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
Meu	nome	é	Mauricio	Aniche,	e	trabalho	com	desenvolvimento
de	 software	 há	 10	 anos.	 Em	 boa	 parte	 desse	 tempo,	 atuei	 como
consultor	 para	 diferentes	 empresas	 do	 mercado	 brasileiro	 e
internacional.	Com	certeza,	as	 linguagens	mais	utilizadas	por	mim
ao	longo	da	minha	carreira	foram	Java,	C#	e	C.
Como	sempre	pulei	de	projeto	em	projeto	(e,	por	consequência,
de	tecnologia	em	tecnologia),	nunca	fui	a	fundo	em	nenhuma	delas.
Pelo	contrário,	sempre	foquei	em	entender	princípios	que	pudessem
ser	levados	de	uma	para	outra,	para	que	no	fim,	o	código	saísse	com
qualidade,	independente	da	tecnologia.
Em	 meu	 último	 ano	 da	 graduação,	 2007,	 comecei	 a	 ler	 mais
sobre	 a	 ideia	 de	 testes	 automatizados	 e	 TDD.	 Achei	 muito
interessante	e	útil	a	ideia	de	se	escrever	um	programa	para	testar	seu
programa.	 Então,	 decidi	 praticar	 TDD	 por	 conta	 própria,	 para
entender	melhor	como	ela	funcionava.
Gostei	 muito	 do	 que	 vi.	 De	 2007	 em	 diante,	 resolvi	 praticar,
pesquisar	e	divulgar	melhor	minhas	ideias	sobre	o	assunto.	Comecei
devagar,	 apenas	blogando	o	que	estava	na	minha	cabeça	 e	 sobre	o
que	gostaria	de	feedback	de	outros	desenvolvedores.	Mas	para	fazer
isso	 de	 maneira	 mais	 decente,	 resolvi	 ingressar	 no	 programa	 de
Mestrado	 da	 Universidade	 de	 São	 Paulo.	 Lá,	 pesquisei	 sobre	 os
efeitos	da	prática	de	TDD	no	design	de	classes.
Ao	longo	desse	tempo,	participei	da	grande	maioria	dos	eventos
relacionados	 ao	 assunto.	 Palestrei	 nos	 principais	 eventos	 de
métodos	 ágeis	 do	 país	 (como	 Agile	 Brazil,	 Encontro	 Ágil),	 de
desenvolvimento	 de	 software	 (QCON	 SP	 e	 DNAD),	 entre	 outros
menores.	 Cheguei	 a	 participar	 de	 eventos	 internacionais	 também;
QUEM	SOU	EU?
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
fui	 o	 único	 palestrante	 brasileiro	 no	 Primeiro	 Workshop
Internacional	sobre	TDD,	em	2010,	na	cidade	de	Paris.
Isso	 mostra	 também	 que	 tenho	 participado	 dos	 eventos
acadêmicos.	Em	2011,	apresentei	um	estudo	sobre	TDD	no	WBMA
(Workshop	 Brasileiro	 de	 Métodos	 Ágeis),	 e	 em	 2012,	 no	 maior
simpósio	brasileiro	sobre	engenharia	de	software,	o	SBES.
Atualmente	 trabalho	pela	Caelum,	 como	 consultor	 e	 instrutor.
Também	sou	aluno	de	doutorado	pela	Universidade	de	São	Paulo,
onde	continuo	a	pesquisar	 sobre	a	 relação	dos	 testes	de	unidade	e
qualidade	do	código.
Portanto,	 esse	 é	 meu	 relacionamento	 com	 TDD.	 Nos	 últimos
anos.	 tenho	 olhado-o	 de	 todos	 os	 pontos	 de	 vista	 possíveis:	 de
praticante,	 de	 acadêmico,	 de	 pesquisador,	 de	 apaixonado,	 de	 frio.
Este	livro	é	o	relato	de	tudo	que	aprendi	nesses	últimos	anos.
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
Já	 faz	 15	 anos	 desde	 que	 Test-Driven	 Development	 (TDD)
evoluiu	 para	 algo	 que	 é	 considerado	 uma	 prática	 útil	 pela
comunidade	 de	 software.	 Originalmente,	 TDD	 evoluiu	 da
Programação	Extrema	(XP),	discutida	por	Kent	Beck	e	outros	antes
mesmo	do	Manifesto	Ágil.
Seu	 foco	 primordial	 era	 guiar	 o	 desenvolvimento	 de	 software
fazendo	o	desenvolvedor	realmente	pensar	sobre	como	ele	validaria
que	 o	 software	 estava	 implementado	 corretamente	 antes	 de	 se
escrever	 o	 código	 daquele	 sistema.	 O	 caminho	 é	 longo	 para	 ser
proficiente	 em	TDD.	Desenvolver	 baterias	 de	 teste	 automatizadas,
refatoração,	 retrabalhar	nos	 tests	 para	 eliminar	duplicação	 e	 testar
condições	excepcionais	são	algumas	delas.
Eu	 conheço	 o	 autor	 (Maurício)	 há	muitos	 anos.	Maurício	 tem
grande	 experiência	 em	 padrões,	 projeto	 de	 sistemas	 orientados	 a
objetos,	Java	e	TDD.	Eu	colaborei	e	trabalhei	com	ele	em	projetos	e
artigos	 de	 sistemas	 orientados	 a	 objetos	 e,	 mais	 específicamente,
sobre	TDD.
Maurício	 tem	 muita	 experiência	 no	 desenvolvimento	 de
sistemas	reais	usando	os	princípios	de	TDD.	Maurício	tem	mais	do
que	 somente	 o	 entendimento	 do	 "como"	 implementar	 uma	 nova
funcionalidade	 usando	TDD.	 Ele	 entende	 claramente	 os	 trade-offs
de	 um	 bom	 design	 orientado	 a	 objetos,	 quando	 e	 onde	 aplicar
padrões	para	se	ter	um	design	mais	limpo,	reusável	e	fácil	de	mudar.
Qualquer	 desenvolvedor	 que	 queira	 se	 tornar	 proficiente	 em
TDD	 não	 precisará	 apenas	 entender	 os	 princípios	 básicos	 de	 se
escrever	 um	 teste	 de	 unidade.	 Ele	 precisará	 também	 conhecer
princípios	 mais	 avançados,	 como	 refatoração,	 como	 manter	 seus
PREFÁCIO
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
testes	limpos,	TDD	e	como	ele	se	relaciona	com	projeto	de	classes,
minimizando	acoplamento	etc.
Este	livro	é	mais	do	que	apenas	um	livro	de	receitas	sobre	como
praticar	TDD.	Ele	discute	todos	os	principais	detalhes	de	TDD.
Joseph	W.	Yoder
The	Refactory,	Inc.	—	2015
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
TDD	 é	 uma	 das	 práticas	 de	 desenvolvimento	 de	 software
sugeridas	por	diversas	metodologias	ágeis,	como	XP.	A	ideia	é	fazer
com	que	o	desenvolvedor	escreva	testes	automatizados	de	maneira
constante	 ao	 longo	 do	 desenvolvimento.	 Mas,	 diferentemente	 do
que	estamos	acostumados,	TDD	sugere	que	o	desenvolvedor	escreva
o	teste	antes	mesmo	da	implementação.
Essa	 simples	 inversão	 no	 ciclo	 traz	 diversos	 benefícios	 para	 o
projeto.	 Baterias	 de	 testes	 tendem	 a	 ser	 maiores,	 cobrindo	 mais
casos,	 e	 garantindo	 uma	 maior	 qualidade	 externa.	 Além	 disso,
escrever	 testes	 de	 unidade	 forçará	 o	 desenvolvedor	 a	 escrever	 um
código	de	melhor	qualidade	pois,	como	veremos	ao	longo	do	livro,
para	escrever	bons	testes	de	unidade,	o	desenvolvedor	é	obrigado	a
fazer	bom	uso	de	orientação	a	objetos.
A	prática	 nos	 ajuda	 a	 escrever	 um	 software	melhor,	 com	mais
qualidade,	 e	 um	 código	 melhor,	 mais	 fácil	 de	 ser	 mantido	 e
evoluído.	 Esses	 dois	 pontos	 são	 importantíssimosem	 qualquer
software,	e	TDD	nos	ajuda	a	alcançá-los.	Toda	prática	que	ajuda	a
aumentar	a	qualidade	do	software	produzido	deve	ser	estudada.
Neste	livro,	tentei	colocar	toda	a	experiência	e	tudo	que	aprendi
ao	 longo	 desses	 últimos	 anos	 praticando	 e	 pesquisando	 sobre	 o
assunto.	Mostrei	 também	 o	 outro	 lado	 da	 prática,	 seus	 efeitos	 no
design	 de	 classes,	 que	 é	 muito	 falada	 mas	 pouco	 discutida	 e
explicada.
A	 prática	 de	 TDD,	 quando	 bem	 usada,	 pode	 ser	 bastante
produtiva.	Mas,	como	verá	ao	longo	do	livro,	os	praticantes	devem
estar	 sempre	 alertas	 às	 dicas	 que	 o	 teste	 dará	 sobre	 nosso	 código.
Aqui,	passaremos	por	eles	e	o	leitor	ao	final	do	livro	terá	em	mãos
RESUMO
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
uma	nova	e	excelente	ferramenta	de	desenvolvimento.
Este	livro	é	destinado	a	desenvolvedores	que	querem	aprender	a
escrever	 testes	de	maneira	eficiente,	e	que	desejam	melhorar	ainda
mais	o	código	que	produzem.	Aqui	utilizamos	Java	para	demonstrar
os	 conceitos	 discutidos,	 mas	 você	 pode	 facilmente	 levar	 as
discussões	feitas	aqui	para	a	sua	linguagem	de	programação	favorita.
Mesmo	 que	 você	 já	 pratique	 TDD,	 tenho	 certeza	 de	 que
encontrará	 discussões	 interessantes	 sobre	 como	 a	 prática	 dá
feedback	 sobre	 problemas	 de	 acoplamento	 e	 coesão,	 bem	 como
técnicas	 para	 escrever	 testes	 melhores	 e	 mais	 fáceis	 de	 serem
mantidos.
Testadores	também	podem	se	beneficiar	deste	livro,	entendendo
como	 escrever	 códigos	 de	 teste	 de	 qualidade,	 quando	ou	não	usar
TDD,	 e	 como	 reportar	 problemas	 de	 código	 para	 os
desenvolvedores.
Ao	 longo	 do	 livro,	 trabalhamos	 em	 diversos	 exemplos,	 muito
similares	 ao	mundo	 real.	 Todo	 capítulo	 possui	 sua	 parte	 prática	 e
parte	 teórica.	Na	parte	prática,	muito	código	de	 teste	é	escrito.	Na
parte	teórica,	refletimos	sobre	o	código	que	produzimos	até	aquele
momento,	 o	 que	 foi	 feito	 de	 bom,	 o	 que	 foi	 feito	 de	 ruim,	 e
melhoramos	de	acordo.
O	leitor	pode	refazer	todos	os	códigos	produzidos	nos	capítulos.
Praticar	TDD	é	essencial	para	que	as	 ideias	 fiquem	naturais.	Além
disso,	a	Caelum	também	disponibiliza	um	curso	online	sobre	testes
automatizados	 (http://www.caelum.com.br/curso/online/testes-
automatizados),	que	pode	ser	usado	como	complemento	deste	livro.
A	quem	se	destina	este	livro?
Como	devo	estudar?
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
Boa	leitura!
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
1
1
2
3
3
5
7
7
8
10
17
19
20
20
21
28
29
32
34
Sumário
1	Introdução
1.1	Era	uma	vez	um	projeto	sem	testes...
1.2	Por	que	devemos	testar?
1.3	Por	que	não	testamos?
1.4	Testes	automatizados	e	TDD
1.5	Conclusão
2	Testes	de	unidade
2.1	O	que	é	um	teste	de	unidade?
2.2	Preciso	mesmo	escrevê-los?
2.3	O	primeiro	teste	de	unidade
2.4	Continuando	a	testar
2.5	Conclusão
3	Introdução	ao	Test-Driven	Development
3.1	O	problema	dos	números	romanos
3.2	O	primeiro	teste
3.3	Refletindo	sobre	o	assunto
3.4	Quais	as	vantagens?
3.5	Um	pouco	da	história	de	TDD
3.6	Conclusão
SumárioCasa	do	Código
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
36
36
38
40
47
51
53
53
58
60
62
63
65
66
69
71
73
76
79
81
82
83
83
87
90
91
95
97
4	Simplicidade	e	Baby	Steps
4.1	O	problema	do	cálculo	de	salário
4.2	Implementando	da	maneira	mais	simples	possível
4.3	Passos	de	bebê	(ou	baby	steps)
4.4	Usando	baby	steps	de	maneira	consciente
4.5	Conclusão
5	TDD	e	design	de	classes
5.1	O	problema	do	carrinho	de	compras
5.2	Testes	que	influenciam	no	design	de	classes
5.3	Diferenças	entre	TDD	e	testes	da	maneira	tradicional
5.4	Testes	como	rascunho
5.5	Conclusão
6	Qualidade	no	código	do	teste
6.1	Repetição	de	código	entre	testes
6.2	Nomenclatura	dos	testes
6.3	Test	Data	Builders
6.4	Testes	repetidos
6.5	Escrevendo	boas	asserções
6.6	Testando	listas
6.7	Separando	as	classes	de	teste
6.8	Conclusão
7	TDD	e	a	coesão
7.1	Novamente	o	problema	do	cálculo	de	salário
7.2	Ouvindo	o	feedback	dos	testes
7.3	Testes	em	métodos	privados?
7.4	Resolvendo	o	problema	da	calculadora	de	salário
7.5	O	que	olhar	no	teste	em	relação	a	coesão?
7.6	Conclusão
Casa	do	CódigoSumário
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
98
98
102
106
107
108
112
115
117
120
121
123
123
129
130
132
133
134
135
135
137
140
145
146
149
150
150
152
8	TDD	e	o	acoplamento
8.1	O	problema	da	nota	fiscal
8.2	Mock	objects
8.3	Dependências	explícitas
8.4	Ouvindo	o	feedback	dos	testes
8.5	Classes	estáveis
8.6	Resolvendo	o	problema	da	nota	fiscal
8.7	Testando	métodos	estáticos
8.8	TDD	e	a	constante	criação	de	interfaces
8.9	O	que	olhar	no	teste	em	relação	ao	acoplamento?
8.10	Conclusão
9	TDD	e	o	encapsulamento
9.1	O	problema	do	processador	de	boleto
9.2	Ouvindo	o	feedback	dos	testes
9.3	Tell,	Don't	Ask	e	Lei	de	Demeter
9.4	Resolvendo	o	problema	do	processador	de	boletos
9.5	O	que	olhar	no	teste	em	relação	ao	encapsulamento?
9.6	Conclusão
10	Testes	de	integração	e	TDD
10.1	Testes	de	unidade,	integração	e	sistema
10.2	Quando	não	usar	mocks?
10.3	Testes	em	DAOs
10.4	Devo	usar	TDD	em	testes	de	integração?
10.5	Testes	em	aplicações	Web
10.6	Conclusão
11	Quando	não	usar	TDD?
11.1	Quando	não	praticar	TDD?
11.2	100%	de	cobertura	de	código?
SumárioCasa	do	Código
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
154
155
156
159
160
162
162
163
164
164
166
166
170
175
176
11.3	Devo	testar	códigos	simples?
11.4	Erros	comuns	durante	a	prática	de	TDD
11.5	Como	convencer	seu	chefe	sobre	TDD?
11.6	TDD	em	sistemas	legados
11.7	Conclusão
12	E	agora?
12.1	Como	aprender	mais	agora?
12.2	Dificuldade	no	aprendizado
12.3	Como	interagir	com	outros	praticantes?
12.4	Conclusão	final
13	Apêndice:	princípios	SOLID
13.1	Sintomas	de	projetos	de	classes	em	degradação
13.2	Princípios	de	projeto	de	classes
13.3	Conclusão
14	Bibliografia
Versão:	20.0.27
Casa	do	CódigoSumário
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
CAPÍTULO	1
Será	que	testar	software	é	realmente	importante?	Neste	capítulo,
discutimos	 um	 pouco	 sobre	 as	 consequências	 de	 software	 não
testado	e	uma	possível	 solução	para	 isso,	que	hoje	 é	um	problema
para	a	sociedade	como	um	todo,	já	que	softwares	estão	em	todos	os
lugares.
Durante	os	anos	de	2005	e	2006,	 trabalhei	em	um	projeto	cujo
objetivo	 era	 automatizar	 todo	o	processo	de	postos	de	gasolina.	O
sistema	deveria	tomar	conta	de	todo	o	fluxo:	desde	a	comunicação
com	as	bombas	de	gasolina,	 liberando	ou	não	o	abastecimento,	até
relatórios	 de	 fluxo	 de	 caixa	 e	 quantidade	 de	 combustível	 vendido
por	dia	ou	por	bomba.
A	 aplicação	 era	 desenvolvida	 inteira	 em	C	 e	 deveria	 rodar	 em
um	microdispositivo	de	200Mhz	de	processamento	e	2MB	de	RAM.
Nós	 éramos	 em	 4	 desenvolvedores,	 e	 todos	 programavam	 e
testavam	ao	mesmo	tempo.
Os	 testes	 não	 eram	 tão	 simples	 de	 serem	 feitos,	 afinal,
precisávamos	 simular	 bombas	 de	 gasolinas,	 abastecimentos
simultâneos	etc.	Mas,	mesmo	assim,	nos	revezávamos	e	testávamos
da	forma	que	conseguíamos.
Após	 alguns	 meses	 de	 desenvolvimento,	 encontramos	 o
INTRODUÇÃO
1.1	ERA	UMA	VEZ	UM	PROJETO	SEM	TESTES...
1	INTRODUÇÃO	 1
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
primeiro	 posto	 disposto	 a	 participar	 do	 piloto	 da	 aplicação.	 Esse
posto	ficava	em	Santo	Domingo,	capital	da	República	Dominicana.
Eu,	na	época	líder	técnico	dessa	equipe,	viajei	para	o	lugar	com	o
objetivo	de	acompanhar	nosso	produto	rodando	pela	primeira	vez.
Fizemos	 a	 instalaçãodo	 produto	 pela	 manhã	 e	 acompanhamos
nosso	 "bebê"	 rodando	 por	 todo	 o	 dia.	 Funcionou	 perfeitamente.
Saímos	de	lá	e	fomos	jantar	em	um	dos	melhores	lugares	da	cidade
para	comemorar.
Missão	cumprida.
Voltando	do	jantar,	fui	direto	para	cama,	afinal,	no	dia	seguinte
entenderíamos	quais	seriam	as	próximas	etapas	do	produto.	Mas	às
7h	 da	 manhã,	 o	 telefone	 tocou.	 Era	 o	 responsável	 pelo	 posto	 de
gasolina	piloto.	Ele	me	ligou	justamente	para	contar	que	o	posto	de
gasolina	 estava	 completamente	 parado	 desde	 as	 0h:	 o	 software
parou	de	funcionar	e	bloqueou	completamente	o	posto	de	gasolina.
Nosso	 software	nunca	havia	 sido	 testado	com	uma	quantidade
grande	 de	 abastecimentos.	 Os	 postos	 em	 Santo	 Domingo	 fazem
muitos	pequenos	abastecimentos	ao	 longo	do	dia	 (diferente	daqui,
onde	enchemos	o	tanque	de	uma	vez).	O	sistema	não	entendeu	isso
muito	bem,	e	optou	por	bloquear	as	bombas	de	gasolina,	para	evitar
fraude,	já	que	não	conseguia	registrar	as	futuras	compras.
O	 software	 fez	 com	 que	 o	 estabelecimento	 ficasse	 12	 horas
parado,	sem	vender	nada.	Quanto	será	que	isso	custou	ao	dono	do
estabelecimento?	Como	será	que	foi	a	reação	dele	ao	descobrir	que	o
novo	produto,	no	primeiro	dia,	causou	tamanho	estrago?
Os	Estados	Unidos	 estimam	que	bugs	de	 software	 lhes	 custam
aproximadamente	 60	 bilhões	 de	 dólares	 por	 ano	 (THIBODEAU,
1.2	POR	QUE	DEVEMOS	TESTAR?
2	 1.2	POR	QUE	DEVEMOS	TESTAR?
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
2012).	O	 dinheiro	 que	 poderia	 estar	 sendo	 usado	 para	 erradicar	 a
fome	do	planeta	está	sendo	gasto	em	correções	de	software	que	não
funcionam.
É	incrível	a	quantidade	de	software	que	não	funciona.	Pergunte
ao	 seu	 amigo	 não-técnico	 se	 ele	 já	 ficou	 irritado	 porque	 algum
programa	do	seu	dia	a	dia	simplesmente	parou	de	funcionar.	Alguns
bugs	de	software	são	inclusive	famosos	por	todos:	o	foguete	Ariane
5	explodiu	por	um	erro	de	software;	um	hospital	panamenho	matou
pacientes	pois	seu	software	para	dosagem	de	remédios	errou.
Não	há	um	desenvolvedor	que	não	 saiba	que	 a	 solução	para	o
problema	 é	 testar	 seus	 códigos.	 A	 pergunta	 é:	 por	 que	 não
testamos?
Não	testamos,	porque	testar	sai	caro.	Imagine	o	sistema	em	que
você	trabalha	hoje.	Se	uma	pessoa	precisasse	testá-lo	do	começo	ao
fim,	quanto	 tempo	ela	 levaria?	Semanas?	Meses?	Pagar	um	mês	de
uma	 pessoa	 a	 cada	 mudança	 feita	 no	 código	 (sim,	 os
desenvolvedores	 também	sabem	que	uma	mudança	 em	um	 trecho
pode	gerar	problemas	em	outro)	é	simplesmente	impossível.
Testar	 sai	 caro,	 no	 fim,	 porque	 estamos	 pagando	 "a	 pessoa"
errada	para	fazer	o	trabalho.	Acho	muito	interessante	a	quantidade
de	tempo	que	gastamos	criando	soluções	tecnológicas	para	resolver
problemas	 "dos	 outros".	 Por	 que	 não	 escrevemos	 programas	 que
resolvam	também	os	nossos	problemas?
Uma	maneira	para	conseguir	 testar	o	 sistema	 todo	de	maneira
constante	 e	 contínua	 a	 um	 preço	 justo	 é	 automatizando	 os	 testes.
1.3	POR	QUE	NÃO	TESTAMOS?
1.4	TESTES	AUTOMATIZADOS	E	TDD
1.3	POR	QUE	NÃO	TESTAMOS?	 3
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
Ou	 seja,	 escrevendo	um	programa	que	 testa	 o	 seu	 programa.	 Esse
programa	invocaria	os	comportamentos	do	seu	sistema	e	garantiria
que	a	saída	é	sempre	a	esperada.
Se	 isso	 fosse	 realmente	 viável,	 teríamos	 diversas	 vantagens.	 O
teste	 executaria	 muito	 rápido	 (afinal,	 é	 uma	 máquina!).	 Se	 ele
executa	rápido,	logo	o	rodaríamos	constantemente.	Se	os	rodarmos
o	tempo	todo,	descobriríamos	os	problemas	mais	cedo,	diminuindo
o	custo	que	o	bug	geraria.
Um	ponto	que	é	sempre	levantado	em	qualquer	discussão	sobre
testes	 manuais	 versus	 testes	 automatizados	 é	 produtividade.	 O
argumento	 mais	 comum	 é	 o	 de	 que	 agora	 a	 equipe	 de
desenvolvimento	 gastará	 tempo	 escrevendo	 código	 de	 teste;	 antes
ela	só	gastava	tempo	escrevendo	código	de	produção.	Portanto,	essa
equipe	será	menos	produtiva.
A	 resposta	 para	 essa	 pergunta	 é:	 o	 que	 é	 produtividade?	 Se
produtividade	for	medida	através	do	número	de	linhas	de	código	de
produção	 escritos	 por	 dia,	 talvez	 o	 desenvolvedor	 seja	 sim	menos
produtivo.	 Agora,	 se	 produtividade	 for	 a	 quantidade	 de	 linhas	 de
código	de	produção	sem	defeitos	escritos	por	dia,	provavelmente	o
desenvolvedor	será	mais	produtivo	ao	usar	testes	automatizados.
Além	disso,	se	analisarmos	o	dia	a	dia	de	um	desenvolvedor	que
faz	 testes	manuais,	 podemos	 perceber	 a	 quantidade	 de	 tempo	 que
ele	 gasta	 com	 teste.	 Geralmente,	 ele	 executa	 testes	 enquanto
desenvolve	 o	 algoritmo	 completo.	 Ele	 escreve	 um	 pouco,	 roda	 o
programa,	 e	 o	 programa	 falha.	 Nesse	 momento,	 o	 desenvolvedor
entende	o	problema,	corrige-o,	e	em	seguida	executa	novamente	o
mesmo	teste.
Quantas	 vezes	 por	 dia	 ele	 executa	 o	 mesmo	 teste	 manual?	 O
desenvolvedor	que	automatiza	seus	testes	perde	tempo	apenas	1	vez
com	 ele;	 nas	 próximas,	 ele	 simplesmente	 aperta	 um	 botão	 e	 vê	 a
4	 1.4	TESTES	AUTOMATIZADOS	E	TDD
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
máquina	executando	o	teste	pra	ele,	de	forma	correta	e	rápida.
Minha	 família	 inteira	 é	 da	 área	médica.	 Um	 jantar	 de	 fim	 de
semana	 em	 casa	 parece	 mais	 um	 daqueles	 episódios	 de	 seriados
médicos	da	 televisão:	 pessoas	discutindo	 casos	 e	 como	 resolvê-los.
Apesar	 de	 entender	 praticamente	 nada	 sobre	medicina,	 uma	 coisa
me	chama	muito	a	atenção:	o	fanatismo	deles	por	qualidade.
Um	 médico,	 ao	 longo	 de	 uma	 cirurgia,	 nunca	 abre	 mão	 de
qualidade.	 Se	 o	 paciente	 falar	 para	 ele:	 "Doutor,	 o	 senhor	 poderia
não	lavar	a	mão	e	terminar	a	cirurgia	15	minutos	mais	cedo?",	tenho
certeza	de	que	o	médico	negaria	na	hora.	Ele	saberia	que	chegaria	ao
resultado	 final	 mais	 rápido,	 mas	 a	 chance	 de	 um	 problema	 é	 tão
grande,	que	simplesmente	não	valeria	a	pena.
Em	nossa	área,	vejo	justamente	o	contrário.	Qual	desenvolvedor
nunca	escreveu	um	código	de	má	qualidade	de	maneira	consciente?
Quem	 nunca	 escreveu	 uma	 "gambiarra"?	 Quem	 nunca	 colocou
software	 em	produção	 sem	executar	 o	mínimo	 suficiente	de	 testes
para	tal?
Não	há	desculpas	para	não	testar	software.	E	a	solução	para	que
seus	 testes	 sejam	 sustentáveis	 é	 automatizando.	Testar	 é	 divertido,
aumenta	 a	 qualidade	 do	 seu	 produto,	 e	 pode	 ainda	 ajudá-lo	 a
identificar	 trechos	de	código	que	 foram	mal	escritos	ou	projetados
(aqui	entra	a	prática	de	TDD).	É	muita	vantagem.
Ao	 longo	 do	 livro,	 espero	 convencê-lo	 de	 que	 testar	 é
importante,	e	que	na	verdade	é	mais	fácil	do	que	parece.
Para	 facilitar	 a	 comunicação	 entre	 os	 leitores	 deste	 livro	 e
1.5	CONCLUSÃO
Como	tirar	dúvidas?
1.5	CONCLUSÃO	 5
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
interessados	 no	 assunto,	 existe	 o	 fórum	 da	 Casa	 do	 Código,	 em
http://forum.casadocodigo.com.br/.	 Toda	 e	 qualquer	 discussão,
dúvida	ou	sugestão	será	bem-vinda.
Não	se	esqueça	também	de	participar	do	GUJ,	o	maior	portal	de
desenvolvedores	 do	 Brasil:	 http://www.guj.com.br/.	 Lá	 você	 pode
perguntar,	responder,	editar	e	dar	pontos	às	dúvidas	e	respostas	de
outros	desenvolvedores.
Caso	 você	 deseje	 submeter	 alguma	 errata	 ou	 sugestão,	 acesse
http://erratas.casadocodigo.com.br
6	 1.5	CONCLUSÃO
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
CAPÍTULO	2
Imagine-se	passeando	em	uma	loja	virtual	qualquer	na	web.	Ao
selecionar	 um	 produto,	 o	 sistema	 coloca-o	 no	 seu	 carrinho	 de
compras.	Ao	finalizar	a	compra,	o	sistema	fala	com	a	operadora	de
cartão	 de	 crédito,	 retira	 o	 produto	do	 estoque,	 dispara	 um	 evento
para	que	a	equipe	de	 logística	separeos	produtos	comprados	e	 lhe
envia	um	e-mail	confirmando	a	compra.
O	software	que	toma	conta	de	tudo	isso	é	complexo.	Ele	contém
regras	 de	 negócio	 relacionadas	 ao	 carrinho	 de	 compras,	 ao
pagamento,	ao	fechamento	da	compra.	Mas,	muito	provavelmente,
todo	 esse	 código	 não	 está	 implementado	 em	 apenas	 um	 único
arquivo;	 esse	 sistema	 é	 composto	 por	 diversas	 pequenas	 classes,
cada	uma	com	sua	tarefa	específica.
Desenvolvedores,	 quando	 pensam	 em	 teste	 de	 software,
geralmente	imaginam	um	teste	que	cobre	o	sistema	como	um	todo.
Um	teste	de	unidade	não	se	preocupa	com	todo	o	sistema;	ele	está
interessado	 apenas	 em	 saber	 se	 uma	 pequena	 parte	 do	 sistema
funciona.
Um	teste	de	unidade	testa	uma	única	unidade	do	nosso	sistema.
Geralmente,	 em	 sistemas	 orientados	 a	 objetos,	 essa	 unidade	 é	 a
classe.	Em	nosso	sistema	de	exemplo,	muito	provavelmente	existem
classes	como	"CarrinhoDeCompras",	"Pedido",	e	assim	por	diante.	A
TESTES	DE	UNIDADE
2.1	O	QUE	É	UM	TESTE	DE	UNIDADE?
2	TESTES	DE	UNIDADE	 7
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
ideia	 é	 termos	 baterias	 de	 testes	 de	 unidade	 separadas	 para	 cada
uma	 dessas	 classes;	 cada	 bateria	 preocupada	 apenas	 com	 a	 sua
classe.
Essa	 mesma	 loja	 virtual	 precisa	 encontrar,	 dentro	 do	 seu
carrinho	 de	 compras,	 os	 produtos	 de	 maior	 e	 menor	 valor.	 Um
possível	 algoritmo	 para	 esse	 problema	 seria	 percorrer	 a	 lista	 de
produtos	 no	 carrinho,	 comparar	 um	 a	 um,	 e	 guardar	 sempre	 a
referência	para	o	menor	e	o	maior	produto	encontrado	até	então.
Em	código,	uma	possível	implementação	seria:
public	class	MaiorEMenor	{
				private	Produto	menor;
				private	Produto	maior;
				public	void	encontra(CarrinhoDeCompras	carrinho)	{
								for(Produto	produto	:	carrinho.getProdutos())	{
												if(menor	==	null	||
																produto.getValor()	<	menor.getValor())	{
																menor	=	produto;
												}
												else	if	(maior	==	null	||	
																				produto.getValor()	>	maior.getValor())	{
																maior	=	produto;
												}
								}
				}
				public	Produto	getMenor()	{
								return	menor;
				}
				public	Produto	getMaior()	{
								return	maior;
				}
}
Veja	 o	 método	 	 encontra()	 .	 Ele	 recebe	 um
2.2	PRECISO	MESMO	ESCREVÊ-LOS?
8	 2.2	PRECISO	MESMO	ESCREVÊ-LOS?
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
	CarrinhoDeCompras		 e	 percorre	 a	 lista	 de	produtos,	 comparando
sempre	 o	 produto	 corrente	 com	 o	 "menor	 e	maior	 de	 todos".	 Ao
final,	temos	no	atributo		maior		e		menor		os	produtos	desejados.	A
figura	a	seguir	mostra	como	o	algoritmo	funciona:
Para	exemplificar	o	uso	dessa	classe,	veja	o	seguinte	código:
public	class	TestaMaiorEMenor	{
				public	static	void	main(String[]	args)	{
								CarrinhoDeCompras	carrinho	=	new	CarrinhoDeCompras();
								carrinho.adiciona(new	Produto("Liquidificador",	250.0));
								carrinho.adiciona(new	Produto("Geladeira",	450.0));
								carrinho.adiciona(new	Produto("Jogo	de	pratos",	70.0));
								MaiorEMenor	algoritmo	=	new	MaiorEMenor();
								algoritmo.encontra(carrinho);
								System.out.println("O	menor	produto:	"	+	
												algoritmo.getMenor().getNome());
								System.out.println("O	maior	produto:	"	+	
												algoritmo.getMaior().getNome());
				}
}
O	carrinho	contém	três	produtos:	liquidificador,	geladeira	e	jogo
2.2	PRECISO	MESMO	ESCREVÊ-LOS?	 9
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
de	pratos.	 É	 fácil	 perceber	 que	 o	 jogo	de	 pratos	 é	 o	 produto	mais
barato	 (R$	 70,00),	 enquanto	 que	 a	 geladeira	 é	 o	 mais	 caro	 (R$
450,00).	A	saída	do	programa	é	exatamente	igual	à	esperada:
O	menor	produto:	Jogo	de	pratos
O	maior	produto:	Geladeira
Apesar	 de	 aparentemente	 funcionar,	 se	 esse	 código	 for	 para
produção,	a	loja	virtual	terá	problemas.
A	 classe	 	 MaiorEMenor	 	 respondeu	 corretamente	 ao	 teste
anterior,	mas	 ainda	não	 é	possível	dizer	 se	 ela	 realmente	 funciona
para	outros	cenários.	Observe	o	código	a	seguir:
public	class	TestaMaiorEMenor	{
				public	static	void	main(String[]	args)	{
								CarrinhoDeCompras	carrinho	=	new	CarrinhoDeCompras();
								carrinho.adiciona(new	Produto("Geladeira",	450.0));
								carrinho.adiciona(new	Produto("Liquidificador",	250.0));
								carrinho.adiciona(new	Produto("Jogo	de	pratos",	70.0));
								MaiorEMenor	algoritmo	=	new	MaiorEMenor();
								algoritmo.encontra(carrinho);
								System.out.println("O	menor	produto:	"	+	
												algoritmo.getMenor().getNome());
								System.out.println("O	maior	produto:	"	+	
												algoritmo.getMaior().getNome());
				}
}
Esse	 código	não	 é	 tão	diferente	do	 anterior.	Os	produtos,	 bem
como	os	valores,	 são	os	mesmos;	 apenas	 a	ordem	em	que	 eles	 são
inseridos	no	carrinho	foi	 trocada.	Espera-se	então	que	o	programa
produza	 a	 mesma	 saída.	 Mas,	 ao	 executá-lo,	 a	 seguinte	 saída	 é
gerada:
O	menor	produto:	Jogo	de	pratos
Exception	in	thread	"main"	java.lang.NullPointerException
				at	TestaMaiorEMenor.main(TestaMaiorEMenor.java:12)
2.3	O	PRIMEIRO	TESTE	DE	UNIDADE
10	 2.3	O	PRIMEIRO	TESTE	DE	UNIDADE
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
Problema!	Essa	não	era	a	saída	esperada!	Agora	está	claro	que	a
classe		MaiorEMenor		não	funciona	bem	para	todos	os	cenários.	Se
os	produtos,	por	algum	motivo,	forem	adicionados	no	carrinho	em
ordem	decrescente,	a	classe	não	consegue	calcular	corretamente.
Uma	 pergunta	 importante	 para	 o	 momento	 é:	 será	 que	 o
desenvolvedor,	ao	escrever	a	classe,	perceberia	esse	bug?	Será	que	ele
faria	todos	os	testes	necessários	para	garantir	que	a	classe	realmente
funcione?
Como	 discutido	 no	 capítulo	 anterior,	 equipes	 de	 software
tendem	 a	 não	 testar	 software,	 pois	 o	 teste	 leva	 tempo	 e,	 por
consequência,	 dinheiro.	 Na	 prática,	 equipes	 acabam	 por	 executar
poucos	 testes	 ralos,	 que	 garantem	 apenas	 o	 cenário	 feliz	 e	 mais
comum.	 Todos	 os	 problemas	 da	 falta	 de	 testes,	 que	 já	 foram
discutidos	anteriormente,	agora	fazem	sentido.
Imagine	 se	 a	 loja	 virtual	 colocasse	 esse	 código	 em	 produção.
Quantas	compras	seriam	perdidas	por	causa	desse	problema?
Para	diminuir	a	quantidade	de	bugs	levados	para	o	ambiente	de
produção,	é	necessário	testar	o	código	constantemente.	Idealmente,
a	 cada	 alteração	 feita,	 todo	 o	 sistema	 deve	 ser	 testado	 por	 inteiro
novamente.	 Mas	 isso	 deve	 ser	 feito	 de	 maneira	 sustentável:	 é
impraticável	pedir	para	que	seres	humanos	testem	o	sistema	inteiro
a	cada	alteração	feita	por	um	desenvolvedor.
A	 solução	para	o	problema	é	 fazer	 com	que	a	máquina	 teste	o
software.	A	máquina	executará	o	teste	rapidamente	e	sem	custo,	e	o
desenvolvedor	não	gastaria	mais	tempo	executando	testes	manuais,
mas	sim	apenas	em	evoluir	o	sistema.
Escrever	um	teste	automatizado	não	é	 tarefa	 tão	árdua.	Ele,	na
verdade,	 se	 parece	 muito	 com	 um	 teste	 manual.	 Imagine	 um
desenvolvedor	 que	 deva	 testar	 o	 comportamento	 do	 carrinho	 de
2.3	O	PRIMEIRO	TESTE	DE	UNIDADE	 11
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
compras	 da	 loja	 virtual	 quando	 existem	 dois	 produtos	 lá
cadastrados:	 primeiramente,	 ele	 "clicaria	 em	 comprar	 em	 dois
produtos",	em	seguida	"iria	para	o	carrinho	de	compras",	e	por	fim,
verificaria	 "a	 quantidade	 de	 itens	 no	 carrinho	 (deve	 ser	 2)"	 e	 o	 "o
valor	 total	 do	 carrinho	 (que	 deve	 ser	 a	 soma	 dos	 dois	 produtos
adicionados	anteriormente)".
Ou	seja,	de	forma	generalizada,	o	desenvolvedor	primeiro	pensa
em	 um	 cenário	 (dois	 produtos	 comprados),	 depois	 executa	 uma
ação	 (vaiao	 carrinho	 de	 compras),	 e	 por	 fim,	 valida	 a	 saída	 (vê	 a
quantidade	de	 itens	 e	 o	 valor	 total	 do	 carrinho).	A	 figura	 a	 seguir
mostra	 os	 passos	 que	 um	 testador	 geralmente	 faz	 quando	 deseja
testar	uma	funcionalidade.
Um	 teste	 automatizado	 é	 similar.	 Ele	 descreve	 um	 cenário,
executa	uma	ação	e	valida	uma	saída.	A	diferença	é	que	quem	fará
tudo	isso	será	a	máquina,	sem	qualquer	intervenção	humana.
De	 certa	 forma,	 um	 teste	 automatizado	 já	 foi	 escrito	 neste
capítulo.	Veja	o	código	adiante,	escrito	para	testar	superficialmente
a	classe		MaiorEMenor	:
public	class	TestaMaiorEMenor	{
				public	static	void	main(String[]	args)	{
								CarrinhoDeCompras	carrinho	=	new	CarrinhoDeCompras();
								carrinho.adiciona(new	Produto("Geladeira",	450.0));
								carrinho.adiciona(new	Produto("Liquidificador",	250.0));
								carrinho.adiciona(new	Produto("Jogo	de	pratos",	70.0));
								MaiorEMenor	algoritmo	=	new	MaiorEMenor();
								algoritmo.encontra(carrinho);
								System.out.println("O	menor	produto:	"	+	
																																algoritmo.getMenor().getNome());
12	 2.3	O	PRIMEIRO	TESTE	DE	UNIDADE
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
								System.out.println("O	maior	produto:	"	+	
																																algoritmo.getMaior().getNome());
				}
}
Veja	que	esse	código	contém,	de	forma	automatizada,	boa	parte
do	 que	 foi	 descrito	 em	 relação	 ao	 teste	 manual:	 ele	 monta	 um
cenário	 (um	 carrinho	 de	 compras	 com	 3	 produtos),	 executa	uma
ação	(invoca	o	método		encontra()	),	e	valida	a	saída	(imprime	o
maior	e	o	menor	produto).
E	 o	 melhor:	 uma	 máquina	 faz	 (quase)	 tudo	 isso.	 Ao	 rodar	 o
código	 anterior,	 a	máquina	monta	o	 cenário	 e	 executa	 a	 ação	 sem
qualquer	 intervenção	 humana.	 Mas	 uma	 ação	 humana	 ainda	 é
requerida	para	descobrir	se	o	comportamento	executou	de	acordo.
Um	 humano	 precisa	 ver	 a	 saída	 e	 conferir	 com	 o	 resultado
esperado.
É	 preciso	 que	 o	 próprio	 teste	 faça	 a	 validação	 e	 informe	 o
desenvolvedor	caso	o	resultado	não	seja	o	esperado.	Para	melhorar
esse	 código,	 agora	 só	 introduzindo	 um	 framework	 de	 teste
automatizado.	 Esse	 framework	 nos	 daria	 um	 relatório	 mais
detalhado	 dos	 testes	 que	 foram	 executados	 com	 sucesso	 e,	 mais
importante,	dos	 testes	que	 falharam,	 trazendo	o	nome	do	 teste	e	a
linha	que	apresentaram	problemas.
Neste	 livro,	 faremos	 uso	 do	 JUnit	 (http://www.junit.org),	 o
framework	 de	 testes	 de	 unidade	mais	 popular	 do	mundo	 Java.	 O
JUnit	possui	um	plugin	para	Eclipse,	que	mostra	uma	lista	de	todos
os	 testes	 executados,	pintando-os	de	verde	em	caso	de	 sucesso,	ou
vermelho	 em	 caso	 de	 falha.	 Ao	 clicar	 em	 um	 teste	 vermelho,	 a
ferramenta	ainda	apresenta	a	 linha	que	falhou,	o	resultado	que	era
esperado	e	o	resultado	devolvido	pelo	método.
Para	 converter	 o	 código	 anterior	 em	 um	 teste	 que	 o	 JUnit
entenda,	não	é	necessário	muito	trabalho.	A	única	parte	que	ainda
2.3	O	PRIMEIRO	TESTE	DE	UNIDADE	 13
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
não	 é	 feita	 100%	 pela	 máquina	 é	 a	 terceira	 parte	 do	 teste:	 a
validação.	É	 justamente	ali	que	 invocaremos	os	métodos	do	 JUnit.
Eles	que	farão	a	comparação	do	resultado	esperado	com	o	calculado.
No	JUnit,	o	método	para	isso	é	o		Assert.assertEquals()	:
import	org.junit.Assert;
import	org.junit.Test;
public	class	TestaMaiorEMenor	{
				@Test
				public	void	ordemDecrescente()	{
								CarrinhoDeCompras	carrinho	=	new	CarrinhoDeCompras();
								carrinho.adiciona(new	Produto("Geladeira",	450.0));
								carrinho.adiciona(new	Produto("Liquidificador",	250.0));
								carrinho.adiciona(new	Produto("Jogo	de	pratos",	70.0));
								MaiorEMenor	algoritmo	=	new	MaiorEMenor();
								algoritmo.encontra(carrinho);
								Assert.assertEquals("Jogo	de	pratos",	
												algoritmo.getMenor().getNome());
								Assert.assertEquals("Geladeira",	
												algoritmo.getMaior().getNome());
				}
}
Pronto.	Esse	código	é	executado	pelo	JUnit.	O	teste,	como	bem
sabemos,	falhará:
14	 2.3	O	PRIMEIRO	TESTE	DE	UNIDADE
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
Para	fazer	o	teste	passar,	é	necessário	corrigir	o	bug	na	classe	de
produção.	 O	 que	 faz	 o	 código	 falhar	 é	 justamente	 a	 presença	 do
	else		 (ele	 fazia	 com	 que	 o	 código	 nunca	 passasse	 pelo	 segundo
	if	,	que	verificava	justamente	o	maior	elemento).	Ao	removê-lo,	o
teste	passa:
public	class	MaiorEMenor	{
				private	Produto	menor;
				private	Produto	maior;
				public	void	encontra(CarrinhoDeCompras	carrinho)	{
								for(Produto	produto	:	carrinho.getProdutos())	{
												if(menor	==	null	||	
																produto.getValor()	<	menor.getValor())	{
																menor	=	produto;
												}
												if	(maior	==	null	||	
																				produto.getValor()	>	maior.getValor()){
																maior	=	produto;
												}
								}
				}
				public	Produto	getMenor()	{
								return	menor;
				}
				public	Produto	getMaior()	{
								return	maior;
				}
}
2.3	O	PRIMEIRO	TESTE	DE	UNIDADE	 15
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
Repare	também	no	tempo	que	a	máquina	levou	para	executar	o
teste:	 0.007	 segundos.	 Mais	 rápido	 do	 que	 qualquer	 ser	 humano
faria.	 Isso	 possibilita	 ao	 desenvolvedor	 executar	 esse	 teste	 diversas
vezes	ao	longo	do	seu	dia	de	trabalho.
E	o	melhor:	 se	 algum	dia	um	outro	desenvolvedor	 alterar	 esse
código,	 ele	 poderá	 executar	 a	 bateria	 de	 testes	 automatizados
existente	 e	 descobrir	 se	 a	 sua	 alteração	 fez	 alguma	 funcionalidade
que	 já	 funcionava	 anteriormente	 parar	 de	 funcionar.	 Isso	 é
conhecido	como	testes	de	 regressão.	 Eles	 garantem	que	o	 sistema
não	regrediu.
MEU	PRIMEIRO	TESTE	AUTOMATIZADO
Há	muitos	anos	atrás,	trabalhava	em	uma	pequena	consultoria
de	 desenvolvimento	 de	 software	 em	 São	 Paulo.	 E	 como	 em
toda	consultoria,	precisávamos	anotar	nossas	horas	de	trabalho
em	 cada	 um	 dos	 projetos	 da	 empresa,	 a	 fim	 de	 cobrar
corretamente	cada	um	dos	clientes.
Resolvi,	 por	 conta	 própria,	 criar	 um	 simples	 projeto	 para
controle	de	horas	de	trabalho	(eu	precisava	de	um	motivo	para
experimentar	 todas	 as	 coisas	 que	 estava	 aprendendo	 naquele
momento	 e,	 dentre	 elas,	 testes	 automatizados).	O	 sistema	 era
bem	 simples:	 cadastro	 de	 funcionários,	 cadastro	 de	 projetos,
ligação	entre	um	funcionário	e	um	projeto	e	cadastro	de	horas
em	um	projeto.
Ao	final	da	implementação,	apresentei	o	sistema	ao	diretor	da
empresa.	 Ele	 adorou,	 e	me	 sugeriu	 a	 implementação	 de	 uma
simples	regra	de	negócio:	se	o	número	total	de	horas	colocadas
no	 projeto	 ultrapasse	 um	 determinado	 limite,	 nenhum
funcionário	 poderia	 adicionar	 mais	 horas	 nele.	 A
implementação	era	bem	trivial:	bastava	fazer	um		if	.
16	 2.3	O	PRIMEIRO	TESTE	DE	UNIDADE
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
Lembro-me	 de	 que	 implementei	 a	 regra	 de	 negócio	 e	 então
escrevi	 o	 teste	 de	 unidade	 para	 garantir	 que	 havia
implementado	 corretamente.	 O	 teste	 que	 acabei	 de	 escrever
ficou	verde,	mas	 três	ou	quatro	 testes	que	 já	existiam	 ficaram
vermelhos.	 A	 única	 linha	 de	 código	 que	 escrevi	 fez	 com	 que
funcionalidades	 que	 já	 funcionavam	 parassem	 de	 trabalhar
corretamente.
Naquele	momento,	me	veio	a	cabeça	todas	as	vezes	que	escrevi
uma	ou	duas	linhas	de	código,	aparentemente	simples,	mas	que
poderiam	 ter	 quebrado	 o	 sistema.	 Percebi	 então	 a	 grande
vantagem	 da	 bateria	 de	 testes	 automatizados:	 segurança.
Percebi	como	é	fácil	quebrar	código,	e	como	é	difícil	perceberisso	 sem	 testes	 automatizados.	Daquele	 dia	 em	 diante,	 penso
duas	vezes	antes	de	escrever	código	sem	teste.
Ainda	 são	 necessários	muitos	 testes	 para	 garantir	 que	 a	 classe
	MaiorEMenor		 funcione	 corretamente.	Até	 agora,	 o	único	 cenário
testado	são	produtos	em	ordem	decrescente.	Muitos	outros	cenários
precisam	ser	testados.	Dentre	eles:
Produtos	com	valores	em	ordem	crescente;
Produtos	com	valores	em	ordem	variada;
Um	único	produto	no	carrinho.
Conhecendo	o	código	da	classe		MaiorEMenor	,	é	possível	prever
que	 esses	 cenários	 funcionarão	 corretamente.	 Escrever	 testes
automatizados	para	eles	pode	parecer	inútil	por	enquanto.
Entretanto,	 é	 importante	 lembrar	 de	 que,	 em	 códigos	 reais,
muitos	desenvolvedores	fazem	alterações	nele.	Para	o	desenvolvedor
2.4	CONTINUANDO	A	TESTAR
2.4	CONTINUANDO	A	TESTAR	 17
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
que	implementa	a	classe,	o	código	dela	é	bem	natural	e	simples	de
ser	entendido.	Mas	para	os	futuros	desenvolvedores	que	a	alterarão,
esse	código	pode	não	parecer	tão	simples.
É	necessário	 então	prover	 segurança	para	 eles	nesse	momento.
Portanto,	 apesar	 de	 alguns	 testes	 parecerem	 desnecessários	 nesse
instante,	eles	 garantirão	que	 a	 evolução	dessa	 classe	 será	 feita	 com
qualidade.
Apenas	para	exemplificar	mais	ainda,	vamos	escrever	mais	um
teste,	 dessa	 vez	 para	 um	 carrinho	 com	 apenas	 1	 produto.	 Repare
que,	nesse	cenário,	é	esperado	que	o	maior	e	menor	produtos	sejam
o	mesmo:
import	org.junit.Assert;
import	org.junit.Test;
public	class	TestaMaiorEMenor	{
				@Test
				public	void	apenasUmProduto()	{
								CarrinhoDeCompras	carrinho	=	new	CarrinhoDeCompras();
								carrinho.adiciona(new	Produto("Geladeira",	450.0));
								MaiorEMenor	algoritmo	=	new	MaiorEMenor();
								algoritmo.encontra(carrinho);
								Assert.assertEquals("Geladeira",	
												algoritmo.getMenor().getNome());
								Assert.assertEquals("Geladeira",	
												algoritmo.getMaior().getNome());
				}
}
18	 2.4	CONTINUANDO	A	TESTAR
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
COMPARANDO	SÓ	O	NOME?
Em	vez	de	comparar	apenas	o	nome	do	produto,	você	poderia
comparar	 o	 objeto	 inteiro:		Assert.assertEquals(produto,
algoritmo.getMenor());	,	 por	 exemplo.	 Mas,	 para	 isso,	 o
método	 	 equals()	 	 deve	 estar	 implementado	 na	 classe
	Produto	.
Em	 certos	 casos,	 essa	 solução	 pode	 ser	 mais	 interessante.
Afinal,	 você	 comparará	 o	 objeto	 inteiro	 e	 não	 só	 apenas	 um
atributo.
Desenvolvedores	gastam	toda	sua	vida	automatizando	processos
de	 outras	 áreas	 de	 negócio,	 criando	 sistemas	 para	 RHs,	 controle
financeiro,	 entre	 outros,	 com	o	 intuito	de	 facilitar	 a	 vida	daqueles
profissionais.	 Por	 que	 não	 criar	 software	 que	 automatize	 o	 seu
próprio	ciclo	de	trabalho?
Testes	 automatizados	 são	 fundamentais	 para	 um
desenvolvimento	de	qualidade,	e	é	obrigação	de	todo	desenvolvedor
escrevê-los.	Sua	existência	 traz	diversos	benefícios	para	o	software,
como	o	aumento	da	qualidade	e	a	diminuição	de	bugs	em	produção.
Nos	próximos	capítulos,	discutiremos	 sobre	como	aumentar	ainda
mais	o	feedback	que	os	testes	nos	dão	sobre	a	qualidade	do	software.
2.5	CONCLUSÃO
2.5	CONCLUSÃO	 19
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
CAPÍTULO	3
Desenvolvedores	 (ou	 qualquer	 outro	 papel	 que	 é	 executado
dentro	de	uma	equipe	de	software)	estão	muito	acostumados	com	o
"processo	 tradicional"	 de	 desenvolvimento:	 primeiro	 a
implementação	 e	 depois	 o	 teste.	 Entretanto,	 uma	 pergunta
interessante	é:	será	que	é	possível	 inverter,	ou	seja,	 testar	primeiro	e
depois	implementar?	E	mais	importante,	faz	algum	sentido?
Para	 responder	 essa	 pergunta,	 ao	 longo	 deste	 capítulo
desenvolveremos	um	simples	algoritmo	matemático,	mas	dessa	vez
invertendo	o	ciclo	de	desenvolvimento:	o	teste	será	escrito	antes	da
implementação.	Ao	final,	discutiremos	as	vantagens	e	desvantagens
dessa	abordagem.
Numerais	romanos	foram	criados	na	Roma	Antiga	e	eles	foram
utilizados	em	todo	o	seu	império.	Os	números	eram	representados
por	sete	diferentes	símbolos,	listados	na	tabela	a	seguir.
I,	unus,	1,	(um)
V,	quinque,	5	(cinco)
X,	decem,	10	(dez)
L,	quinquaginta,	50	(cinquenta)
C,	centum,	100	(cem)
INTRODUÇÃO	AO	TEST-
DRIVEN	DEVELOPMENT
3.1	O	PROBLEMA	DOS	NÚMEROS	ROMANOS
20	 3	INTRODUÇÃO	AO	TEST-DRIVEN	DEVELOPMENT
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
D,	quingenti,	500	(quinhentos)
M,	mille,	1.000	(mil)
Para	 representar	 outros	 números,	 os	 romanos	 combinavam
estes	símbolos,	começando	do	algarismo	de	maior	valor	e	seguindo
a	regra:
Algarismos	 de	 menor	 ou	 igual	 valor	 à	 direita	 são
somados	ao	algarismo	de	maior	valor;
Algarismos	 de	menor	 valor	 à	 esquerda	 são	 subtraídos
do	algarismo	de	maior	valor.
Por	 exemplo,	 XV	 representa	 15	 (10	 +	 5)	 e	 o	 número	 XXVIII
representa	28	(10	+	10	+	5	+	1	+	1	+	1).	Há	ainda	uma	outra	regra:
nenhum	símbolo	pode	ser	repetido	lado	a	lado	por	mais	de	3	vezes.
Por	exemplo,	o	número	4	é	representado	pelo	número	IV	(5	-	1)	e
não	pelo	número	IIII.
Existem	 outras	 regras	 (especialmente	 para	 números	 maiores,
que	 podem	 ser	 lidas	 aqui
http://pt.wikipedia.org/wiki/Numera%C3%A7%C3%A3o_romana),
mas	em	 linhas	gerais,	 este	 é	 o	problema	 a	 ser	 resolvido.	Dado	um
numeral	 romano,	 o	 programa	 deve	 convertê-lo	 para	 o	 número
inteiro	correspondente.
Conhecendo	 o	 problema	 dos	 numerais	 romanos,	 é	 possível
levantar	 os	 diferentes	 cenários	 que	 precisam	 ser	 aceitos	 pelo
algoritmo:	 um	 símbolo,	 dois	 símbolos	 iguais,	 três	 símbolos	 iguais,
dois	 símbolos	 diferentes	 do	maior	 para	 o	menor,	 quatro	 símbolos
dois	a	dois,	e	assim	por	diante.	Dado	todos	estes	cenários,	uns	mais
simples	 que	os	 outros,	 começaremos	pelo	mais	 simples:	 um	único
símbolo.
3.2	O	PRIMEIRO	TESTE
3.2	O	PRIMEIRO	TESTE	 21
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
Começando	 pelo	 teste	 "deve	 entender	 o	 símbolo	 I".	 A	 classe
responsável	 pela	 conversão	 pode	 ser	 chamada,	 por	 exemplo,	 de
	ConversorDeNumeroRomano	,	e	o	método		converte()	,	recebendo
uma	 String	 com	 o	 numeral	 romano	 e	 devolvendo	 o	 valor	 inteiro
representado	por	aquele	número:
public	class	ConversorDeNumeroRomanoTest	{
				@Test
				public	void	deveEntenderOSimboloI()	{
								ConversorDeNumeroRomano	romano	=	
												new	ConversorDeNumeroRomano();
								int	numero	=	romano.converte("I");
								assertEquals(1,	numero);
				}
}
IMPORT	ESTÁTICO
Repare	 que	 aqui	 utilizamos	 	assertEquals()		 diretamente.
Isso	 é	 possível	 graças	 ao	 import	 estático	 do	 Java	 5.0.	 Basta
importar		import	static	org.junit.Assert.*		 e	 todos	 os
métodos	 estáticos	 dessa	 classe	 estarão	 disponíveis	 sem	 a
necessidade	de	colocar	o	nome	dela.
Veja	 que	 nesse	 momento	 esse	 código	 não	 compila;	 a	 classe
	ConversorDeNumeroRomano	,	bem	como	o	método		converte()	,
não	existem.	Para	resolver	o	erro	de	compilação,	é	necessário	criar	a
classe,	mesmo	que	sem	uma	implementação	real:
public	class	ConversorDeNumeroRomano	{
				public	int	converte(String	numeroEmRomano)	{
								return	0;
				}
}
22	 3.2	O	PRIMEIRO	TESTE
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
De	volta	ao	teste,	ele	agora	compila.	Ao	executá-lo,	o	teste	falha.
Mas	 não	 há	 problema;	 isso	 já	 era	 esperado.	 Para	 fazê-lo	 passar,
introduziremos	ainda	uma	segunda	regra:	o	código	escrito	deve	ser
sempre	o	mais	simples	possível.
Com	essa	regra	em	mente,	o	código	mais	simples	que	fará	o	teste
passar	é	fazer	simplesmente	o	método	converte()	retornar	o	número1:
public	int	converte(String	numeroEmRomano)	{
				return	1;
}
Desenvolvedores,	muito	provavelmente,	não	ficarão	felizes	com
essa	 implementação,	afinal	ela	 funciona	apenas	para	um	caso.	Mas
isso	não	é	problema,	já	que	a	implementação	não	está	pronta;	ainda
estamos	trabalhando	nela.
Um	próximo	cenário	seria	o	símbolo	V.	Nesse	caso,	o	algoritmo
deve	retornar	5.	Novamente	começando	pelo	teste:
@Test
public	void	deveEntenderOSimboloV()	{
				ConversorDeNumeroRomano	romano	=	
								new	ConversorDeNumeroRomano();
				int	numero	=	romano.converte("V");
				assertEquals(5,	numero);
}
Esse	 teste	 também	falha.	Novamente	 faremos	a	 implementação
mais	 simples	 que	 resolverá	 o	 problema.	 Podemos,	 por	 exemplo,
fazer	 com	 que	 o	 método	 	converte()		 verifique	 o	 conteúdo	 do
número	a	ser	convertido:	se	o	valor	for	"I",	o	método	retorna	1;	se	o
valor	for	"V",	o	método	retorna	5:
public	int	converte(String	numeroEmRomano)	{
				if(numeroEmRomano.equals("I"))	return	1;
				else	if(numeroEmRomano.equals("V"))	return	5;
				return	0;
}
3.2	O	PRIMEIRO	TESTE	 23
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
Os	 testes	 passam	 (os	 dois	 que	 temos).	 Poderíamos	 repetir	 o
mesmo	teste	e	a	mesma	implementação	para	os	símbolos	que	faltam
(X,	 L,	 C,	 M,	 ...).	 Mas	 nesse	 momento,	 já	 temos	 uma	 primeira
definição	sobre	nosso	algoritmo:	quando	o	numeral	romano	possui
apenas	um	símbolo,	basta	devolvermos	o	inteiro	associado	a	ele.
Em	 vez	 de	 escrever	 um	monte	 de	 	if	s	 para	 cada	 símbolo,	 é
possível	usar	um	switch	que	corresponde	melhor	ao	nosso	cenário.
Melhorando	 ainda	 mais,	 em	 vez	 do	 switch,	 é	 possível	 guardar	 os
símbolos	em	uma	tabela,	ou	no	Java,	em	um	mapa	entre	o	algarismo
e	 o	 inteiro	 correspondente	 a	 ele.	 Sabendo	 disso,	 vamos	 nesse
momento	alterar	o	código	para	refletir	a	solução:
public	class	ConversorDeNumeroRomano	{
				private	static	Map<String,	Integer>	tabela	=	
								new	HashMap<String,	Integer>()	{{
								put("I",	1);
								put("V",	5);
								put("X",	10);
								put("L",	50);
								put("C",	100);
								put("D",	500);
								put("M",	1000);
				}};
				public	int	converte(String	numeroEmRomano)	{
								return	tabela.get(numeroEmRomano);
				}
}
Ambos	 os	 testes	 continuam	 passando.	 Passaremos	 agora	 para
um	 segundo	 cenário:	 dois	 símbolos	 em	 sequência,	 como	 por
exemplo,	"II"	ou	"XX".	Começando	novamente	pelo	teste,	temos:
@Test
public	void	deveEntenderDoisSimbolosComoII()	{
				ConversorDeNumeroRomano	romano	=
									new	ConversorDeNumeroRomano();
				int	numero	=	romano.converte("II");
				assertEquals(2,	numero);
24	 3.2	O	PRIMEIRO	TESTE
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
}
Para	 fazer	 o	 teste	 passar	 de	 maneira	 simples,	 é	 possível
simplesmente	adicionar	os	símbolos	"II"	na	tabela:
private	static	Map<String,	Integer>	tabela	=	
				new	HashMap<String,	Integer>()	{{
				put("I",	1);
				put("II",	2);
				put("V",	5);
				put("X",	10);
				put("L",	50);
				put("C",	100);
				put("D",	500);
				put("M",	1000);
}};
O	teste	passa.	Mas,	apesar	de	simples,	essa	não	parece	uma	boa
ideia	de	 implementação:	 seria	necessário	 incluir	 todos	os	possíveis
símbolos	nessa	tabela,	o	que	não	faz	sentido.
É	 hora	 de	 refatorar	 esse	 código	 novamente.	 Uma	 possível
solução	seria	iterar	em	cada	um	dos	símbolos	no	numeral	romano	e
acumular	seu	valor;	ao	final,	retorna	o	valor	acumulado.	Para	isso,	é
necessário	 mudar	 a	 	tabela		 para	 guardar	 somente	 os	 símbolos
principais	 da	 numeração	 romana.	 Uma	 possível	 implementação
deste	algoritmo	seria:
private	static	Map<Character,	Integer>	tabela	=	
				new	HashMap<Character,	Integer>()	{{
				put('I',	1);
				put('V',	5);
				put('X',	10);
				put('L',	50);
				put('C',	100);
				put('D',	500);
				put('M',	1000);
}};
public	int	converte(String	numeroEmRomano)	{
				int	acumulador	=	0;
				for(int	i	=	0;	i	<	numeroEmRomano.length();	i++)	{
3.2	O	PRIMEIRO	TESTE	 25
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
								acumulador	+=	tabela.get(numeroEmRomano.charAt(i));
				}
				return	acumulador;
}
DE	STRING	PARA	CHAR?
Repare	 que	 o	 tipo	 da	 chave	 no	mapa	mudou	 de	 String	 para
Character.	Como	o	algoritmo	captura	letra	por	letra	da	variável
	numeroEmRomano	,	usando	o	método		charAt()	,	que	devolve
um	char,	a	busca	do	símbolo	fica	mais	direta.
Os	três	testes	continuam	passando.	E,	dessa	forma,	resolvemos	o
problema	de	 dois	 símbolos	 iguais	 em	 seguida.	O	próximo	 cenário
são	 quatro	 símbolos,	 dois	 a	 dois,	 como	 por	 exemplo,	 "XXII",	 que
deve	resultar	em	22.	Veja	o	teste:
@Test
public	void	deveEntenderQuatroSimbolosDoisADoisComoXXII()	{
				ConversorDeNumeroRomano	romano	=	
								new	ConversorDeNumeroRomano();
				int	numero	=	romano.converte("XXII");
				assertEquals(22,	numero);
}
Esse	teste	já	passa	sem	que	precisemos	fazer	qualquer	alteração.
O	algoritmo	existente	até	aqui	já	resolve	o	problema.	Vamos	então
para	o	próximo	cenário:	números	 como	 "IV"	ou	 "IX",	 em	que	não
basta	apenas	somar	os	símbolos	existentes.
Novamente,	começando	pelo	teste:
@Test
public	void	deveEntenderNumerosComoIX()	{
				ConversorDeNumeroRomano	romano	=
									new	ConversorDeNumeroRomano();
				int	numero	=	romano.converte("IX");
				assertEquals(9,	numero);
}
26	 3.2	O	PRIMEIRO	TESTE
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
Para	 fazer	 esse	 teste	 passar,	 é	 necessário	 pensar	 um	 pouco
melhor	sobre	o	problema.	Repare	que	os	símbolos	em	um	numeral
romano,	 da	 direita	 para	 a	 esquerda,	 sempre	 crescem.	Quando	 um
número	 a	 esquerda	 é	 menor	 do	 que	 seu	 vizinho	 a	 direita,	 esse
número	deve	então	ser	subtraído	em	vez	de	somado	no	acumulador.
Esse	algoritmo,	em	código:
public	int	converte(String	numeroEmRomano)	{
				int	acumulador	=	0;
				int	ultimoVizinhoDaDireita	=	0;
				for(int	i	=	numeroEmRomano.length()	-	1;	i	>=	0;	i--)	{
								//	pega	o	inteiro	referente	ao	simbolo	atual
								int	atual	=	tabela.get(numeroEmRomano.charAt(i));
								//	se	o	da	direita	for	menor,	o	multiplicaremos	
								//	por	-1	para	torná-lo	negativo
								int	multiplicador	=	1;
								if(atual	<	ultimoVizinhoDaDireita)	multiplicador	=	-1;
								acumulador	+=	
											tabela.get(numeroEmRomano.charAt(i))	*	multiplicador;
								//	atualiza	o	vizinho	da	direita
								ultimoVizinhoDaDireita	=	atual;
				}
				return	acumulador;
}
Os	testes	agora	passam.	Mas	veja,	existe	código	repetido	ali.	Na
linha	 em	 que	 o	 acumulador	 é	 somado	 com	 o	 valor	 atual,
	tabela.get(numeroEmRomano.charAt(i))		 pode	 ser	 substituído
pela	variável		atual	.	Melhorando	o	código,	temos:
acumulador	+=	atual	*	multiplicador;
A	refatoração	 foi	 feita	com	sucesso,	 já	que	os	 testes	continuam
passando.	 Ao	 próximo	 cenário:	 numeral	 romano	 que	 contenha
tanto	números	"invertidos",	como	"IV",	e	dois	símbolos	lado	a	lado,
como	 "XX".	 Por	 exemplo,	 o	 número	 "XXIV",	 que	 representa	 o
número	24.
3.2	O	PRIMEIRO	TESTE	 27
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
Começando	pelo	teste:
@Test
public	void	deveEntenderNumerosComplexosComoXXIV()	{
				ConversorDeNumeroRomano	romano	=
								new	ConversorDeNumeroRomano();
				int	numero	=	romano.converte("XXIV");
				assertEquals(24,	numero);
}
Esse	 teste	 já	 passa;	 o	 algoritmo	 criado	 até	 então	 já	 atende	 o
cenário	 do	 teste.	 Ainda	 há	 outros	 cenários	 que	 poderiam	 ser
testados,	mas	já	fizemos	o	suficiente	para	discutir	sobre	o	assunto.
De	maneira	mais	abstrata,	o	ciclo	que	 foi	repetido	ao	 longo	do
processo	de	desenvolvimento	da	classe	anterior	foi:
Escrevemos	 um	 testede	 unidade	 para	 uma	 nova
funcionalidade;
Vimos	o	teste	falhar;
Implementamos	o	código	mais	simples	para	resolver	o
problema;
Vimos	o	teste	passar;
Melhoramos	 (refatoramos)	 nosso	 código	 quando
necessário.
Esse	 ciclo	 de	 desenvolvimento	 é	 conhecido	 por	 Test-Driven
Development	(TDD),	ou,	Desenvolvimento	Guiado	pelos	Testes.
A	ideia	é	simples:	o	desenvolvedor	deve	começar	a	 implementação
pelo	 teste,	 e	deve	o	 tempo	 todo	 fazer	de	 tudo	para	que	seu	código
fique	simples	e	com	qualidade.
3.3	REFLETINDO	SOBRE	O	ASSUNTO
28	 3.3	REFLETINDO	SOBRE	O	ASSUNTO
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
Esse	 ciclo	 é	 também	 conhecido	 como	 ciclo	 vermelho-verde-
refatora	 (ou	 red-green-refactor).	 O	 primeiro	 passo	 é	 escrever	 um
teste	que	 falha.	A	cor	vermelha	 representa	esse	 teste	 falhando.	Em
seguida,	o	fazemos	passar	(a	cor	verde	representa	ele	passando).	Por
fim,	refatoramos	para	melhorar	o	código	que	escrevemos.
Muitos	 praticantes	 de	 TDD	 afirmam	 que	 executar	 esse	 ciclo
pode	 ser	 muito	 vantajoso	 para	 o	 processo	 de	 desenvolvimento.
Algumas	delas:
Foco	no	teste	e	não	na	implementação	—	Ao	começar
pelo	teste,	o	programador	consegue	pensar	somente	no
que	a	classe	deve	fazer,	e	esquece	por	um	momento	da
implementação.	 Isso	 o	 ajuda	 a	 pensar	 em	 melhores
cenários	de	teste	para	a	classe	sob	desenvolvimento.
Código	 nasce	 testado	—	 Se	 o	 programador	 pratica	 o
ciclo	 corretamente,	 isso	 então	 implica	 em	 que	 todo	 o
código	de	produção	 escrito	possui	 ao	menos	um	 teste
3.4	QUAIS	AS	VANTAGENS?
3.4	QUAIS	AS	VANTAGENS?	 29
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
de	unidade	verificando	que	ele	funciona	corretamente.
Simplicidade	—	 Ao	 buscar	 pelo	 código	mais	 simples
constantemente,	 o	 desenvolvedor	 acaba	 por	 fugir	 de
soluções	 complexas,	 comuns	 em	 todos	 os	 sistemas.	O
praticante	 de	 TDD	 escreve	 código	 que	 apenas	 resolve
os	problemas	que	estão	representados	por	um	teste	de
unidade.	 Quantas	 vezes	 o	 desenvolvedor	 não	 escreve
código	desnecessariamente	complexo?
Melhor	 reflexão	 sobre	 o	 design	 da	 classe	 —	 No
cenário	tradicional,	muitas	vezes	a	falta	de	coesão	ou	o
excesso	 de	 acoplamento	 é	 causado	 muitas	 vezes	 pelo
desenvolvedor	que	só	pensa	na	implementação	e	acaba
esquecendo	como	a	classe	vai	funcionar	perante	o	todo.
Ao	 começar	 pelo	 teste,	 o	 desenvolvedor	 pensa	 sobre
como	 sua	 classe	 deverá	 se	 comportar	 frente	 às	 outras
classes	do	sistema.	O	teste	atua	como	o	primeiro	cliente
da	classe	que	está	sendo	escrita.	Nele,	o	desenvolvedor
toma	decisões	como	o	nome	da	classe,	os	seus	métodos,
parâmetros,	tipos	de	retorno	etc.	No	fim,	todas	elas	são
decisões	de	design	e,	quando	o	desenvolvedor	consegue
observar	com	atenção	o	código	do	teste,	seu	design	de
classes	pode	crescer	muito	em	qualidade.
Todos	estes	pontos	serão	mais	bem	descritos	e	aprofundados	no
capítulo	 a	 seguir.	 Nesse	 momento,	 foque	 nestas	 vantagens.	 Uma
pergunta	que	pode	vir	 a	 cabeça	 é:	 "No	modelo	 tradicional,	onde	os
testes	 são	 escritos	 depois,	 o	 desenvolvedor	 não	 tem	 os	 mesmos
benefícios?"
A	resposta	 é	 sim.	Mesmo	desenvolvedores	que	 escrevem	 testes
depois	podem	obter	as	mesmas	vantagens.	Um	desenvolvedor	pode
perceber	que	está	com	dificuldades	de	escrever	um	teste	e	descobrir
30	 3.4	QUAIS	AS	VANTAGENS?
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
que	 o	 design	da	 classe	 que	 implementou	 tem	problemas;	 ele	 pode
também	 conseguir	 abstrair	 a	 implementação	 e	 escrever	 bons
cenários	de	teste.
Mas	 há	 uma	 diferença	 crucial:	 a	 quantidade	 de	 vezes	 que	 um
programador	praticante	de	TDD	recebe	feedback	sobre	esses	pontos
e	a	quantidade	que	um	programador	que	não	pratica	TDD	recebe.
Veja	a	 figura	a	seguir.	O	praticante	de	TDD	escreve	um	pouco
de	 testes,	 um	 pouco	 de	 implementação	 e	 recebe	 feedback.	 Isso
acontece	ao	longo	do	desenvolvimento	de	maneira	frequente.	Já	um
programador	 que	 não	 pratica	 TDD	 espera	 um	 tempo	 (às	 vezes
longo	demais)	para	obter	o	mesmo	feedback.
Ao	receber	feedback	desde	cedo,	o	programador	pode	melhorar
o	 código	 e	 corrigir	 problemas	 a	 um	 custo	 menor	 do	 que	 o
programador	que	recebeu	a	mesma	mensagem	muito	tempo	depois.
Todo	 programador	 sabe	 que	 alterar	 o	 código	 que	 ele	 acabou	 de
escrever	é	muito	mais	fácil	e	rápido	do	que	alterar	o	código	escrito	3
dias	atrás.
No	fim,	TDD	apenas	maximiza	a	quantidade	de	feedback	sobre
o	 código	 que	 está	 sendo	 produzido,	 fazendo	 o	 programador
perceber	 os	 problemas	 antecipadamente	 e,	 por	 consequência,
diminuindo	os	custos	de	manutenção	e	melhorando	o	código.
3.4	QUAIS	AS	VANTAGENS?	 31
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
DESENVOLVEDORES	E	A	BUSCA	PELA	COMPLEXIDADE
Acho	 impressionante	 como	 nós,	 desenvolvedores,	 somos
atraídos	 por	 complexidade.	 Gostamos	 de	 problemas	 difíceis,
que	nos	desafiem.	Lembro-me	de	que,	no	começo	de	carreira,
quando	 pegava	 alguma	 funcionalidade	 simples	 de	 ser
implementada,	 eu	 mesmo	 "aumentava	 a	 funcionalidade"
somente	para	 torná-la	 interessante	do	ponto	de	 vista	 técnico.
Ou	 seja,	 um	 simples	 relatório	 se	 tornava	 um	 relatório
complexo,	com	diversos	filtros	e	que	podia	ser	exportado	para
muitos	formatos	diferentes.
Aprender	a	ser	simples	foi	difícil.	O	TDD,	de	certa	forma,	me
ajudou	 nisso.	Ao	 pensar	 de	 pouco	 em	 pouco,	 e	 implementar
somente	 o	 necessário	 para	 resolver	 o	 problema	 naquele
momento,	 comecei	a	perceber	que	poderia	gastar	meu	 tempo
implementando	 funcionalidades	 que	 realmente	 agregariam
valor	para	o	usuário	final.
Portanto,	não	ache	que	"ser	simples"	é	fácil.	Lembre-se	de	que
somos	atraídos	por	complexidade.
TDD	ficou	bastante	popular	após	a	publicação	do	livro	TDD:	By
Example,	do	Kent	Beck,	em	2002.	O	próprio	Kent	afirma	que	TDD
não	 foi	 uma	 ideia	 totalmente	 original.	 Ele	 conta	 que,	 em	 algum
momento	 de	 sua	 vida,	 leu	 em	 algum	 dos	 livros	 de	 seu	 pai	 (que
também	era	programador)	sobre	uma	técnica	de	testes	mais	antiga,
com	a	qual	o	programador	colocava	na	fita	o	valor	que	ele	esperava
daquele	programa,	e	então	o	desenvolvia	até	chegar	naquele	valor.
3.5	UM	POUCO	DA	HISTÓRIA	DE	TDD
32	 3.5	UM	POUCO	DA	HISTÓRIA	DE	TDD
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
Ele	próprio	conta	que	achou	a	ideia	estúpida.	Qual	o	sentido	de
escrever	 um	 teste	 que	 falha?	 Mas	 resolveu	 experimentar.	 Após	 a
experiência,	 ele	 disse	 que	 "as	 pessoas	 sempre	 falavam	 para	 ele
conseguir	 separar	 o	 que	 o	 programa	 deve	 fazer	 da	 sua
implementação	final,	mas	que	ele	não	sabia	como	fazer,	até	aquele
momento	em	que	resolveu	escrever	o	teste	antes."
Daquele	momento	em	diante,	Kent	Beck	continuou	a	trabalhar
na	ideia.	Em	1994,	ele	escreveu	o	seu	primeiro	framework	de	testes
de	unidade,	o	SUnit	(para	Smalltalk).	Em	1995,	ele	apresentou	TDD
pela	primeira	vez	na	OOPSLA	(conferência	muito	famosa	da	área	de
computação,	já	que	muitas	novidades	tendem	a	aparecer	lá).
Já	 em	 2000,	 o	 JUnit	 surgiu	 e	 Kent	 Beck,	 junto	 com	 Erich
Gamma,	 publicou	 o	 artigo	 chamado	 Test	 Infected	 (2000),	 que
mostrava	 as	 vantagens	 de	 se	 ter	 testes	 automatizados	 e	 como	 isso
pode	ser	viciante.
Finalmente	 em	 2002,	 Kent	 Beck	 lançou	 seu	 livro	 sobre	 isso,	 e
desde	então	a	prática	tem	se	tornado	cada	vez	mais	popular	entre	os
desenvolvedores.
A	 história	 mais	 completa	 pode	 ser	 vista	 na	 Wiki	 da	 C2
(http://c2.com/cgi/wiki?TenYearsOfTestDrivenDevelopment)	ou	na
palestra	 do	 Steve	 Freeman	 e	Michael	 Feathers	 na	QCON	 de	 2009
(FEATHERS;	FREEMAN,	2009).
3.5	UM	POUCO	DA	HISTÓRIA	DE	TDD	 33
E-book gerado especialmente paraHenrique Pimentel - henriq.pimentel@gmail.com
FERREIRA	FALA
Duas	 histórias	 muito	 conhecidas	 cercam	 Kent	 Beck	 e	 o
nascimento	 dos	 primeiros	 frameworks	 de	 testes	 unitários.	 O
SUnit,	 para	 Smalltalk,	 não	 era	 um	 código	 distribuído	 em
arquivos	 da	 maneira	 usual.	 Beck	 na	 época	 atuava	 como
consultor	e	tinha	o	hábito	de	recriar	o	framework	junto	com	os
programadores	de	cada	cliente.	A	criação	do	 JUnit	 também	é
legendária:	a	primeira	versão	foi	desenvolvida	numa	sessão	de
programação	pareada	entre	o	Kent	Beck	e	o	Erich	Gamma	em
um	voo	Zurique-Atlanta.
Neste	 capítulo,	 apresentamos	 TDD	 e	 mostramos	 algumas	 das
vantagens	que	o	programador	obtém	ao	utilizá-la	no	seu	dia	a	dia.
Entretanto,	 é	 possível	 melhorar	 ainda	 mais	 a	 maneira	 na	 qual	 o
programador	faz	uso	da	prática.
Somente	praticando	TDD	com	esse	simples	exemplo,	é	possível
levantar	diversas	questões,	como:
Muitos	 cenários	 foram	 deixados	 para	 trás,	 como	 por
exemplo,	 a	 conversão	 de	 números	 como	 "CC",	 "MM"
etc.	Eles	devem	ser	escritos?
O	inverso	da	pergunta	anterior:	testes	para	"I",	"V",	"X"
devem	ser	considerados	diferentes	ou	repetidos?
E	quanto	à	repetição	de	código	dentro	de	cada	teste?	É
possível	 melhorar	 a	 qualidade	 de	 código	 do	 próprio
teste?
3.6	CONCLUSÃO
34	 3.6	CONCLUSÃO
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
A	ideia	de	sempre	fazer	o	teste	passar	da	maneira	mais
simples	possível	faz	sentido?	Deve	ser	aplicado	100%	do
tempo?
Existe	alguma	regra	para	dar	nomes	aos	testes?
Qual	o	momento	ideal	para	refatorar	o	código?
Se	 durante	 a	 implementação,	 um	 teste	 antigo,	 que
passava,	quebra,	o	que	devo	fazer?
Para	 que	 um	 desenvolvedor	 faça	 uso	 de	 TDD	 de	 maneira
profissional	e	produtiva,	estes	e	outros	pontos	devem	ser	discutidos
e	clarificados.	Nos	próximos	capítulos,	responderemos	a	cada	uma
dessas	perguntas,	usando	como	exemplo	um	sistema	razoavelmente
complexo	muito	similar	aos	encontrados	no	mundo	real.
3.6	CONCLUSÃO	 35
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
CAPÍTULO	4
No	 capítulo	 anterior,	 apresentamos	 TDD	 em	 um	 exemplo
complexo	 do	 ponto	 de	 vista	 algorítmico,	 mas	 bem	 controlado.
Mesmo	assim,	ele	foi	muito	útil	e	serviu	para	mostrar	os	passos	de
um	desenvolvedor	que	pratica	TDD.
O	 mundo	 real	 é	 mais	 complexo	 do	 que	 isso.	 Algoritmos
matemáticos	 são	 combinados	 e	 interagem	com	entidades	que	vêm
do	 banco	 de	 dados	 e	 são	 apresentados	 para	 o	 usuário	 através	 de
alguma	 interface.	 De	 agora	 em	 diante,	 os	 exemplos	 a	 serem
trabalhados	 serão	 outros	 e,	 com	 certeza,	 mais	 parecidos	 com	 a
realidade.
No	 mundo	 real,	 as	 coisas	 evoluem	 e	 mudam	 rapidamente.
Portanto,	nos	próximos	exemplos,	sempre	imagine	que	eles	ficarão
mais	complexos	e	evoluirão.
Suponha	 que	 uma	 empresa	 precise	 calcular	 o	 salário	 do
funcionário	e	seus	descontos.	Para	calcular	esse	desconto,	a	empresa
leva	 em	 consideração	 o	 salário	 atual	 e	 o	 cargo	 do	 funcionário.
Vamos	representar	funcionários	e	cargos	da	seguinte	maneira:
public	enum	Cargo	{
				DESENVOLVEDOR,
SIMPLICIDADE	E	BABY
STEPS
4.1	O	PROBLEMA	DO	CÁLCULO	DE	SALÁRIO
36	 4	SIMPLICIDADE	E	BABY	STEPS
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
				DBA,
				TESTADOR
}
public	class	Funcionario	{
				private	String	nome;
				private	double	salario;
				private	Cargo	cargo;
				public	Funcionario(String	nome,	double	salario,
								Cargo	cargo)	{
								this.nome	=	nome;
								this.salario	=	salario;
								this.cargo	=	cargo;
				}
				public	String	getNome()	{
								return	nome;
				}
				public	double	getSalario()	{
								return	salario;
				}
				public	Cargo	getCargo()	{
								return	cargo;
				}
}
Repare	 que	 um	 funcionário	 possui	 nome,	 salário	 e	 cargo.	 O
cargo	 é	 representado	 por	 uma	 enumeração.	 Nesse	 momento,	 a
enumeração	 contém	 apenas	 desenvolvedor,	 testador	 e	 DBA.	 Em
uma	 situação	 real,	 essa	 enumeração	 seria	 maior	 ainda,	 mas	 com
esses	3	já	gera	uma	boa	discussão.
As	regras	de	negócio	são	as	seguintes:
Desenvolvedores	 possuem	 20%	 de	 desconto	 caso	 seus
salários	 sejam	 maiores	 do	 que	 R$	 3000,0.	 Caso
contrário,	o	desconto	é	de	10%.
DBAs	 e	 testadores	 possuem	 desconto	 de	 25%	 se	 seus
4.1	O	PROBLEMA	DO	CÁLCULO	DE	SALÁRIO	 37
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
salários	 forem	 maiores	 do	 que	 R$	 2500,0.	 Em	 caso
contrário,	15%.
É	hora	de	implementar	essas	regras.	Uma	primeira	ideia	é	criar
uma	 classe	 	 CalculadoraDeSalario	 ,	 que	 recebe	 um
	Funcionario		e	retorna	o	salário	do	funcionário	com	o	desconto	já
subtraído.
O	primeiro	cenário	a	ser	testado	será	o	de	desenvolvedores	com
salários	menores	do	que	R$	3.000,00.	Sabemos	que	o	desconto	é	de
10%.	Portanto,	 se	o	desenvolvedor	ganhar	R$	1.500,00,	 seu	 salário
menos	desconto	deve	ser	de	R$	1350,00	(1500	*	90%):
public	class	CalculadoraDeSalarioTest	{
@Test
public	void	
deveCalcularSalarioParaDesenvolvedoresComSalarioAbaixoDoLimite()
{
				CalculadoraDeSalario	calculadora	=	
								new	CalculadoraDeSalario();
				Funcionario	desenvolvedor	=	new	Funcionario
								("Mauricio",	1500.0,	Cargo.DESENVOLVEDOR);
				double	salario	=	
								calculadora.calculaSalario(desenvolvedor);
				assertEquals(1500.0	*	0.9,	salario,	0.00001);
}
}
Hora	de	fazer	o	teste	passar.	Mas	lembre-se	de	que	a	ideia	é	fazer
o	 teste	 passar	 da	maneira	mais	 simples	 possível.	 Veja	 o	 código	 a
seguir:
public	class	CalculadoraDeSalario	{
4.2	 IMPLEMENTANDO	 DA	 MANEIRA	 MAIS
SIMPLES	POSSÍVEL
38	 4.2	IMPLEMENTANDO	DA	MANEIRA	MAIS	SIMPLES	POSSÍVEL
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
				public	double	calculaSalario(Funcionario	funcionario)	{
								return	1350.0;
				}
}
É	 possível	 ser	 mais	 simples	 do	 que	 isso?	 O	 código	 retorna
diretamente	 o	 valor	 esperado	 pelo	 teste!	 Isso	 é	 aceitável,	 pois	 o
código	ainda	não	está	finalizado.
Vamos	agora	ao	próximo	cenário:	desenvolvedores	que	ganham
mais	do	que	R$	3.000.0.	O	teste	é	bem	similar	ao	anterior:
@Test
public	void	
deveCalcularSalarioParaDesenvolvedoresComSalarioAcimaDoLimite(){
				CalculadoraDeSalario	calculadora	=
								new	CalculadoraDeSalario();
				Funcionario	desenvolvedor	=	new	Funcionario
								("Mauricio",	4000.0,	Cargo.DESENVOLVEDOR);
				double	salario	=	calculadora.calculaSalario(desenvolvedor);
				assertEquals(4000.0	*	0.8,	salario,	0.00001);
}
Novamente,	 fazemos	 o	 teste	 passar	 da	 maneira	 mais	 simples
possível.	Veja	o	código:
public	double	calculaSalario(Funcionario	funcionario)	{
				if(funcionario.getSalario()	>	3000)	return	3200.0;
				return	1350.0;
}
Um	simples		if		que	verifica	o	salário	do	funcionário	e	retorna
os	valores	esperados.	O	próximo	teste	agora	garante	que	DBAs	com
salários	inferior	a	R$	1.500,00	recebam	15%	de	desconto:
@Test
public	void
deveCalcularSalarioParaDBAsComSalarioAbaixoDoLimite(){
				CalculadoraDeSalario	calculadora	=
								new	CalculadoraDeSalario();
				Funcionario	dba	=	new	Funcionario
4.2	IMPLEMENTANDO	DA	MANEIRA	MAIS	SIMPLES	POSSÍVEL	 39
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
								("Mauricio",	500.0,	Cargo.DBA);
				double	salario	=	calculadora.calculaSalario(dba);
				assertEquals(500.0	*	0.85,	salario,	0.00001);
}
Para	 fazer	 esse	 teste	 passar	 da	 maneira	 mais	 simples,	 basta
novamente	colocar	um	outro		if	:
public	double	calculaSalario(Funcionario	funcionario)	{
				if(funcionario.getCargo().equals(Cargo.DESENVOLVEDOR))	{
								if(funcionario.getSalario()	>	3000)	return	3200.0;
								return	1350.0;}
				return	425.0;
}
Repare	 que,	 se	 for	 desenvolvedor,	 continuamos	 usando	 aquele
código	simples	que	escrevemos.	Caso	contrário,	 retornamos	425.0,
que	é	o	valor	esperado	para	o	salário	do	DBA.
Mas,	 antes	 de	 continuarmos,	 precisamos	 discutir	 sobre	 o
processo	utilizado	até	agora.
A	 ideia	 de	 sempre	 tomar	 o	 passo	 mais	 simples	 que	 resolva	 o
problema	 naquele	 momento	 (e	 faça	 o	 teste	 passar)	 é	 conhecido
pelos	 praticantes	 de	 TDD	 como	 baby	 steps.	 A	 vantagem	 desses
passos	 de	 bebê	 é	 tentar	 levar	 o	 desenvolvedor	 sempre	 ao	 código
mais	simples	e,	por	consequência,	mais	fácil	de	ser	compreendido	e
mantido	posteriormente.
O	 problema	 é	 que	 a	 ideia	 dos	 passos	 de	 bebê	 é	 muito	 mal
interpretada	por	muitos	praticantes.	Por	exemplo,	veja	que,	ao	final,
tínhamos	3	testes:	2	para	as	regras	do	desenvolvedor	e	1	para	a	regra
do	DBA.	E	a	implementação	final	gerada	até	então	era:
public	double	calculaSalario(Funcionario	funcionario)	{
4.3	PASSOS	DE	BEBÊ	(OU	BABY	STEPS)
40	 4.3	PASSOS	DE	BEBÊ	(OU	BABY	STEPS)
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
				if(funcionario.getCargo().equals(Cargo.DESENVOLVEDOR))	{
								if(funcionario.getSalario()	>	3000)	return	3200.0;
								return	1350.0;
				}
				return	425.0;
}
Repare	 que,	 a	 cada	 teste,	 nós	 implementamos	 a	modificação
mais	 simples	 (TDD	 prega	 por	 simplicidade),	 que	 era	 justamente
adicionar	 mais	 um	 	if		 e	 colocar	 o	 valor	 fixo	 que	 fazia	 o	 teste
passar.	Não	há	modificação	mais	simples	do	que	essa.
O	problema	 é	 que	 em	algum	momento	 fizemos	 tanto	 isso	que
nossa	 implementação	passou	 a	 ficar	muito	 longe	da	 solução	 ideal.
Veja	que,	dada	a	implementação	atual,	levá-la	para	a	solução	flexível
que	resolverá	o	problema	de	forma	correta	não	será	fácil.	O	código
ficou	complexo	sem	percebermos.
Generalizando	 o	 ponto	 levantado:	 o	 desenvolvedor,	 em	 vez	 de
partir	para	uma	solução	mais	abstrata	que	resolveria	o	problema	de
forma	 genérica,	 prefere	 ficar	 postergando	 a	 implementação	 final,
com	a	desculpa	de	estar	praticando	passos	de	bebê.
Imagine	isso	em	um	problema	do	mundo	real,	complexo	e	cheio
de	 casos	 excepcionais.	 Na	 prática,	 o	 que	 acontece	 é	 que	 o
programador	 gasta	 tanto	 tempo	 "contornando"	 a	 solução	 que
resolveria	 o	 problema	 de	 uma	 vez	 que,	 quando	 chega	 a	 hora	 de
generalizar	 o	 problema,	 ele	 se	 perde.	 Em	 sessões	 de	Coding	Dojo,
onde	os	programadores	se	juntam	para	praticar	TDD,	é	comum	ver
sessões	 que	 duram	 muito	 tempo	 e,	 ao	 final,	 os	 desenvolvedores
pouco	avançaram	no	problema.
Isso	é	simplesmente	uma	má	interpretação	do	que	são	passos	de
bebê.	 O	 desenvolvedor	 deve	 buscar	 pela	 solução	 mais	 simples,	 e
não	pela	modificação	mais	 simples.	Veja	 que	 a	modificação	mais
simples	não	é	necessariamente	a	solução	mais	simples.
4.3	PASSOS	DE	BEBÊ	(OU	BABY	STEPS)	 41
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
No	 começo,	 modificações	 mais	 simples	 podem	 ajudar	 o
desenvolvedor	 a	 pensar	melhor	 no	 problema	 que	 está	 resolvendo;
esse	 foi	 o	 caso	quando	 implementamos	o		return	1350.0	.	Mas,
caso	 o	 desenvolvedor	 continue	 somente	 implementando	 as
modificações	 mais	 simples,	 isso	 pode	 afastá-lo	 da	 solução	 mais
simples,	 que	 é	 o	 que	 o	 desenvolvedor	 deveria	 estar	 buscando	 ao
final.	 Isso	 pode	 ser	 exemplificado	 pela	 sequência	 de	 	 if	 	 que
fizemos	na	qual,	em	vez	de	partirmos	para	a	solução	correta	(igual
fizemos	 no	 capítulo	 anterior),	 optamos	 pela	 modificação	 mais
simples.
42	 4.3	PASSOS	DE	BEBÊ	(OU	BABY	STEPS)
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
CODING	DOJO
Um	coding	dojo	 é	 um	encontro	de	desenvolvedores	 que	 estão
interessados	 em	 aprender	 alguma	 coisa	 nova,	 como	 uma
linguagem	 de	 programação	 diferente,	 ou	 técnicas	 de
desenvolvimento	 diferentes.	 O	 objetivo	 é	 criar	 um	 ambiente
tranquilo	e	favorável	a	novos	aprendizados.
A	 prática	 mais	 comum	 é	 juntar	 alguns	 desenvolvedores	 e
projetar	 uma	 máquina	 na	 parede.	 Dois	 desenvolvedores
sentam	em	frente	ao	computador	e	começam	a	resolver	algum
problema	predeterminado,	usando	a	 linguagem	e/ou	a	prática
que	desejam	aprender	melhor.
Geralmente	 esses	 dois	 desenvolvedores	 têm	 apenas	 alguns
minutos	 para	 trabalhar.	 Enquanto	 eles	 trabalham,	 a	 plateia
assiste	 e	 eventualmente	 sugere	 alterações	 para	 o	 "piloto	 e
copiloto".	 Ao	 final	 do	 tempo	 (geralmente	 7	 minutos),	 o
copiloto	vira	piloto,	o	piloto	volta	para	a	plateia,	 e	alguém	da
plateia	se	torna	"copiloto".
Você	 pode	 ler	 mais	 sobre	 coding	 dojos,	 diferentes	 estilos,
problemas	sugeridos	nas	mais	diversas	referências	na	Internet
(http://www.codingdojo.org).
Veja	 as	 figuras	 a	 seguir.	 Nela	 temos	 o	 código	 e	 as	 possíveis
soluções	 para	 o	 problema.	Dentro	 desse	 conjunto,	 existem	 as	 que
são	resolvidas	pelas	mudanças	mais	simples,	que	podem,	ou	não,	ser
a	solução	mais	simples	também	para	o	problema:
4.3	PASSOS	DE	BEBÊ	(OU	BABY	STEPS)	 43
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
Se	o	desenvolvedor	continuamente	opta	pela	modificação	mais
simples	 que	 não	 é	 a	 solução	mais	 simples,	 isso	 só	 vai	 afastá-lo	 da
melhor	solução:
44	 4.3	PASSOS	DE	BEBÊ	(OU	BABY	STEPS)
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
4.3	PASSOS	DE	BEBÊ	(OU	BABY	STEPS)	 45
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
Em	 nosso	 exemplo,	 veja	 que	 a	 solução	 mais	 simples	 acabou
sendo	o	uso	de		if	s.	Sabemos	que	todo	condicional	faz	o	código	ser
mais	difícil	de	ser	mantido	e	de	ser	testado.	Sabemos	que	essa	não	é
a	melhor	solução	para	o	problema;	o	uso	de	polimorfismo	seria	mais
adequado.	Nesse	problema	específico,	discutiremos	como	resolvê-lo
da	melhor	forma	nos	capítulos	posteriores.
Novamente,	 resumindo	 a	 discussão:	 a	mudança	mais	 simples
para	resolver	um	problema	não	é	necessariamente	a	solução	mais
simples	para	resolvê-lo.
Os	 passos	 de	 bebê	 servem	 para	 ajudar	 o	 desenvolvedor	 a
entender	melhor	o	problema	e	diminuir	o	passo	caso	ele	não	se	sinta
confortável	 com	 o	 problema	 que	 está	 resolvendo.	 Se	 o
desenvolvedor	está	implementando	um	trecho	de	código	complexo
e	 tem	 dúvidas	 sobre	 como	 fazê-lo,	 ele	 pode	 desacelerar	 e	 fazer
implementações	 mais	 simples.	 Mas	 caso	 esteja	 seguro	 sobre	 o
problema,	 ele	 pode	 tomar	 passos	 maiores	 e	 ir	 direto	 para	 uma
implementação	mais	abstrata.
O	próprio	Kent	Beck	comenta	sobre	 isso	em	seu	 livro.	Em	seu
exemplo,	 ele	 implementa	 uma	 classe		Dinheiro	,	 responsável	 por
representar	uma	unidade	monetária	e	 realizar	operações	 sobre	ela.
No	 começo,	 ele	 toma	 passos	 simplórios,	 como	 os	 feitos
anteriormente,	mas	 finaliza	 o	 capítulo	 dizendo	 que	 ele	 não	 toma
passos	 pequenos	 o	 tempo	 todo;	 mas	 que	 fica	 feliz	 por	 poder
tomá-los	quando	necessário.
46	 4.3	PASSOS	DE	BEBÊ	(OU	BABY	STEPS)
E-book gerado especialmente para Henrique Pimentel - henriq.pimentel@gmail.com
CÓDIGO	 DUPLICADO	 ENTRE	 O	 CÓDIGO	 DE	 TESTE	 E	 O	 CÓDIGO	 DE
PRODUÇÃO
Todo	 desenvolvedor	 sabe	 que	 deve	 refatorar	 qualquer
duplicidade	 de	 código	 no	 momento	 que	 a	 encontrar.	 No
próprio	 problema	 da	 soma,	 a	 duplicidade	 já	 aparece	 logo	 no
primeiro	 teste:	 repare	 que	 o	 "1",	 "2"	 existentes	 no	 código	 de
testes	está	duplicado	com	o	"I"	e	"II"	no	código	de	produção.
É	fácil	ver	que	cada	"I",	adiciona	1	no	número	final.	Sim,	você
deve	 ficar	atento	com	duplicidade	de	código	entre	a	classe	de
teste	 e	 a	 classe	 de	 produção.	 Nesse	 caso,	 após	 o	 teste	 ficar
verde,	 o	 desenvolvedor	 poderia	 já	 refatorar	 o	 código

Continue navegando