Testes OO
Aspectos Avançados em
Engenharia de Software
Aula 6
Fernanda Campos
DCC/UFJF
Teste de software



A fase de teste, no processo de
desenvolvimento de software, tem papel crítico
na garantia da qualidade.
Essa fase fornece subsídios para identificar
problemas e mensurar a qualidade dos
produtos.
A atividade de teste deve resultar em
parâmetros que nos permitam avaliar o grau
de confiança de um sistema.
Teste de software


É necessário testar um sistema OO em uma
variedade de níveis diferentes para descobrir
erros que podem ocorrer à medida que
classes colaboram umas com as outras e
subsistemas se comunicam entre si.
Teste OO é estrategicamente similar ao teste
de sistemas convencionais, mas é taticamente
diferente.
Teste de software


O teste OO pode começar pela revisão dos modelos da
análise e do projeto. Uma vez gerado o código, começa
uma série de testes para exercitar operações de classes
e verificar se existem erros quando uma classe colabora
com outra. À medida que as classes são integradas para
formar um subsistema, o teste baseado em uso é
aplicado. Finalmente, casos de uso são usados para
descobrir erros em nível de validação do software.
Teste OO enfoca a seqüência de operações para
exercitar os estados de uma classe.
Para que testar?


Qualidade: Código testado é mais confiável
•
Coragem para mudar: De que adianta a OO isolar a interface
da implementação se o programador tem medo de mudar a
implementação?
•

Como saber se o recurso funciona sem testar?
Como saber se ainda funciona após refatoramento?
Saber quando o projeto está pronto. Testes são requisitos
“executáveis”. Escreva-os antes. Quando todos rodarem 100%,
o projeto está concluído!
Problema com testes
(e a solução)



Todos sabem: testes devem ser escritos;
Poucos o fazem, e por quê não ?
• Síndrome da pressa
Isto cria um círculo vicioso
menos produtividade
menos estabilidade

menos testes
mais pressão
Como quebrar este ciclo: criando um ambiente simples de
testes. Depois de fazer os primeiros testes, o hábito vem
para ficar.
Testar  Depurar

Simplificando
• Depurar - o que se faz quando se sabe que o
•

programa não funciona;
Testar - tentativas sistemáticas de encontrar
erros em programa que você “acha” que está
funcionando.
“Testes podem mostrar a presença de
erros, não a sua ausência (Dijkstra)”
Teste de software



Duas técnicas podem ser utilizadas para realizar teste de
software: teste funcional e teste estrutural.
O teste funcional, também chamado teste de "caixapreta", testa o sistema do ponto de vista do usuário, isto
é, não considera a estrutura interna ou a forma de
implementação do sistema. Este é o único tipo de teste
possível quando não se dispõe do código-fonte.
O teste estrutural, também chamado de teste de "caixabranca", procura exercitar todas as partes do códigofonte de um sistema. Dessa forma, é necessário ter o
código-fonte disponível, para controlar o que foi e o que
não foi testado.
Teste enquanto você escreve código

Se possível escreva os testes antes
mesmo de escrever o código
• uma das técnicas de XP

quanto antes for encontrado o erro melhor !!
Técnicas básicas





Teste o código em seus limites;
Teste de pré e pós condições;
Uso de premissas (assert);
Programe defensivamente;
Use os códigos de erro.
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 uma entrada vazia, um único item,
um vetor cheio, etc.
Testes sistemáticos

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
teste as funções/métodos individualmente
Testes Sistemáticos

Conheça as saídas esperadas
• conheça a resposta certa
• para programas mais complexos valide a
saída com exemplos conhecidos
• compiladores - arquivos de teste;
• numéricos - exemplos conhecidos, características;
• gráficos - exemplos, não confie apenas nos seus
olhos.
Testes Sistemáticos

Verifique as propriedades invariantes
• alguns programas mantém propriedades da
entrada
• número de linhas
• tamanho da entrada
• freqüência de caracteres
Testes Sistemáticos

Compare implementações
independentes
• os resultados devem ser os mesmos
• se forem diferentes pelo menos uma das
implementações está incorreta

