28
Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman

Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman

Embed Size (px)

Citation preview

Page 1: Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman

Exemplo de desenvolvimento com testes

(JUNIT - estudo de caso)

Alfredo Goldman

Page 2: Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman

Problema com testesTodos sabem: devem ser escritos;Poucos o fazem, e por quê não ?

Estou com muita pressaMas, isto cria um círculo vicioso:

menos testesmenos produtividademenos estabilidade

mais pressão

Page 3: Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman

Como quebrar este cicloCriando um ambiente simples de testesDepois de fazer os primeiros testes

o hábito vem para ficar

Vamos mostrar como seria um desenvolvimento ideal.... Através do JUnit...

Page 4: Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman

O programaUm sistema para representar

diversas moedas;

Para começar: algo simples.

Page 5: Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman

class Money { private int fAmount; private String fCurrency;

public Money(int amount, String currency) { fAmount = amount; fCurrency = currency; }

public int amount() { return fAmount; }

public String currency() { return fCurrency; }}

Page 6: Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman

Para somar dois Moneys da mesma moeda (currency):

public Money add(Money m) { return new Money(amount()+m.amount(), currency());}

Page 7: Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman

Questão de hábitoCode a little, test a little, code a little,

test a little....

Já temos um objeto, vamos testá-lo !!

No JUnit os testes devem ser subclasses de TestCase

Page 8: Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman

