Vous êtes sur la page 1sur 13

UNIVERSIDADE LUTERANA DO BRASIL

CENTRO DE CIÊNCIAS EXATAS E NATURAIS

CURSO DE SISTEMAS DE INFORMAÇÃO

TESTES DE SISTEMA

MAURICIO VOLKWEIS ASTIAZARA

IGOR CASA NOVA DOS SANTOS

Engenharia de Software I

Torres, Junho de 2001


Introdução

Este trabalho tem como objetivo mostrar a importância dos testes no desenvolvimento

estruturado de software, passando pelas fases desta etapa e os tipos de teste utilizados em cada

fase. Aborda também os métodos para uma correta aplicação dos testes de forma eficiente,

visando a produção de um sistema com qualidade.


Testes
1 Objetivo
O propósito dos testes é evitar “surpresas desagradáveis” depois que o sistema entra em
funcionamento. O propósito da análise estruturada é evitar surpresas desagradáveis nos testes.
Os dois estão intimamente relacionados.

2 Tipos de Teste
Durante as quatro fases de teste de um projeto são aplicados testes que podem ser
classificados em duas categorias: Testes Estruturais e Testes Funcionais. Antes de entrarmos
nas fases do teste veremos como são caracterizados estes dois tipos de teste.

2.1 Testes Estruturais

São também chamados de testes de Caixa Branca. Preocupam-se em verificar como as


funções são implementadas. Assim além de detectarem o erro, podem ajudar de modo
significativo na sua correção. São constituídos de atividades de verificação que normalmente
incluem a análise da especificação do projeto, do código do programa e do fluxo de dados.
Esse tipo de análise é classificada como estática, pois o programa não ou módulo não
necessita necessariamente estar em execução para que ela sejam efetuadas.

Os testes estruturais procuram analisar como as funções são implementadas

Os testes estruturais podem ajudar a descobrir funções ausentes no programa, erro nas
expressões aritméticas, declaração de tipos necessária, diferenças entre áreas de dados
compartilhadas, erro nas interfaces de módulos (parâmetros) e não cumprimento de padrões.
Exemplos de técnicas aplicadas no testes estruturados:
• Análise da estrutura de controle;
• Técnicas baseadas em lógica matemática;
• Inspeções;
• Testes de mesa;
• Programas verificadores de estrutura;
• Teste baseado na cobertura: é aquele em cada comando do módulo é executado ao menos
uma vez;
• Teste baseado na cobertura de desvios: testa cada decisão e segue todos os desvios da
decisão;
• Teste da cobertura dos caminhos DD: um caminho DD é a seqüência de comandos que se
inicia no resultado de uma decisão e termina na próxima decisão;
• Teste baseado na complexidade: procura orientar o esforço do teste para as partes mais
complexas do código, onde é mais provável a existência de erros. Para métrica da
complexidade utiliza-se uma das diversas técnicas existentes como a métrica de Halstead,
número ciclomático de complexidade de McCabe e a complexidade da variável de
controle de McClure.

2.2 Testes Funcionais

São também chamados de testes Caixa Preta. Preocupam-se em testar se as funções


realizam as tarefas corretamente independente do modo como o façam (só interessa se as
respostas estão corretas ou não). Estes testes são executados depois do teste de estrutura e tem
como objetivo validar o que foi feito na etapa anterior, aprovando ou não. Os testes funcionais
são realizados com o programa ou módulo em execução, por isso é chamado de análise
dinâmica.
O processo de um teste funcional envolve os seguintes passos:
1 Selecionar um conjunto de dados de entrada com os quais se executará o programa;
2 Determinar a saída que se espera ser produzida;
3 Executar o programa;
4 Comparar os resultados produzidos pelo programa com o que era esperado.

Passos para a realização de um teste funcional.

Diferentes aspectos da funcionalidade do programa devem ser testados nesta fase e para
cada um deles existe uma metodologia para a produção de dados de teste (primeiro passo,
acima). Por isso os testes funcionais se dividem nas seguintes etapas:
1 Teste de Via Normal (ou Caminho Normal)
2 Teste de Via de Erro (ou Caminho de Exceção)
3 Teste de Estado Transiente
4 Teste de Desempenho (ou Performance)
5 Testes Especiais

