ferramentas testes2003
DESCRIPTION
teste slideTRANSCRIPT
Exemplo de desenvolvimento com testes
Prof. Dr. Alfredo Goldman
Departamento de Ciência da ComputaçãoIME / USP
3 de Abril de 2003VI Semana da Computação
03/04/2003 VI Semana da Computação
Problema com testes
Todos sabem: devem ser escritos;Poucos o fazem, e por quê não ?
Estou com muita pressaMas, isto cria um círculo vicioso:
menos testes
menos produtividademenos estabilidade
mais pressão
03/04/2003 VI Semana da Computação
Como quebrar este ciclo
Criando um ambiente simples de testesDepois de fazer os primeiros testes
o hábito vem para ficarVamos mostrar como seria um
desenvolvimento ideal.... Através do JUnit...
Mas, antes uma visão geral:
03/04/2003 VI Semana da Computação
JUnit - como funciona ?
Arcabouço Java para testes de unidade API para construir testes
Classes básicas: Test, TestCase, TestSuite,...Usam-se métodos tipo premissa:
• assertTrue(), assertEquals, fail(), ...
API para a execução de testes (TestRunners)Modo textoModo gráfico
03/04/2003 VI Semana da Computação
Junit - origens e uso
Criado por K. Beck e E. GammaPadrão para testes em JavaPermite a execução automática de
testes Executa os testes de forma silenciosa
Dirigido a testes de unidade Métodos Pode-se agrupar diversos testes
03/04/2003 VI Semana da Computação
Exemplo de uso
Padrão use o método testXxx() para testar o método xxx()
Utilize os métodos da classe TestCase assertEquals( objeto1, objeto2); assertTrue( varBool); assertNotNull( objeto); fail();
03/04/2003 VI Semana da Computação
JUnit na prática
1) O TestRunner recebe uma subclasse de TestCase;
2) Descobre seus métodos (reflexão);3) Para cada testXxx(); cria nova instância
garante independência !!
executa setUp(); testXxx(); tearDown();
4) Possibilidades:término OK, falha, ou exceção
03/04/2003 VI Semana da Computação
Criando uma seqüência de testes
Classe TestSuite Método addTest adiciona um teste a lista Encontra os testes em uma classe
(reflexão)new TestSuite( ClasseDeTestes.class);
Pode-se juntar tudoTestSuite ts = new TestSuite(“tudo”);
ts.addTest( pacote.Teste1.testeX);
ts.addTest( ClasseDeTestes.suite());
03/04/2003 VI Semana da Computação
Premissas em Java (JDK 1.4)
Nova palavra chave: assert assert (n > 0) : “n não é positivo”;
Podem ser desligadas facilmenteProvocam um AssertionError quando
falhamPara usá-las:
javac -source 1.4 Classe.java java -ea Classe
03/04/2003 VI Semana da Computação
JUnit e premissas:
Premissas são usadas dentro do código
Os testes JUnit ficam em classes separadas Não tem acesso a partes encapsuladas
JUnit testa a partir da interfacePremissas podem verificar lógica interna
03/04/2003 VI Semana da Computação
Testes de desempenho
JUnitPerf Métodos para medir desempenho e
escalabilidade TimedTest
Mede, e limita o tempo do teste
LoadTestExecução concorrente, configuração por timers
ThreadTestExecuta o teste como uma thread separada
03/04/2003 VI Semana da Computação
Testes de Stress
JMeter - testa nos limites De carga
Para diferentes tipos BDs, páginas WEB, objetos Java
Gera gráficos Pode ser usado em conjunto com o JUnitPerf
03/04/2003 VI Semana da Computação
Testes de páginas WEB
Testar do ponto de vista do usuário Através de páginas Testes funcionais
Extensões do Junit HttpUnit e ServletUnit JXweb (especifica os testes em XML) XMLUnit Todos são projetos sourceforge
03/04/2003 VI Semana da Computação
JUnit na prática: O programa
Um sistema para representar diversas moedas;
Para começar: algo simples.
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; }}
03/04/2003 VI Semana da Computação
Para somar dois “Moneys” da mesma moeda (currency):
public Money add(Money m) { return new Money(amount()+m.amount(), currency());}
03/04/2003 VI Semana da Computação
Questão de hábito
Code 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
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
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
03/04/2003 VI Semana da Computação
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...
03/04/2003 VI Semana da Computação
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"); }}
03/04/2003 VI Semana da Computação
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));}
03/04/2003 VI Semana da Computação
Próximos passos
Definir como rodar um teste individual;
Definir como rodar uma seqüência de testes.
// 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");
03/04/2003 VI Semana da Computação
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;}
03/04/2003 VI Semana da Computação
Pode-se automatizar testes
Ou apenas:
public static Test suite() {return new TestSuite(MoneyTest.class);}
Agora, um pouco de JUnit na prática.
03/04/2003 VI Semana da Computação
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]); }}
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
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...
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); //…}
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
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...
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);}
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);}
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 ???
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")));}
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;}
03/04/2003 VI Semana da Computação
Desenvolvimento com testes
Testes 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.