public class MoneyTest extends TestCase { //… public void testSimpleAdd() { Money m12CHF= new Money(12, "CHF"); // (1) Money m14CHF= new Money(14, "CHF"); Money expected= new Money(26, "CHF"); Money result= m12CHF.add(m14CHF); // (2) Assert.assertTrue(expected.equals(result)); // (3) }}

O testSimpleAdd() consiste em:

Código para criar os objetos;

Código para usar os objetos;

Código para verificar os resultados.

Falta fazer a sobrecarga de equals

Page 9: Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman

public void testEquals() { Money m12CHF= new Money(12, "CHF"); Money m14CHF= new Money(14, "CHF");

Assert.assertTrue(!m12CHF.equals(null)); Assert.assertEquals(m12CHF, m12CHF); Assert.assertEquals(m12CHF, new Money(12, "CHF")); // (1) Assert.assertTrue(!m12CHF.equals(m14CHF));}

// lembrete: o equals do object volta true se os// objetos comparados são o mesmo.

Mas antes um teste para o equals

Page 10: Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman

Agora sim

public boolean equals(Object anObject) { if (anObject instanceof Money) { Money aMoney = (Money) anObject; return aMoney.currency().equals(currency()) && amount() == aMoney.amount(); } return false;}// faltou sobrecarregar o método hashCode...

Page 11: Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman

Mas, já apesar dos testes serem pequenos já há código duplicado...

public class MoneyTest extends TestCase { private Money f12CHF; private Money f14CHF;

protected void setUp() { f12CHF= new Money(12, "CHF"); f14CHF= new Money(14, "CHF"); }}

Page 12: Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman

Agora os testes podem ser rescritos como:

public void testEquals() { assert(!f12CHF.equals(null)); assertEquals(f12CHF, f12CHF); assertEquals(f12CHF, new Money(12, "CHF")); assert(!f12CHF.equals(f14CHF));}

public void testSimpleAdd() { Money expected= new Money(26, "CHF"); Money result= f12CHF.add(f14CHF); assert(expected.equals(result));}

Page 13: Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman

Próximos passosDefinir como rodar um teste

individual;

Definir como rodar uma seqüência de testes.

Page 14: Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman

// forma estática, com classe interior

TestCase test= new MoneyTest("simple add") { public void runTest() { testSimpleAdd(); }};

// forma dinâmica, usa reflexão

TestCase test= new MoneyTest("testSimpleAdd");

Page 15: Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman

Pode-se automatizar testes Criando uma seqüência de testes

public static Test suite() { TestSuite suite= new TestSuite(); suite.addTest(new MoneyTest("testEquals")); suite.addTest(new MoneyTest("testSimpleAdd")); return suite;}

Page 16: Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman

Pode-se automatizar testes Ou apenas:

public static Test suite() {return new TestSuite(MoneyTest.class);}

Agora, um pouco de JUnit na prática.

Page 17: Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman

Continuando o projetoDeve-se poder guardar diversos tipos de moeda

class MoneyBag { private Vector fMoneis= new Vector();

MoneyBag(Money m1, Money m2) { appendMoney(m1); appendMoney(m2); }

MoneyBag(Money bag[]) { for (int i= 0; i < bag.length; i++) appendMoney(bag[i]); }}

Page 18: Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman

protected void setUp() { f12CHF= new Money(12, "CHF"); f14CHF= new Money(14, "CHF"); f7USD= new Money( 7, "USD"); f21USD= new Money(21, "USD"); fMB1= new MoneyBag(f12CHF, f7USD); fMB2= new MoneyBag(f14CHF, f21USD);}

Para os testes deve se criar também objetos do novo tipo

Page 19: Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman

public void testBagEquals() { assert(!fMB1.equals(null)); assertEquals(fMB1, fMB1); assert(!fMB1.equals(f12CHF)); assert(!f12CHF.equals(fMB1)); assert(!fMB1.equals(fMB2));}

Devem se criar novos testes, mas os testes antigos continuam lá

E devem continuar funcionando...

Page 20: Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman

public Money add(Money m) { if (m.currency().equals(currency()) ) return new Money(amount() + m.amount(), currency()); return new MoneyBag(this, m);}// ops MoneyBag != Money....

Agora podemos melhorar o método add

Agora existem duas representações de dinheiro...

interface IMoney { public abstract IMoney add(IMoney aMoney); //…}

Page 21: Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman

Mas, ainda não temos testes para tipos mistos...

public void testMixedSimpleAdd() { // [12 CHF] + [7 USD] == {[12 CHF][7 USD]} Money bag[]= { f12CHF, f7USD }; MoneyBag expected= new MoneyBag(bag); assertEquals(expected, f12CHF.add(f7USD)); }Os outros testes seguem o mesmo padrão:

testBagSimpleAdd - soma MoneyBag com Money testSimpleBagAdd - soma Money com MoneyBag testBagBagAdd - soma dois MoneyBags

Page 22: Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman

Mais testes estão disponíveis:

public static Test suite() { TestSuite suite= new TestSuite(); suite.addTest(new MoneyTest("testMoneyEquals")); suite.addTest(new MoneyTest("testBagEquals")); suite.addTest(new MoneyTest("testSimpleAdd")); suite.addTest(new MoneyTest("testMixedSimpleAdd")); suite.addTest(new MoneyTest("testBagSimpleAdd")); suite.addTest(new MoneyTest("testSimpleBagAdd")); suite.addTest(new MoneyTest("testBagBagAdd")); return suite;}

Agora sim vamos implementá-los...

Page 23: Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman

class Money implements IMoney { public IMoney add(IMoney m) { return m.addMoney(this); } //…}class MoneyBag implements IMoney { public IMoney MoneyBag.add(IMoney m) { return m.addMoneyBag(this); } //…}

//… IMoney addMoney(Money aMoney); IMoney addMoneyBag(MoneyBag aMoneyBag);}

Page 24: Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman

Em Money.

public IMoney addMoney(Money m) { if (m.currency().equals(currency())) return new Money(amount()+m.amount(), currency()); return new MoneyBag(this, m);}

public IMoney addMoneyBag(MoneyBag s) { return s.addMoney(this);}

Page 25: Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman

Em MoneyBag.

public IMoney addMoney(Money m) { return new MoneyBag(m, this);}

public IMoney addMoneyBag(MoneyBag s) { return new MoneyBag(s, this);}

Surge um problema.... E se retira-se 12CHF de um MoneyBag com12CHF ???

Page 26: Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman

Primeiro o teste...

public void testSimplify() { // {[12 CHF][7 USD]} + [-12 CHF] == [7 USD] Money expected= new Money(7, "USD"); assertEquals(expected, fMS1.add(new Money(-12, "CHF")));}

Page 27: Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman

Depois o código.

public IMoney addMoney(Money m) { return (new MoneyBag(m, this)).simplify();}

public IMoney addMoneyBag(MoneyBag s) { return (new MoneyBag(s, this)).simplify();}

private IMoney simplify() { if (fMonies.size() == 1) return (IMoney)fMonies.firstElement() return this;}

Page 28: Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman

Desenvolvimento com testesTestes devem ser escritos assim que

possível;Testes devem ser adaptados segundo

as mudanças;Deixe os testes antigos rodando;Quando surgem novas idéias (simplify),

crie testes, veja se funcionam, e se necessário altere o código.