Desenvolvimento Orientado a
Componentes e Reuso
Testes de Software
JUnit
Prof. Thiago Affonso de M. N. Viana
[email protected]
Por que usar testes?
• Castigo para programador
• Gastos com tempo e dinheiro
• Leis de Murphy
– 1ª. Se uma coisa pode sair errado, sairá.
– 2ª. Se tudo parece estar indo bem, é porque
você não olhou direito.
– 3ª. A natureza sempre está a favor da falha
oculta.
Por que usar testes?
• "É de conhecimento geral entre os analistas de software que nunca
se elimina o último bug de um programa. Os bugs são aceitos como
uma triste realidade. Esperamos eliminá-los todos, um por um, mas
nunca conseguiremos nos livrar deles." DeMarco, Tom , Editora
Campus, 91
• Desculpas:
– "Depois eu escrevo o plano de testes..."
– "Vamos deixar os testes para a próxima fase..."
– "Na minha máquina funcionou..."
– "Temos que entregar o produto na semana que vem..."
Falta, Erro e Falha
• Falta (Bug)
if(x > 1){
//fazer alguma coisa
}
• Erro (estado transiente que não deveria acontecer)
x=0
• Falha (erro perceptível)
– Causaria uma excecao no sistema
– Tela azul
• Tolerancia a falhas
– habilidade de um sistema continuar em operação mesmo na
ocorrência de falhas
O que são testes de software?
• “Execuções de um programa com a intenção de
encontrar erros". Myers, 1979
• Processo de testes
– Foco na prevenção de erros (como outras
fases da garantia da qualidade de software);
– descobrir sintomas causados por erros;
– fornecer diagnósticos claros para que os
erros sejam facilmente corrigidos
Elementos complicadores
• erros nem sempre são óbvios;
• erros diferentes podem ter a mesma
manifestação;
• saber quem um programa não esta correto não
necessariamente é saber como corrigir o erro.
Teste x Depuração
• Objetivos do teste : mostrar que o software
tem erros.
• Objetivos da depuração : encontrar a causa do
erro detectado no teste, e projetar e
implementar as modificações no programa para
correção do erro.
Processo de Testes
•
Etapas
– Definir os processos
– Medir os processos
– Controlar os processos (garantir que a
variabilidade é estável e os resultados
previsíveis)
– Melhorar os processos
Tipos de testes
•
•
•
•
•
•
•
Teste Estrutural (Caixa branca)
Teste Funcional (Caixa preta)
Teste baseado em erros
Teste de unidade
Teste de sistema
Teste de regressão
Teste de aceitação
Teste Estrutural (caixa branca)
•
•
•
•
Os caminhos lógicos são testados com o intuito de
garantir que todos os caminhos independentes dentro
de um módulo tenham sido exercitados pelo menos
uma vez.
Executa todas as decisões lógicas para valores falsos
ou verdadeiros
Executa todos os laços em suas fronteiras
Exercita as estruturas de dados internas
Teste Estrutural (caixa preta)
•
•
•
São usados para demonstrar que as funções dos softwares são
operacionais, que a entrada é adequadamente aceita e a saída é
corretamente produzida; que a integridade das informações
externas é mantida.
Atividade complementar aos testes de caixa branca, com a
finalidade de descobrir tipos/classes de erros.
Procura descobrir erro em:
–
funções incorretas ou ausentes;
–
erros de interface;
–
erros nas estruturas de dados ou em acesso a bancos de
dados externos;
–
erros de desempenho;
–
erro de inicialização e término
Teste baseado em erros
•
Consiste em incluir propositalmente algum
erro no programa e observar o
comportamento do programa com erro,
comparando-o com o comportamento do
programa original.
Teste de unidade
•
•
•
Deve ser escrito pelo mesmo programador
que desenvolveu o código a ser testado.
Serve como documentação do sistema
Essencial para análise de desempenho
Teste de sistema
•
•
•
Comparar o sistema com seus objetivos
originais
Enfatizar a análise do comportamento da
estrutura hierárquica de chamadas de
módulos
Fase mais complexa, devido à quantidade de
informações envolvidas
Teste de regressão
•
•
Teste necessário para assegurar que
modificações no programa não causaram
novos erros
baseado em arquivo de 'log'
Teste de aceitação
•
•
•
A validação é bem sucedida quando o
software funciona de uma maneira
razoavelmente esperada pelo cliente .
Pressman , 1995
Expectativas dos clientes documentadas
Uso da documentação do usuário
Testes num nível mais prático
• Teste o código em seus limites;
– Para cada pequeno trecho de código (um laço, ou if por
exemplo) verifique o seu bom funcionamento;
– Tente ume entrada vazia, um único item, um vetor cheio, etc.
• Teste de pré e pós condições;
– Verificar certas propriedades antes e depois de trechos de
código;
• Programe defensivamente;
• Sempre verificar se ocorreram erros ao abrir, ler, escrever e
principalmente fechar arquivos;
• Use excecoes;
• Sempre tratar as possíveis exceções;
Testes num nível mais prático
• Teste incrementalmente
– Durante a construção do sistema;
– Após testar dois pacotes independentemente teste se eles
funcionam juntos;
• Teste primeiro partes simples
– Tenha certeza que partes básicas funcionam antes de
prosseguir;
– Testes simples encontram erros simples;
• Conheça as saídas esperadas
– Conheça a resposta certa;
– Para programas mais complexos valide a saída com exemplos
conhecidos;
– Numéricos - exemplos conhecidos, características;
– Gráficos - exemplos, não confie apenas nos seus olhos;
Testes num nível mais prático
• Testar com grandes quantidades de dados
– Gerados automaticamente;
– Erros comuns:
– Overflow nos buffers de entrada, vetores e
contadores;
• Não continue a implementação de novas características
se já foram encontrados erros;
– Teste em várias máquinas, compiladores e SOs(Se
possível)
Conclusões
• "Teste e depois codifique" (Hetzel)
• "Teste cedo e frequentemente" (Beizer)
Ferramentas
• JUnit
– Framework para escrever testes
• Maiores informacoes em
– http://www.testingfaqs.org/
JUnit - Objetivos
• Desenvolver um framework que programadores
de fato usarão para escrever testes de unidade
– Testes de unidade são testes de classes
individuais
• Exigir o mínimo do programador
• Evitar duplicação de esforços ao escrever testes
• Permitir escrever testes que retenham seu valor
ao longo do tempo
JUnit: Framework Java para testes
de unidade
• Framework de testes
• Integrado com várias ferramentas: Eclipse,
Netbeans, ...
• Funcionamento simples e eficaz
Um exemplo do uso do framework
• Para testar uma classe, criamos uma classe de
testes correspondente
• O mínimo que se deve fazer é o seguinte
(versão 4.4+):
• Criar uma classe que tenha o nome
TestNomeDaClasse.
• Usar @Test ou @Test(expected= ...Exception)
antes da assinatura do método.
• Fornecer um ou mais métodos com o nome
test...() sem parâmetros e sem valor de retorno.
• O que foi mencionado acima é o mínimo
necessário para usar o framework
• Para ter um pouco mais de controle, podemos
fazer override dos seguintes métodos, se
necessário:
– setUp()
• Usado para construir um contexto para um teste
– tearDown()
• Usado para desfazer o que setUp() faz
– runTest()
• Para controlar a execução de um teste particular
• É raro fazer override disso
Escrevendo testes
• Testes de unidade: forma mais simples
– Expressões num depurador
– Expressões impressas em uma saída padrão
– Requerem observação humana
• JUnit
– Forma simples que não requer observação humana
– Use a annotation @Test no método
– Para verificar um valor use os métodos assertEquals
e assertNotSame
Escrevendo testes
• Exemplo
@Test
public void testSimpleAdd() {
Money m12CHF= new Money(12, "CHF");
Money m14CHF= new Money(14, "CHF");
Money expected= new Money(26, "CHF");
Money result= m12CHF.add(m14CHF);
assertTrue(expected.equals(result));
}
Escrevendo testes
• Para testes similares a testes já realizados, usamos Fixture
• Útil para configurar todos os dados (conjunto de objetos)
necessários a bateria de testes
• Usa annotations especiais
– @Before –inicializar toda as variáveis do método
– @After – liberar os recursos alocados pelo método
• Uma vez tendo uma Fixture, pode-se escrever diversos
Test Cases.
Escrevendo testes
public class MoneyTest {
private Money f12CHF;
private Money f14CHF;
private Money f28USD;
@Before
public void setUp() {
f12CHF= new Money(12, "CHF");
f14CHF= new Money(14, "CHF");
f28USD= new Money(28, "USD");
}
}
Executando Testes
• JUnit prove ferramentas para definir os testes a serem executados e
mostrar os resultados
– org.junit.runner.JUnitCore.runClasses(TestClass1.class, ...);
– Declare um metodo estático suite que retorna um teste
public static junit.framework.Test suite() {
return new JUnit4TestAdapter(Example.class);
}
– Para compatibilidade com versoes anteriores do JUnit
• Exceções esperadas – verificar que o código executa com sucesso
ou se comporta como esperado em situações especiais são partes
do programa de teste
Executando Testes
new ArrayList<Object>().get(0);
@Test(expected=IndexOutOfBoundsException.class)
public void empty() {
new ArrayList<Object>().get(0);
}
Funcionamento dos testes
• Todos os testes corretos – barra verde.
• Houve falha em algum dos testes – barra
vermelha.
• Erro – foi jogada alguma exceção e não foi
tratada – barra azul.
Componentes de um teste Junit
• Classes a serem testadas:
Triangulo.java
Circulo.java
• Classe contendo os casos de teste
TesteTriangulo.java
TesteCirculo.java
• Chamador dos testes
TestesAceitacao.java
Classe com casos de teste
• Devem estender da classe
junit.framework.TestCase
• Possui os métodos
– setUp()
– tearDown()
• Todos os casos de teste começam com “test”
e não possuem parâmetros.
JUnit - Casos de teste
• assert – Garante que uma determinada
condição seja verdadeira. Caso não seja uma
exceção é levantada(AssertionFailedError).
Ex:. assert(“mensagem de erro”, var1 == var2);
• assertEquals – Verifica se dois valores
passados como parâmetro são iguais
Ex:. assert(“mensagem de erro”, var1, var2);
• fail – Retorna uma exceção caso execute esta
linha.
Ex:. fail(“não deveria passar por esta linha”);
Exemplos de testes
• Testando valores validos
– Somente o assert é necessário.
String retorno = Triangulo.classificaTriangulo(new
String[] {"4", "4", "8"});
assertEquals("Valores não deveriam formar um
triângulo.","NAO É TRIÂNGULO", retorno);
Exemplos de testes
• Testando se operações não retornam exceções
String[] texto = new String[]{"A", "A", "A"};
try {
Sring retorno = Triangulo.classificaTriangulo(texto);
fail("Não levantou NumberFormatException para " +
trianguloString(texto));
}
Exemplos de testes
• Testando se operações retornam exceções indevidas
String[] texto = new String[]{"A", "A", "A"};
try {
Sring retorno = Triangulo.classificaTriangulo(texto);
} catch (NumberFormatException nfe)
{
//ok
} catch (Throwable th)
{
fail("Lançou exceção diferente de NumberFormatException
para os valores de entrada" + th.getMessage());
}
SetUp
• Inicializa o ambiente para a realização dos
testes
setup()
caso de teste ()
...
setup()
caso de teste()
...
TearDown
• Usado para “limpar” o ambiente depois da
realização dos testes
setup()
caso de teste ()
tearDown()
setup()
caso de teste()
tearDown()
...
Observação Importante!
• JUnit não garante ordem de execução dos
testes
• Para isso, cada caso de teste deve ser
adicionado na classe chamadora.
Exercício
• Crie a classe Triangulo.java:
• A classe possui um método classificar:
recebe três valores de lado e informa:
–
–
–
–
Se os lados formam um triângulo eqüilátero
Se os lados formam um triângulo isósceles
Se os lados formam um triângulo escaleno
Se os lados NÃO formam um triângulo
• Crie a classe de caso de testes
• Crie uma classe que executa uma suíte de
testes
Download

Aula 7