TDD NA PRÁTICA
Desenvolvimento Orientado a Testes

Rafael Fuchs
agenda
•
•
•
•
•
•
•
•
•
•
•

introdução a TDD
design emergente
tipos de testes
mais sobre TDD
exemplos
dificuldades
acoplamento/coesão
mocks/stubs
ferramentas
revisão
referências
introdução a TDD
•
•
•
•
•
•
•
•

Test Driven Development
Desenvolvimento Orientado a Testes
1999 – Kent Beck + XP
princípio de test first
2003 – TDD: by Example
técnica de desenvolvimento
não é sobre escrever testes
mas por que TDD???
red > green > refactor
adicione
UM teste
que FALHE

TDD
refatore!

adicione
código
para teste
PASSAR
tipos de teste - escopo
unit testing
integration testing
system testing
system integration testing
tipos de teste - objetivo
smoke
regressão
aceitação
alpha
beta
tipos de teste – não funcional
performance
carga
usabilidade
segurança
...
automatizado vs. unitário
unitário
• direcionado: testa uma condição específica em um
métodos específico
• isolado: o código sendo testado não pode ter
dependência externa
• repetível e previsível: deve ser capaz de ser roda várias
vezes e produzir sempre o mesmo resultado
• independente: não podemos garantir a ordem dos
testes – seus testes devem funcionar e ter o mesmo
comportamento se rodados em qualquer ordem

automatizado
• …
TDD
• Escreva um teste que falhe antes de escrever
qualquer outro codigo (red)
• Escreve o mínimo de código possível para
fazer esse teste passar
• Refatore...
• Repita o processo
adicione
UM
teste
que
FALHE

TDD
refatore!

adicione
código
para
teste
PASSAR
TDD
• objetivo simples:
– programar algo que satisfaça uma condição

• baby steps
• primeiro teste: chama algo que não existe
• rascunho do seu código
TDD
•
•
•
•
•

design/arquitetura emergente
mais coesão, menos acoplamento
isolamento de erros
modularização
não é solução para todos os problemas do
mundo
red > green > refactor
adicione
UM teste
que FALHE

TDD
refatore!

adicione
código
para teste
PASSAR
as 3 leis do TDD
1. Você não pode escrever código de produção a menos
que ele tenha um teste que falhe.
2. Você não pode escrever mais teste que o suficiente
para falhar – erros de compilação são falhas.
3. Você não pode escrever mais código que o suficiente
para o código de produção passar em um teste.

(Martin Fowler, 2011)
TDD - vantagens
•
•
•
•
•
•
•
•
•

melhor entendimento dos requisitos
garantir testes
maior qualidade de código
maior simplicidade
menos código
melhor uso OOP
menos defeitos
gera exemplos de uso
menos debug
Página 1/329
TDD - vantagens
•
•
•
•
•
•
•
•

maior confiança
manutenção mais fácil
menor custo de mudança
eliminar dead code/código parasita
evitar erros de regressão
maior cobertura
acaba quando termina
feedback constante
Página 2/329
TDD - vantagens

Página 3/329
TDD - vantagens

Página 4/329
TDD - estudos
•
•
•
•
•
•
•
•
•
•

Redução de 40-50% na quantidade de defeitos
87% - facilitou o entendimentos dos requisitos
96% - reduziu o tempo gasto com debug
78% - aumentou a produtividade
50% - ajuda a diminuir o tempo de desenvolvimento
92% - ajuda a manter um código de maior qualidade
79% - promove um design mais simples
104% - menos acoplamento
43% - métodos menos complexos
cobertura entre 92% - 98%
Página 5/329
TDD - desvantagens
•
•
•
•
•
•
•
•

testes viciados
falsa sensação de segurança
suporte gerencial / alta administração
mau uso
muita integração externa
curva de aprendizagem
atrapalha linha de pensamento
banco de dados
TDD - dificuldades
onde começar?
o que testar?
quando parar?
CUIDADO!!!
getters/setters
delegação

acesso a sistemas externos
(banco, file system, ws, etc)
pode-se garatir qualidade de outra formas
exemplo 01 - soma
Classe com método simples para somar 2 inteiros.
Adicionar um teste
public class TesteSoma extends TestCase {
@Test
public void testSomaUmMaisUm() {
assertEquals(2, Calc.soma(1,1));
}
}

FALHA! Não compila!
Escrever código para teste passar
public class Calc {
static public int soma(int a, int b) {
return 2;
}
}
public class TesteSoma extends TestCase {
@Test
public void testSomaUmMaisUm() {
assertEquals(2, Calc.soma(1,1));
}
}