Cobertura dos testes
• cada comando do programa deve ser
executado por algum teste
Automação de testes

Testes manuais

Testes automatizados
• tediosos, não confiáveis
• devem ser facilmente executáveis
Automação de testes

Teste de regressão automáticos
• comparar a nova versão com a antiga
• verificar se os erros da versão antiga foram
•
corrigidos
verificar se novos erros não foram criados
Automação de testes


Crie testes autocontidos
•
testes que contém suas próprias entradas e respectivas
saídas esperadas
O que fazer quando um erro é encontrado?
•
se não foi encontrado por um teste
• faça um teste que o provoque
Arcabouço de testes

As vezes para se testar um componente
isoladamente é necessários criar um
ambiente com características de onde
este componente será executado
Testes de estresse

Testar com grandes quantidades de dados
• gerados automaticamente
• erros comuns:
• overflow nos buffers de entrada, vetores e contadores
• Exemplo: ataques de segurança
Tipos de teste

“white box”
• testes feitos por quem conhece (escreveu) o
código

“black box”

“usuários”
• testes sem conhecer o código
• encontram novos erros pois usam o programa
de formas que não foram previstas
Teste OO

O processo de teste de software OO
apresenta algumas vantagens em relação ao
procedural, entre as quais cita-se:
•
•
•
Métodos e interfaces de classes são explicitamente
definidos;
Menos casos de testes para cobertura do software;
Reutilização de casos de teste devido à presença da
característica de herança.
Teste OO

Existem desvantagens como:
•
•
•
A avaliação da corretude da classe é dificultada pela
presença do encapsulamento de informações;
O gerenciamento do teste é dificultado pelos múltiplos
pontos de entrada (métodos) de uma classe;
As interações entre os objetos são expandidas pelo
polimorfismo e pela ligação dinâmica.
Tipos de testes em software OO

testes das classes

testes de interações
testes de regressão
teste do sistema e sub-sistemas
teste de aceitação
testes de implantação




Análise de Riscos


Análise de Riscos ajuda a planejar quais
testes devem ser feitos
Um risco - ameaça ao sucesso de um projeto
 riscos do gerenciamento do projeto
 testes não ajudam muito
 riscos do negócio
 testes da funcionalidade
 riscos técnicos
 testes de unidades, das classes, componentes, etc.
Dimensões do Processo de Testes

Quem cria os testes?
 Os desenvolvedores? Uma equipe especializada em
testes? Ambos?

Quais partes são testadas?

Quando os testes serão realizados?
 Todas? Nenhuma? Ou só as de alto risco?

Sempre? Rotineiramente? No final do projeto?
Dimensões do Processo de Testes

Como será feito?
 Baseado no que o software faz ou em como o
software faz?
 Os testadores conhecem a implementação ou só a
interface?

Quanto de testes é o adequado?
Papéis no Processo de Testes

Testador de classes

Testador da Integração
 testa as interações entre  objetos

Testador do sistema
 conhece o domínio e é capaz de verificar a aplicação
como um todo
 ponto de vista do usuário do sistema

Gerente do Processo de Testes
 coordena e escalona os testes e as pessoas
Planejamento de Testes


Muitas vezes é esquecido ou não é
considerado pelos gerentes de projeto
Atividades de planejamento:
• Escalonamento das atividades de testes
• Estimativas de custo, tempo e pessoal
•
necessário para realizar os testes
Equipamento necessário
Planejamento de Testes

Atividades de planejamento:
• Definição do nível de cobertura: quanto maior,
mais código será exigido.
 métricas para avaliar eficácia de um conjunto de
testes
• cobertura do código
• cobertura das pós-condições
• cobertura dos elementos do modelo
Testes das Classes (unidades)

Uma maneira é o peer-review
• Errar é humano

Testes automatizados são melhores

Testes automatizados devem cobrir
• alguns casos normais
• o maior número possível de casos limítrofes
Testes das Interações

Objetos podem interagir de 4 formas
diferentes:
• um objeto é passado como parâmetro para outro
objeto numa chamada de método
• um objeto devolve uma referência para outro
objeto numa chamada de método
• um método cria uma instância de outro objeto
• um método usa uma instância global de outra
classe (normalmente evitado)
Casos: Teste das interações


