Post on 19-Apr-2015
Desenvolvimento Orientado a Componentes e Reuso
Testes de Software
JUnit
Prof. Thiago Affonso de M. N. Viana thiago_affonso_viana@yahoo.com.
br
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.javaCirculo.java
• Classe contendo os casos de testeTesteTriangulo.javaTesteCirculo.java
• Chamador dos testesTestesAceitacao.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 iguaisEx:. 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