A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

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

Apresentações semelhantes


Apresentação em tema: "Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman."— Transcrição da apresentação:

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

2 Problema com testes zTodos sabem: devem ser escritos; zPoucos o fazem, e por quê não ? yEstou com muita pressa zMas, isto cria um círculo vicioso: menos testes menos produtividade menos estabilidade mais pressão

3 Como quebrar este ciclo zCriando um ambiente simples de testes zDepois de fazer os primeiros testes yo hábito vem para ficar zVamos mostrar como seria um desenvolvimento ideal.... yAtravés do JUnit...

4 O programa zUm sistema para representar diversas moedas; zPara começar: algo simples.

5 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; }

6 Para somar dois Moneys da mesma moeda (currency): public Money add(Money m) { return new Money(amount()+m.amount(), currency()); }

7 Questão de hábito zCode a little, test a little, code a little, test a little.... zJá temos um objeto, vamos testá-lo !! zNo JUnit os testes devem ser subclasses de TestCase

8 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)assertTrue } 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

9 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

10 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...

11 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() {setUp f12CHF= new Money(12, "CHF"); f14CHF= new Money(14, "CHF"); }

12 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)); }

13 Próximos passos zDefinir como rodar um teste individual; zDefinir como rodar uma seqüência de testes.

14 // 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");

15 Pode-se automatizar testes zCriando 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; }

16 Pode-se automatizar testes zOu apenas: public static Test suite() { return new TestSuite(MoneyTest.class); } Agora, um pouco de JUnit na prática.

17 Continuando o projeto Deve-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]); }

18 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

19 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...

20 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); //… }

21 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

22 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...

23 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); }

24 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); }

25 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 com 12CHF ???

26 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"))); }

27 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; }

28 Desenvolvimento com testes zTestes devem ser escritos assim que possível; zTestes devem ser adaptados segundo as mudanças; zDeixe os testes antigos rodando; zQuando surgem novas idéias (simplify), crie testes, veja se funcionam, e se necessário altere o código.


Carregar ppt "Exemplo de desenvolvimento com testes (JUNIT - estudo de caso) Alfredo Goldman."

Apresentações semelhantes


Anúncios Google