2.2.1 Teste de Via Normal

Este teste é derivado do Dicionário de Dados. Consiste em gerar um grupo de entradas


válidas para verificar se o sistema executa o que foi exigido na especificação estruturada.
Casos de teste devem ser derivados para cada item no dicionário de dados e para cada
fluxo de dados composto seguindo o que foi especificado no dicionário de dados. Gerar todas
as possibilidades de dados para cada item é impossível, ao invés disso devemos concentrar os
testes nas chamadas situações limite, que pode ocasionar a maior parte dos erros. Pode-se
ainda acrescentar um valor intermediário, com a objetivo de abranger todas as faixas de
valores (inferior, médio e superior). Em geral as situações limite devem ser testadas nos
seguintes aspectos:
• Limites de Entrada: limites superiores, inferiores e outros associados
com as entradas do sistema. A finalidade destes testes é verificar se o sistema
aceitará entradas dentro dos limites da especificação. Por exemplo: se a
especificação indica que uma entrada do sistema deve ser uma string de 1 a 40
caracteres devemos testar se o sistema funcionará com strings de 1, 20, 39 e 40
caracteres.
• Limites de Saída: limites superiores, inferiores e outros associados com
as saídas do sistema. Por exemplo: se um sistema de folha de pagamento que
supostamente deve ser capaz de produzir contracheques de seis dígitos, obviamente
é uma boa idéia construir-se casos de teste que produzam este tipo de contracheque.
• Limites Funcionais: para assegurar que as funções descritas na
especificação do processo sejam executadas corretamente em situações limite. Por
exemplo, um módulo OrdenaTab que ordena uma tabela de itens. Os limites
funcionais seriam testados utilizando-se uma tabela vazia, uma tabela com somente
um item, uma com itens já ordenados, uma com itens iguais e outra com o limite
máximo de itens (se houver).
Uma vez definidos os conjuntos de valores válidos para cada item do dicionário de
dados, eles devem ser combinados gerando uma gama de valores de entrada para o teste de
via normal. Isso poderia ser feito utilizando-se um banco de dados com os conjuntos
escolhidos e aplicando-se a operação de produto cartesiano sobre eles. Em alguns casos o
tamanho deste banco de dados pode tornar-se um transtorno, não sendo viável realizar o teste
com todos os valores obtidos ou até mesmo não sendo possível completar o banco de dados.
Mesmo nesses casos a equipe deve estar ciente que o sistema deve ser capaz de manipular
qualquer uma dessas entradas.
Tomemos agora um exemplo prático de teste de via normal para entrada a partir de um
dicionário de dados simples, que segue a seguinte notação:

Símbolo Significado
= É composto de
+ E
<min>{ }<max> Iteração (mínimo, tipo de dado, máximo)
<valor1> – <valor2> Intervalo de valores
[<valor1>|<valor2>|<valorN>] Escolha Múltipla

Dicionário Exemplo:

Cod_quarto = 1 – 1000
Status = [ “vago” | “ocupado” ]

A partir do que está especificado neste dicionário podemos derivar os seguintes


conjuntos de dados válidos:

Cod_quarto =(1, 500, 1000)


Status = (“vago”; “ocupado”)

Combinando-se os valores obtemos as seguintes entradas válidas:

Cod_quarto Status
1 “vago”
500 “vago”
1000 “vago”
1 “ocupado”
500 “ocupado”
1000 “ocupado”

2.2.2 Testes de Via de Erro

Semelhante ao de via normal, porém entra com dados inválidos no sistema para avaliar
seus tratamentos de erros, que deve ser recusá-los, evitando a produção de saídas inválidas ou
até mesmo o travamento do sistema.
Esses dados inválidos são geralmente de dois tipos:
1 Casos que infrinjam os limites de entrada (citados nos testes de via normal) como por
exemplo, para uma entrada de valor numérico que deve ser um valor de 1 a 10, um conjunto
de dados inválidos para teste poderia ser –1,0,11,15.
2 Valores incompatíveis com o tipo de dado esperado, como por exemplo, para a
mesma entrada numérica acima o conjunto de dados poderia ser 1A, w, #?, (vazio).
Cada conjunto de dados inválidos substituirá o seu respectivo conjunto de valores
normais de cada vez, que foram usados no teste anterior (via normal). Efetua-se a combinação
(produto cartesiano) nesse novo arranjo de conjuntos obtendo-se um conjunto de entradas
inválidas, que contém um único erro (que está no item que teve seu conjunto normal
substituído pelo inválido). Somente um conjunto de dados inválidos será combinado com o de
vias normais de cada vez, produzindo um único erro por entrada. Não se deve produzir
entradas com combinações de erros ou entradas com um dado com múltiplos erros.
Seguindo o mesmo dicionário do exemplo anterior, podemos estabelecer os seguintes
conjuntos de dados inválidos:

Cod_quarto = (0, 1001, “M#”)


Status = (“vag1”, 2)

Iniciamos a substituição pelo do primeiro item de dado (Cod_quarto) e efetuamos a


combinação com os dados válidos. Assim se seguirá com o resto dos conjuntos.

Cod_quarto Status
0 “vago”
1001 “vago”
“M#” “vago”
0 “ocupado”
1001 “ocupado”
“M#” “ocupado”

2.2.3 Teste de Estado Transiente

Os testes derivados até agora seriam suficientes para testar um sistema que não tivesse
nenhuma memória, que tratasse cada entrada de modo independente do que tivesse acontecido
antes. Porém para sistemas com vários estados transientes será necessário agrupar os testes
em seqüências. A seqüência de testes pode ser organizada para forçar o sistema em cada um
dos estados possíveis e testar o seu desempenho nesse estado. Para derivar um conjunto
completo de seqüências de teste deve-se listar os estados em memória para cada fluxo de
dados de entrada e realizar uma seqüência de teste para cada estado.

2.2.4 Teste de Desempenho

Visa verificar se os requisitos de tempo e volume especificados na análise foram


realmente atendidos. Este tipo de teste é essencial para grandes sistemas em-linha, mas pode
ser desnecessário para pequenos sistemas em lote ou para qualquer tipo de sistema em que o
hardware seja uma pequena parte do custo geral do sistema, e que seja facilmente expansível
(por exemplo adicionando mais memória ou atualizando o processador).
Na maioria dos casos de teste de desempenho preocupa-se com o rendimento, tempo de
resposta e capacidade de banco de dados. Pode não ser prático ou mesmo possível criar
entradas reais suficientes e carga suficiente no novo sistema para verificar se o seu
desempenho é satisfatório, porém pode-se utilizar uma série de técnicas de simulação.
Pode-se enganar o sistema em operação como se ele tivesse um pesado volume
reduzindo o hardware disponível. Por exemplo rodar o sistema em máquina com somente
8MB de memória ao invés de 64MB.
Outra maneira é a partir de um pequeno volume de dados efetuar centenas de cópias ou
até milhares para se obter o volume necessário.
Naturalmente essas simulações são subterfúgios não garantem a geração de resultados
perfeitos.

2.2.5 Teste Especiais

Seria ingenuidade pensar que qualquer sistema, independente de sua complexidade,


poderia ser completamente testado na sua funcionalidade pelos testes descritos anteriormente
que são derivados da especificação estruturada. Alguns precisam claramente de testes
adicionais para lidarem com suas naturezas particulares. Já que estes testes não podem ser
derivados da especificação estruturada eles devem ser colocados explicitamente na
especificação estruturada antes que ela seja considerada completa. Isto manterá o conceito de
que todos os testes têm como base a especificação estruturada.

3 Fases do teste
A abordagem estruturada teve grande influência na etapa de teste, assim como nas
outras fases de desenvolvimento de software. O teste tem sido formalizado como um
procedimento de quatro fases como descrito abaixo.

3.1 Teste de Unidade

O teste de unidade consiste em se aplicar o teste estruturado e o teste funcional para


cada função, sub-rotina ou módulo. O teste de unidade normalmente é realizado pelo
programador como parte da etapa de codificação.
O teste de unidade sozinho não garante que ao unirmos os módulos testados teremos um
sistema funcionando com sucesso, mas garante que módulo testado chegue a fase de
integração cumprindo o seu objetivo lógico, a sua função.
No teste de Unidade cada módulo é testado individualmente quanto a estrutura e funcionalidade

3.2 Teste de Integração

O teste de integração consiste em se aplicar o teste estruturado e o teste funcional sobre


uma hierarquia de módulos, como um subsistema ou o sistema completo. O objetivo do teste
de integração é verificar se cada módulo funciona corretamente dentro da estrutura de
controle e checar se as interfaces dos módulos (a comunicação entre eles) estão corretas.

Nos teste de integração é checada a comunicação (dados, controles) entre módulos.

O teste de integração tem diferentes abordagens: bottom-up, a top-down, e a middle-out


são as básicas, mas existem outras variações. A seguir veremos mais detalhadamente cada
uma delas.

3.2.1 Bottom-up

O nome desta estratégia significa do fundo para cima e segue este princípio na
integração dos módulos, iniciando pelos módulos de nível mais baixo de forma ascendente até
chegar aos níveis mais alto.

Direção da integração na abordagem Bottom-up

Esta estratégia de integração requer a construção de acionadores, que é um módulo


temporário responsável pelo teste. O acionador chamará o módulo que esta sendo testado
passando-lhe como parâmetro os dados do teste e recebendo o que o módulo retorna (se o
módulo testado precisa de parâmetros ou retorna valores).
A estratégia Bottom-up tem apresentado vários problemas à fase de integração:
• acionadores podem exigir grande esforço pra serem desenvolvidos de modo a
simularem de modo fiel o sistema, além disso podem ser uma fonte adicional de erros;
• as funções de alto nível do programa são testados por último, retardando a descoberta
de erros que podem ser cruciais;
• erros de interface podem aparecer muito tarde, aumento de forma proporcional a
dificuldade de correção.

3.2.2 Top-down
Na estratégia top-down (do topo para baixo) os módulos de alto nível são integrados e
testados em primeiro lugar. Desse modo o teste segue de modo descendente na estrutura
hierárquica. O teste top-down requer a criação de módulos temporários chamados stubs. O
módulo stub representa o módulo de nível logo abaixo do módulo que está sendo testado. A
medida que o teste continua e se desce na estrutura, cada stub é substituído pelo módulo real e
novos stubs para esse módulo são criados.

Direção da integração na abordagem Top-down

Os módulos stubs podem ser de diversos tipos, cada tipo pode auxiliar de modo
diferente no teste do sistema:
• Não executar nada. Não é muito útil mas fácil de implementar;
• Exibir uma mensagem indicando que foi chamado. Útil para verificação do fluxo de
controle do sistema;
• Exibir um terminal, permitindo que o responsável pelo teste passe dados e tempo de
execução para o módulo superior;
• Retornar um valor constante, um número aleatório ou um número de uma tabela de teste.
• Ser uma versão simplificada do módulo real;
• Testar ou exibir os dados com os quais foi chamado;
• Aguardar certo tempo. Esse tipo de stub é útil em sistemas de tempo real ou sistemas
operacionais nos quais é preciso assegurar-se de que o sistema funcionará corretamente
com um módulo que consumirá, por exemplo, 19 milésimos de segundo. Também pode
ser utilizado para simular o acesso a um hardware que demorou tantos milésimos de
segundo para estar pronto.

Substituição dos stubs pelos módulos a medida que segue o teste.

A estratégia top-down oferece importantes vantagens sobre a bottom-up:


• As funções de alto nível são testadas em primeiro lugar;
• O teste de integração pode começar mais cedo porque os módulos de alto nível podem ser
codificados em primeiro lugar e podem ser testados com stubs;
• Os stubs são mais fáceis de serem construídos que os acionadores.
Problemas com a abordagem top-down:
• Importantes funções de alto nível são testadas bem tarde no processo de desenvolvimento.
Problemas nessas funções podem forçar a um tardio reprojeto de funções de alto nível;
• Às vezes pode ser difícil construir os stubs simulando efetivamente o modo real.

3.2.3 Middle-out

Em pequenos programas, faz pouca diferença qual abordagem de integração é usada.


Neste caso, teste de unidade e teste e integração são freqüentemente combinados em uma
etapa. Em grandes projetos porém, prefere-se mais formalidade na separação das etapas de
teste. Prefere-se, também uma abordagem que combine as técnicas top-down e middle-out a
fim de minimizar seus problemas e aproveitar melhor suas vantagens. Middle-out significa do
meio para fora, neste caso o meio não significa exatamente a metade da estrutura, mas sim a
parte principal do projeto, que pode estar localizada em qualquer região.

Abordagem Middle-out: partindo do módulo principal.


Inicia-se a integração a partir dessa parte crucial e pode-se seguir tanto para cima ou
para baixo, de acordo com a importância dos módulos. Dessa maneira têm-se a garantia de
erros em partes importantes sejam descobertas tardiamente, forçando a uma reprojeção dos
outros módulos.
Esta estratégia tem sido a que produz os melhores resultados, sendo a adotada pela
maior parte dos desenvolvedores. Existem variações sobre esta estratégia sobre como
percorrer a estrutura.

3.3 Teste de Sistema

É executado após o teste de integração e é basicamente um teste funcional aplicado


sobre a estrutura já integrada na fase anterior. O objetivo é descobrir implementações
incorretas ou falta de implementação das especificações dos requisitos e corrigi-las. As partes
mais importantes do sistema e mais freqüentemente usadas devem ser testadas mais
exaustivamente.

3.4 Teste de Aceitação

A fases anteriores de teste serviam para detectar erros afim de corrigi-los. Mas no teste
de aceitação não é mais uma etapa de correção. O teste de aceitação é a mais pura forma de
teste funcional, determinando se o projeto atingiu seu alvo ou não, pois o teste de aceitação é
o que foi exigido na especificação (requisitos do usuário) estruturada produzida pela atividade
de análise .

Análise  Especificação Estruturada  Geração do Teste de Aceitação


O teste de aceitação é efetuado elaborando-se um plano de teste e aplicando-se o teste
funcional, visto em tipos de teste, no programa, como visto abaixo:

1 Elaborar Plano de Teste


2 Aplicar Teste Funcional
2.1 Teste de Via Normal (ou Caminho Normal)
2.2 Teste de Via de Erro (ou Caminho de Exceção)
2.3 Teste de Estado Transiente
2.4 Teste de Desempenho (ou Performance)
2.4 Testes Especiais

3.4.1 Elaborar Plano de Teste

É o passo mais importante, pois uma vez desenvolvido é usado por todas as atividades
subseqüentes. O plano de teste deve cobrir o estabelecimento do pessoal para testar o sistema,
um esboço das normas de teste e um relatório de tempo estimado e recursos necessários a
atividade de teste.
O objetivo inicial do plano deve ser a definição de uma pessoa ou grupo de pessoas
responsável por testar o sistema. Esta pessoa (ou grupo) deve ser alguém diferente das pessoas
que desenvolveram os sistema. Na verdade quanto mais afastada do projeto a pessoa
responsável, mais objetivo e profundo será o procedimento do teste. Pode-se até mesmo
contratar uma organização externa (como uma firma de consultoria de software) para realizar
o teste. De qualquer forma, o teste deve ser feito por alguém que entenda que o processo
possui a finalidade expressa de encontrar erros e revelar falhas do sistema.
Precisam ser desenvolvidos procedimentos e padrões para a construção de casos de
teste, documentação de resultados, convenção de nomeação, armazenamento e recuperação
para grupos (ou arquivos) de dados de teste.

3.4.2 Aplicar Teste Funcional

O teste funcional é aquele visto na parte de Tipos de Teste, que agora deve ser aplicado
de modo global no programa de modo a validá-lo, resultando na sua aprovação ou reprovação.
Conclusão
Durante a realização deste trabalho concluímos que a análise estruturada possibilita o

desenvolvimento de software de qualidade, mas a etapa de teste é a que fornece maior retorno

ao desenvolvedor, tanto em relação ao atendimento dos requisitos do usuário quanto ao

progresso do projeto. Devendo portanto, receber a mesma dedicação e provimento de recursos

que as outras etapas da análise estruturada.


Bibliografia

1. YOURDON, Edward. Administrando o Ciclo de Vida do Sistema. Rio de Janeiro:


Campus, 1989.

2. PAGE-JONES, Meilir. Projeto Estruturado de Sistemas. São Paulo: McGraw-Hill,


1988.

3. MARTIN, James; MC CLURE, Carma. Técnicas Estruturadas e Case. São Paulo:


Makron, 1991.

Vous aimerez peut-être aussi