ppt - IME-USP

Propaganda
Exemplo de desenvolvimento
com testes
Prof. Dr. Alfredo Goldman
Departamento de Ciência da Computação
IME / USP
3 de Abril de 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 pressa
Mas, isto cria um círculo vicioso:
menos testes
menos produtividade
menos estabilidade
mais pressão
03/04/2003
VI Semana da Computação
Como quebrar este ciclo
Criando um ambiente simples de testes
Depois de fazer os primeiros testes
o hábito vem para ficar
Vamos 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 texto
Modo gráfico
03/04/2003
VI Semana da Computação
Junit - origens e uso
Criado por K. Beck e E. Gamma
Padrão para testes em Java
Permite 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 tudo
TestSuite 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 facilmente
Provocam um AssertionError quando falham
Para 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 interface
Premissas 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
LoadTest
Execução concorrente, configuração por timers
ThreadTest
Executa 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.
03/04/2003
VI Semana da Computação
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;
}
}
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
03/04/2003
VI Semana da Computação
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
Mas antes um teste para o 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.
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.
03/04/2003
VI Semana da Computação
// 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");
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 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]);
}
}
03/04/2003
VI Semana da Computação
Para os testes deve se criar também objetos do novo tipo
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);
}
Devem se criar novos testes, mas os testes antigos continuam lá
public void testBagEquals() {
assert(!fMB1.equals(null));
assertEquals(fMB1, fMB1);
assert(!fMB1.equals(f12CHF));
assert(!f12CHF.equals(fMB1));
assert(!fMB1.equals(fMB2));
}
E devem continuar funcionando...
Agora podemos melhorar o método add
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 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 com
12CHF ???
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;
}
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.
03/04/2003
VI Semana da Computação
Download