Compila e o teste passa!
Adicionar um teste – código já é simples e claro
public class Calc {
static public int soma(int a, int b) {
return 2;
}
}
public class TesteSoma extends TestCase {
[...]
@Test
public void testSomaDoisMaisTres() {
assertEquals(5, Calc.soma(2,3);
}
}

FALHA!
Escrever código para teste passar
public class Calc {
static public int soma(int a, int b) {
if (a==2 && b==3) return 5;
return 2;
}
}
public class TesteSoma extends TestCase {
@Test
public void testSomaUmMaisUm() {
assertEquals(2, Calc.soma(1,1));
}
@Test
public void testSomaDoisMaisTres() {
assertEquals(5, Calc.soma(2,3);
}
}

Teste passa!
Agora sim: Refatorar!
public class Calc {
static public int soma(int a, int b) {
return a + b;
}
}
public class TesteSoma extends TestCase {
@Test
public void testSomaUmMaisUm() {
assertEquals(2, Calc.soma(1,1));
}
@Test
public void testSomaDoisMaisTres() {
assertEquals(5, Calc.soma(2,3);
}
}

Teste continua passando… tudo certo!
exemplo 02 – Crivo de Eratóstenes
Crivo de Eratóstenes: algoritmo para gerar números primos

0-1-2-3-4-5-6-7-8-9-10
Em seguida o algoritmo elimina os números 0 e 1 por não serem primos:
2-3-4-5-6-7-8-9-10
Começando pelo número 2, elimina-se cada um dos seus múltiplos, com exceção dele próprio
(que é primo).
2-3-5-7-9
Avançando para o próximo número ainda não eliminado, que é 3, o algoritmo elimina cada um de
seus múltiplos com exceção dele próprio.
2-3-5-7
O processo é repetido até se alcançar o número máximo informado. No caso do exemplo
acima, os passos executados já foram suficientes para identificar todos os primos até 10.
Fonte:
http://desenvolvimentoagil.com.br/xp/praticas/tdd/
Iniciamos pelo teste...

E rodamos o teste sem código.
Obviamente vai falhar...
Nosso teste:

Escrevemos um código mínimo
Para fazer o teste passar.
Código mínimo mesmo.
Adicionamos um teste... Que falha.

E escrevemos código para o teste passar...
Então refatoramos nosso código... Testes e código de produção
Mais um pouco de refatoração,
sempre rodando os testes para garantir o bom funcionamento.
Após algumas rodadas de refatoração... O algoritmo completo.
Mais alguns testes – e agora todos devem passar...
design/arquitetura emergente
(evolutivo, orgânico)
pequenos pedaços de software
evitar trabalho antecipado
último momento responsável
modelo tradicional:
preguiça de mudar mais tarde
mocks e stubs
•
•
•
•

simular estado/comportamento
sistemas/bibliotecas externos
banco de dados
stubs: nos preocupamos em testar o estado dos
objetos após a execução do método. Neste caso
incluimos os asserts para ver se o método nos levou ao
estado que esperamos.
• mocks: testar a interação entre objetos e o
comportamento do objeto durante a execução do
método. Neste caso, os asserts servem para ver se os
métodos se relacionaram como o esperado.
exemplo de jMockit
setup e testando exceção
exemplo de jMockit
teste simples
coesão e acoplamento
coesão
• responsabilidade unica
uma classe deve ter uma unica responsabilidade
• maior modularização e reuso
• muitos testes para um metodo/classe

acomplamento
• dependência de outras classes
• inversão de controle e injeção de dependência
• muitos mocks/stubs
ferramentas
• testes unitários
– jUnit (http://junit.org/)
– xUnit (http://xunit.codeplex.com/)

• mocks
–
–
–
–
–

Mockito (https://code.google.com/p/mockito/)
jMockit (https://code.google.com/p/jmockit/)
jMock (http://jmock.org/)
EasyMock (http://easymock.org/)
moq (https://code.google.com/p/moq/)

• cobertura
– Cobertura (http://cobertura.github.io/cobertura/)
– EMMA (http://emma.sourceforge.net/)
retomando...
•
•
•
•
•
•
•
•
•

red > green > refactor
tipos de testes
testes automatizados vs. unitários
baby steps
design emergente
mocks/stubs
coesão/acomplamento
ferramentas
refatore!
cobertura

adicione
UM
teste que
FALHE

TDD

adicione
código
para teste
PASSAR
livros
• Refactoring: Improving the Design of Existing Code
(Martin Fowler)
http://www.amazon.com/exec/obidos/ASIN/0201485672

• Test Driven Development: By Example (Kent Beck)
http://www.amazon.com/exec/obidos/asin/0321146530/

• Extreme Programming Explained: Embrace Change (Kent
Beck)
http://www.amazon.com/Extreme-Programming-Explained-Embrace-Edition/dp/0321278658/ref=pd_sim_b_3
obrigado!
perguntas?

Rafael Fuchs
rafael.fuchs@adp.com
@rafaelfuchs

TDD na Prática

  • 1.
    TDD NA PRÁTICA DesenvolvimentoOrientado a Testes Rafael Fuchs
  • 2.
    agenda • • • • • • • • • • • introdução a TDD designemergente tipos de testes mais sobre TDD exemplos dificuldades acoplamento/coesão mocks/stubs ferramentas revisão referências
  • 3.
    introdução a TDD • • • • • • • • TestDriven Development Desenvolvimento Orientado a Testes 1999 – Kent Beck + XP princípio de test first 2003 – TDD: by Example técnica de desenvolvimento não é sobre escrever testes mas por que TDD???
  • 4.
    red > green> refactor adicione UM teste que FALHE TDD refatore! adicione código para teste PASSAR
  • 5.
    tipos de teste- escopo unit testing integration testing system testing system integration testing
  • 6.
    tipos de teste- objetivo smoke regressão aceitação alpha beta
  • 7.
    tipos de teste– não funcional performance carga usabilidade segurança ...
  • 8.
    automatizado vs. unitário unitário •direcionado: testa uma condição específica em um métodos específico • isolado: o código sendo testado não pode ter dependência externa • repetível e previsível: deve ser capaz de ser roda várias vezes e produzir sempre o mesmo resultado • independente: não podemos garantir a ordem dos testes – seus testes devem funcionar e ter o mesmo comportamento se rodados em qualquer ordem automatizado • …
  • 9.
    TDD • Escreva umteste que falhe antes de escrever qualquer outro codigo (red) • Escreve o mínimo de código possível para fazer esse teste passar • Refatore... • Repita o processo adicione UM teste que FALHE TDD refatore! adicione código para teste PASSAR
  • 10.
    TDD • objetivo simples: –programar algo que satisfaça uma condição • baby steps • primeiro teste: chama algo que não existe • rascunho do seu código
  • 11.
    TDD • • • • • design/arquitetura emergente mais coesão,menos acoplamento isolamento de erros modularização não é solução para todos os problemas do mundo
  • 12.
    red > green> refactor adicione UM teste que FALHE TDD refatore! adicione código para teste PASSAR
  • 13.
    as 3 leisdo TDD 1. Você não pode escrever código de produção a menos que ele tenha um teste que falhe. 2. Você não pode escrever mais teste que o suficiente para falhar – erros de compilação são falhas. 3. Você não pode escrever mais código que o suficiente para o código de produção passar em um teste. (Martin Fowler, 2011)
  • 14.
    TDD - vantagens • • • • • • • • • melhorentendimento dos requisitos garantir testes maior qualidade de código maior simplicidade menos código melhor uso OOP menos defeitos gera exemplos de uso menos debug Página 1/329
  • 15.
    TDD - vantagens • • • • • • • • maiorconfiança manutenção mais fácil menor custo de mudança eliminar dead code/código parasita evitar erros de regressão maior cobertura acaba quando termina feedback constante Página 2/329
  • 16.
  • 17.
  • 18.
    TDD - estudos • • • • • • • • • • Reduçãode 40-50% na quantidade de defeitos 87% - facilitou o entendimentos dos requisitos 96% - reduziu o tempo gasto com debug 78% - aumentou a produtividade 50% - ajuda a diminuir o tempo de desenvolvimento 92% - ajuda a manter um código de maior qualidade 79% - promove um design mais simples 104% - menos acoplamento 43% - métodos menos complexos cobertura entre 92% - 98% Página 5/329
  • 19.
    TDD - desvantagens • • • • • • • • testesviciados falsa sensação de segurança suporte gerencial / alta administração mau uso muita integração externa curva de aprendizagem atrapalha linha de pensamento banco de dados
  • 20.
    TDD - dificuldades ondecomeçar? o que testar? quando parar?
  • 21.
    CUIDADO!!! getters/setters delegação acesso a sistemasexternos (banco, file system, ws, etc) pode-se garatir qualidade de outra formas
  • 22.
    exemplo 01 -soma Classe com método simples para somar 2 inteiros. Adicionar um teste public class TesteSoma extends TestCase { @Test public void testSomaUmMaisUm() { assertEquals(2, Calc.soma(1,1)); } } FALHA! Não compila!
  • 23.
    Escrever código parateste passar public class Calc { static public int soma(int a, int b) { return 2; } } public class TesteSoma extends TestCase { @Test public void testSomaUmMaisUm() { assertEquals(2, Calc.soma(1,1)); } } Compila e o teste passa!
  • 24.
    Adicionar um teste– código já é simples e claro public class Calc { static public int soma(int a, int b) { return 2; } } public class TesteSoma extends TestCase { [...] @Test public void testSomaDoisMaisTres() { assertEquals(5, Calc.soma(2,3); } } FALHA!
  • 25.
    Escrever código parateste passar public class Calc { static public int soma(int a, int b) { if (a==2 && b==3) return 5; return 2; } } public class TesteSoma extends TestCase { @Test public void testSomaUmMaisUm() { assertEquals(2, Calc.soma(1,1)); } @Test public void testSomaDoisMaisTres() { assertEquals(5, Calc.soma(2,3); } } Teste passa!
  • 26.
    Agora sim: Refatorar! publicclass Calc { static public int soma(int a, int b) { return a + b; } } public class TesteSoma extends TestCase { @Test public void testSomaUmMaisUm() { assertEquals(2, Calc.soma(1,1)); } @Test public void testSomaDoisMaisTres() { assertEquals(5, Calc.soma(2,3); } } Teste continua passando… tudo certo!
  • 27.
    exemplo 02 –Crivo de Eratóstenes Crivo de Eratóstenes: algoritmo para gerar números primos 0-1-2-3-4-5-6-7-8-9-10 Em seguida o algoritmo elimina os números 0 e 1 por não serem primos: 2-3-4-5-6-7-8-9-10 Começando pelo número 2, elimina-se cada um dos seus múltiplos, com exceção dele próprio (que é primo). 2-3-5-7-9 Avançando para o próximo número ainda não eliminado, que é 3, o algoritmo elimina cada um de seus múltiplos com exceção dele próprio. 2-3-5-7 O processo é repetido até se alcançar o número máximo informado. No caso do exemplo acima, os passos executados já foram suficientes para identificar todos os primos até 10. Fonte: http://desenvolvimentoagil.com.br/xp/praticas/tdd/
  • 28.
    Iniciamos pelo teste... Erodamos o teste sem código. Obviamente vai falhar...
  • 29.
    Nosso teste: Escrevemos umcódigo mínimo Para fazer o teste passar. Código mínimo mesmo.
  • 30.
    Adicionamos um teste...Que falha. E escrevemos código para o teste passar...
  • 31.
    Então refatoramos nossocódigo... Testes e código de produção
  • 32.
    Mais um poucode refatoração, sempre rodando os testes para garantir o bom funcionamento.
  • 33.
    Após algumas rodadasde refatoração... O algoritmo completo.
  • 34.
    Mais alguns testes– e agora todos devem passar...
  • 35.
    design/arquitetura emergente (evolutivo, orgânico) pequenospedaços de software evitar trabalho antecipado último momento responsável modelo tradicional: preguiça de mudar mais tarde
  • 36.
    mocks e stubs • • • • simularestado/comportamento sistemas/bibliotecas externos banco de dados stubs: nos preocupamos em testar o estado dos objetos após a execução do método. Neste caso incluimos os asserts para ver se o método nos levou ao estado que esperamos. • mocks: testar a interação entre objetos e o comportamento do objeto durante a execução do método. Neste caso, os asserts servem para ver se os métodos se relacionaram como o esperado.
  • 37.
    exemplo de jMockit setupe testando exceção
  • 38.
  • 39.
    coesão e acoplamento coesão •responsabilidade unica uma classe deve ter uma unica responsabilidade • maior modularização e reuso • muitos testes para um metodo/classe acomplamento • dependência de outras classes • inversão de controle e injeção de dependência • muitos mocks/stubs
  • 40.
    ferramentas • testes unitários –jUnit (http://junit.org/) – xUnit (http://xunit.codeplex.com/) • mocks – – – – – Mockito (https://code.google.com/p/mockito/) jMockit (https://code.google.com/p/jmockit/) jMock (http://jmock.org/) EasyMock (http://easymock.org/) moq (https://code.google.com/p/moq/) • cobertura – Cobertura (http://cobertura.github.io/cobertura/) – EMMA (http://emma.sourceforge.net/)
  • 41.
    retomando... • • • • • • • • • red > green> refactor tipos de testes testes automatizados vs. unitários baby steps design emergente mocks/stubs coesão/acomplamento ferramentas refatore! cobertura adicione UM teste que FALHE TDD adicione código para teste PASSAR
  • 42.
    livros • Refactoring: Improvingthe Design of Existing Code (Martin Fowler) http://www.amazon.com/exec/obidos/ASIN/0201485672 • Test Driven Development: By Example (Kent Beck) http://www.amazon.com/exec/obidos/asin/0321146530/ • Extreme Programming Explained: Embrace Change (Kent Beck) http://www.amazon.com/Extreme-Programming-Explained-Embrace-Edition/dp/0321278658/ref=pd_sim_b_3
  • 43.