Chamadas de métodos
2 abordagens:
• Programação defensiva
• O receptor verifica os parâmetros
• Programação por contrato
• A mensagem é verificada antes do envio
Casos: Teste das interações

Subclasses/superclasses
• Use o diagrama de classes para identificar quais
testes de regressão devem ser realizados quando
uma classe é alterada ou uma nova classe é criada.
• Execute os testes escritos para a superclasse mas
agora usando a nova subclasse
• Para testar classes abstratas, somos obrigados a
criar classes concretas só para testá-las
O que são ferramentas para testes
automáticos?

São programas que avaliam se outro programa
funciona como esperado e retornam resposta do
tipo "sim" ou "não“.
Ex: um main() que cria um objeto de uma classe
testada, chama seus métodos e avalia os
resultados

Validam os requisitos de um sistema
Testes Automáticos (self-checking)




Os testes devem verificar a si mesmos.
A saída deve ser
• “OK” ou
• lista precisa das coisas que deram errado.
Quando os testes funcionam, sua saída
deve ser apenas uma lista enxuta de “Oks”.
Ou um botão e uma luz verde e outra
vermelha.
O Testador Ideal
executar
Teste
OK
ver
Erro
Detalhes
JUnit: O que é?

JUnit é um “framework” que facilita o
desenvolvimento e execução de testes de
unidade em código Java
•
Uma API para construir os testes
• Classes Test, TestCase, TestSuite, etc. oferecem a
•
•
infraestrutura necessária para criar os testes.
Métodos assertTrue( ), assertEquals( ), fail( ), etc. são
usados para testar os resultados.
Aplicações para executar testes (os TestRunners)
• Rodam testes individuais e suites (conjuntos de testes).
JUnit: Para que serve?




“Padrão” para testes de unidade em Java
Desenvolvido por Kent Beck (o guru do XP) e Erich
Gamma (do GoF "Design Patterns")
Facilita:
•
•
JUnit pode verificar se cada método de uma classe
funciona da forma esperada
•
•

A criação e execução automática de testes
A apresentação dos resultados
Permite agrupar e rodar vários testes ao mesmo tempo
Na falha, mostra a causa em cada teste
Serve de base para extensões
CppUnit

CppUnit é a versão para C++ do JUnit (mas
não é idêntico)
http://cppunit.sourceforge.net

A saída dos testes pode ser em XML ou em
formato de texto para testes automáticos, e
com interface visual para testes
supervisionados
JUnit: Como funciona






O TestRunner recebe uma subclasse de
junit.framework.TestCase
Usa reflection para descobrir seus métodos
Para cada método testXXX(), executa:
1. o método setUp()
2. o próprio método testXXX()
3. o método tearDown()
O test case é instanciado para executar um
método testXXX() de cada vez.
As alterações que ele fizer ao estado do objeto
não afetarão os demais testes
Método pode terminar, falhar ou provocar
exceção
TestCase
setUp()
tearDown()
MyTestCase
setUp()
testXXX( )
testYYY( )
tearDown()
JMeter:
Testes de Stress
Uma ótima ferramenta open-source para testar os
limites de uma aplicação

•
•
•


Simula carga pesada em servidor, rede ou objeto
Testa performance sob diferentes tipos de carga em aplicações Web,
servidores de FTP, objetos Java, bancos de dados, servlets, scripts
em Perl, sistemas de arquivos, e outras aplicações (Java ou não)
Gera gráficos com resultados para
análise
JMeter pode ser usado para
simular carga que cause falha
em testes decorados com JUnitPerf
http://jakarta.apache.org/jmeter
Dependência de código-fonte


Problema: Como testar componente que depende do código de outros componentes?
Classe-alvo não oferece o que testar:
Bandeja
ImpressoraTest
testImprime()
Impressora
imprime()
temPapel()
Cartucho
temTinta()
Se houver tinta e se houver papel método void imprime( )
deve funcionar

Como saber se há ou não tinta e papel?
public void testImprime( ) {
Impressora imp = new Impressora();
imp.imprime( ); // void!
assert???(???);
}

Stubs: objetos "impostores"

É possível remover dependências de código-fonte refatorando
o código para usar interfaces

Agora B pode ser substituída por um stub
•
•
BStub está sob controle total de ATest (1)
Em alguns casos, ATest pode implementar InterB (2)
Dependência:
solução usando stubs

Quando usar stubs
•
•
Dependência ainda não está pronta
Dependências têm estado mutante, imprevisível ou
estão indisponíveis durante o desenvolvimento
• BDs, servidores de aplicação, servidores Web, hardware
Dependências de servidores

Usar stubs para simular serviços
•
•
•
É preciso implementar classes que devolvam as respostas esperadas
para diversas situações
Complexidade pode não compensar investir no desenvolvimento
Use soluções open-source prontas!
•
DBUnit: extensão do JUnit para testar aplicações JDBC
http://dbunit.sourceforge.net
• JUnitEE: extensão do JUnit para testar aplicações J2EE
http://junitee.sourceforge.net

Usar proxies para serviços reais
•
•
Testa a integração real do componente com seu ambiente
Solução open-source:
•
Cactus: testa integração da aplicação com servlet containers
Cactus:
Testes de aplicações J2EE

Cactus é um framework open-source do
projeto Jakarta para testar aplicações
que utilizam componentes J2EE
• Componentes Web (Camada de
Controle)
• Camada EJB (Model) e cliente
(View): indiretamente
Cactus estende o JUnit

Execução dos testes é realizada de forma idêntica
TestCases são construídos herdando de uma subclasse de
junit.framework.TestCase (Exemplo: ServletTestCase)

Cactus:
Testes de aplicações J2EE

Cactus testa a integração dos componentes Web com seus
containers
•
•
Usa o próprio container como servidor e JUnit como cliente
•
•
Uma cópia do Test Case é instanciada pelo container
Outra cópia é instanciada pelo JUnit
Comunicação é intermediada por um proxy (ServletRedirector,
JSPRedirector ou FilterRedirector)
•
•
JUnit envia requisições via HTTP para proxy
Proxy devolve resultado via HTTP e JUnit os mostra
Cliente
Servidor
(1) beginXXX()
Classe
de Teste
(9) endXXX()
(4) setUp()
(2)
(3)
Proxy
(8)
(7)
Classe
de Teste
(6) tearDown()
(5) testXXX()
Classes do
Servidor
Testes de interface em servidores Web


Testar o funcionamento da aplicação do ponto de vista do usuário
• Verificar se uma página HTML ou XML contém determinado
texto ou determinado elemento
• Verificar se resposta está de acordo com dados passados na
requisição: testes funcionais do tipo "caixa- preta"
Soluções (extensões do JUnit):
• HttpUnit e ServletUnit:
•
•
•
permitem testar dados de árvore DOM HTML gerada
JXWeb (combinação do JXUnit com HttpUnit)
•
•
permite especificar os dados de teste em arquivos XML
arquivos de teste Java são gerados a partir do XML
XMLUnit: extensão simples para testar árvores XML
Dicas para fazer testes




Cheque os limites dos vetores
•
•
caso a linguagem não faça isto por você
faça com que o tamanho dos vetores seja pequeno; ao invés
de criar testes muito grandes
Faça funções de hashing constantes
Crie versões de malloc que ocasionalmente falham
Desligue todos os testes antes de lançar a versão
final
Dicas para fazer testes

Inicialize os vetores e variáveis com um valor não
nulo
•


ex: 0xDEADBEEF pode ser facilmente encontrado
Não continue a implementação de novas
características se já foram encontrados erros
Teste em várias máquinas, compiladores e SOs
Concluindo


Testes proporcionam:
• Planejamento
• Refinamento do design
• Ritmo saudável
• Design simples
• Lançamentos pequenos
Vale a pena investir tempo para desenvolver e aperfeiçoar a
prática constante de escrever testes automatizados
• mais produtividade, maior integração de equipes
• produtos de melhor qualidade, com prazo previsível
• menos stress, mais organização
Download

Aspectos_Engenharia_de_Software-2009_-_aula6_-_teste