Exceto para as mais triviais aplicações de software, normalmente é considerado impossível testar todas as combinações
de entradas logicamente viáveis para um sistema de software. Por conseguinte, a seleção de um bom subconjunto que tenha
a maior probabilidade de encontrar a maioria dos erros, é uma tarefa importante e útil para os testadores executarem.
Os testes baseados na análise de classes de equivalência (sinônimos: decomposição de equivalência, análise de
domínio) são uma forma de análise de teste de caixa-escura que tenta reduzir a quantidade total de testes
potenciais a um conjunto mínimo que irá descobrir a maioria dos erros possíveis [MYE79].
Trata-se de um método que decompõe o conjunto de entradas e saídas em uma quantidade finita de Classes de
Equivalência, que permitem a escolha de um valor de teste representativo para cada classe. O teste que resulta do
valor representativo para uma classe é chamado de "equivalente" para os outros valores na mesma classe. Se nenhum erro
for encontrado no teste de valor representativo, conclui-se que todos os outros valores "equivalentes" também não
identificarão nenhum erro.
O poder das Classes de Equivalência reside na sua capacidade de orientar o testador a usar de uma estratégia de
amostragem para reduzir a explosão combinatória dos testes potencialmente necessários. A técnica fornece uma base
lógica através da qual um subconjunto do total concebível de testes possa ser selecionado. Aqui estão algumas
categorias de áreas problemáticas para uma grande gama de testes que podem se beneficiar da consideração das classes de
equivalência:
-
Combinação de variáveis independentes
-
Variáveis dependentes baseadas em relacionamentos hierárquicos
-
Variáveis dependentes baseadas em relacionamentos temporais
-
Relacionamentos agregados baseados em exemplares de mercado
-
Relacionamentos complexos que podem ser modelados
Existem diferentes estratégias e técnicas que podem ser usadas nos testes de decomposição por equivalência. Aqui estão
alguns exemplos:
A teoria da decomposição de equivalência como proposto por Glenford Myers [MYE79]. Tenta
reduzir a quantidade total de casos de teste necessários pela decomposição das condições de entrada em uma quantidade
finita de classes de equivalência. Dois tipos de classe de equivalência estão classificados: o conjunto de entradas
válidas para o programa é considerado como classe de equivalência válida, e todas as outras entradas são
incluídas na classe de equivalência inválida.
Aqui esta um conjunto de diretrizes para identificar classes de equivalência:
-
Se uma condição de entrada especifica um conjunto de valores (tal como, o programa "aceita valores entre 10 e
100"), então uma classe de equivalência válida (entre 10 e 100) e duas classes de equivalência inválidas (inferior
a 10 e superior a 100) são identificadas.
-
Se uma condição de entrada especifica um conjunto de valores (tais como, "o pano pode ser de várias cores:
VERMELHO, BRANCO, PRETO, VERDE e MARROM"), então uma classe de equivalência válida (os valores válidos) e uma
classe de equivalência inválida (todos os outros valores inválidos) são identificadas. Cada valor de classe de
equivalência válida deve ser tratado distintamente.
-
Se a condição de entrada for especificada como uma situação "dever ser" (tal como, "o texto de entrada deve estar
em caixa alta"), então uma classe de equivalência válida (caracteres maiúsculos) e uma classe de equivalência
inválida (todas as outras entradas, exceto caracteres maiúsculos) são identificadas.
-
Tudo que acabou "com longa duração" antes da tarefa ser feita é uma classe de equivalência. Tudo que foi feito em
um curto intervalo de tempo antes do programa terminar é outra classe. Tudo que foi feito exatamente antes do
programa começar outra operação é outra classe.
-
Se for especificado que um programa deve trabalhar com tamanho de memória entre 64M e 256M. Então esta dimensão de
tamanho é uma classe de equivalência. Qualquer outro tamanho de memória, que seja maior que 256M ou menor que 64M,
não pode ser aceito.
-
A decomposição do evento de saída depende das entradas do programa. Mesmo que diferentes classes de equivalência de
entrada possam ter o mesmo tipo do evento de saída, você deverá tratar distintamente as classes de equivalência de
entrada.
Em cada uma das classes de equivalência, considera-se que as condições limítrofes tenham uma maior taxa de sucesso na
identificação de resultados com falhas do que as condições não limítrofes. As condições limítrofes são os valores,
imediatamente acima ou abaixo dos limites de cada classe de equivalência.
Os testes que resultam das condições limítrofes fazem uso dos valores, mínimo (min), logo acima do mínimo (min+), logo
abaixo do máximo (max-), e máximo (max) do intervalo que precisa ser testado. Ao testar valores limítrofes, os
testadores escolhem alguns casos de teste para cada classe de equivalência. Para a amostra de testes relativamente
pequena, a probabilidade de descoberta de falha é elevada. É dado ao testador algum alívio no ônus de testar uma enorme
quantidade de casos em uma classe de equivalência de valores que não são susceptíveis de produzir grandes diferenças
nos resultados dos testes.
Algumas recomendações ao escolher valores limítrofes:
-
Para uma variável de ponto flutuante, se a sua condição válida for entre
-1,0 e 1,0 ,
teste -1,0 , 1,0 , -1,001 e 1,001 .
-
Para um inteiro, se a gama de entrada válida for entre
10 e 100 , teste 9 ,
10 , 100 e 101 .
-
Se um programa espera uma letra maiúscula, teste os limites A e Z. Teste
@ e [ também,
porque no código ASCII, @ está logo abaixo de A e [ está logo depois de Z.
-
Se a entrada ou saída de um programa é um conjunto ordenado, preste atenção no primeiro e no último elemento do
conjunto.
-
Se a soma das entradas tiver que ser um número específico (
n ), teste o programa onde a soma seja
n-1 , n e n+1 .
-
Se o programa aceita uma lista, teste os valores da lista. Todos os outros valores são inválidos.
-
Ao ler ou escrever em um arquivo, verifique o primeiro e o último caractere do arquivo.
-
O menor valor nominal do dinheiro é um centavo ou o equivalente. Se o programa aceita um determinado intervalo,
entre a e b, teste a
-0,01 e b +0,01 .
-
Para uma variável com vários conjuntos de valores, cada conjunto de valores é uma classe de equivalência. Se os
subintervalos não estiverem sobrepostos, teste os valores dos limites, logo acima do limite superior e logo abaixo
do limite inferior.
Após a tentativa das duas últimas estratégias de análise de valor limítrofe, um testador experiente irá observar as
entradas do programa para descobrir qualquer caso de "valor especial", que possa ser outra fonte potencialmente rica
para descobrir falhas do software. Aqui estão alguns exemplos:
-
Para um tipo inteiro, o zero deve sempre ser testado se está na classe de equivalência válida.
-
Ao testar tempo (hora, minuto e segundo), 59 e 0 devem sempre ser testados como limites superior e inferior para
cada campo, independente das restrições das variáveis de entrada. Sendo assim, com exceção dos valores de limite de
entrada, -1, 0, 59 e 60 devem ser sempre casos de teste.
-
Ao testar datas (ano, mês e dia), vários casos de teste, tais como a quantidade de dias em um determinado mês, a
quantidade de dias do mês de fevereiro em ano bissexto, a quantidade de dias em ano não bissexto, devem ser
envolvidos.
Ostrand e Balcer [16] desenvolveram um método de decomposição que ajuda os testadores a
analisar a especificação do sistema, escrever scripts de teste, e gerenciá-los. Diferente das estratégias comuns que
normalmente focam no código, o seu método também se baseia nas informações de especificação e design.
O principal benefício deste método é a sua capacidade de expor erros antes do código ser escrito porque a fonte de
entrada é a especificação e os resultados dos testes da análise da especificação. As falhas na especificação serão
descobertas cedo, muitas vezes, bem antes que elas sejam implementadas no código.
A estratégia para o método de "decomposição de categoria" é a seguinte:
-
Analise a especificação: decomponha a funcionalidade do sistema em unidades funcionais que possam ser testadas
independentemente, tanto pela especificação como pela implementação.
Então;
-
Identifique os parâmetros e as condições ambientais que irão influenciar na execução da função. Os
parâmetros são as entradas da unidade funcional. As condições ambientais são os estados do sistema, que
afetarão a execução da unidade funcional.
-
Identifique as características dos parâmetros e das condições ambientais.
-
Classifique as características em categorias, que afetarão o comportamento do sistema.
As descrições de comportamento ambíguas, contraditórias e esquecidas serão descobertas nesta fase.
-
Decomponha as categorias em opções: As opções são as diferentes situações possíveis que podem ocorrer e não são
esperadas. Elas representam o mesmo tipo de informação em uma categoria.
-
Determine as relações entre as restrições das escolhas. As escolhas em diferentes categorias influenciam umas as
outras, que também têm uma influência na construção da suíte de testes. As restrições são adicionadas para eliminar
a contradição entre a escolha de diferentes parâmetros e ambientes.
-
Projete os casos de teste de acordo com as informações das categorias, escolhas e restrições. Se uma opção provocar
um erro, não a combine com outras opções para criar o caso de teste. Se uma opção puder ser "adequadamente" testada
por um único teste, ela também é a representante da escolha ou de um valor especial.
-
Glenford J. Myers, The Art of Software Testing, John Wiley & Sons, Inc., New York, 1979.
-
White L. J. and Cohen E. I., A domain strategy for computer program testing, IEEE Transaction on Software
Engineering, Vol. SE-6, No. 3, 1980.
-
Lori A. Clarke, Johnhette Hassell, and Debra J Richardson, A Close Look at Domain Testing, IEEE Transaction on
Software Engineering, 8-4, 1992.
-
Steven J. Zeil, Faten H. Afifi and Lee J. White, Detection of Linear Detection via Domain Testing, ACM Transaction
on Software Engineering and Methodology, 1-4, 1992.
-
BingHiang Jeng, Elaine J. Weyuker, A Simplified Domain-Testing Strategy, ACM Transaction on Software Engineering
and Methodology, 3-3, 1994.
-
Paul C. Jorgensen, Software Testing - A Craftsman's Approach, CRC Press LLC, 1995.
-
Martin R. Woodward and Zuhoor A. Al-khanjari, Testability, fault, and the domain-to-range ratio: An eternal
triangle, ACM Press New York, NY, 2000.
-
Dick Hamlet, On subdomains: Testing, profiles, and components, SIGSOFT: ACM Special Interest Group on Software
Engineering, 71-16, 2000.
-
Cem Kaner, James Bach, and Bret Pettichord, Lessons learned in Software Testing, John Wiley & Sons, Inc., New
York, 2002.
-
Andy Podgurski and Charles Yang, Partition Testing, Stratified Sampling, and Cluster Analysis, SIGSOFT: ACM Special
Interest Group on Software Engineering, 18-5, 1993.
-
Debra J. Richardson and Lori A. Clarke, A partition analysis method to increase program reliability, SIGSOFT: ACM
Special Interest Group on Software Engineering, 1981.
-
Lori A. Clarke, Johnette Hassell, and Debra J Richardson, A system to generate test data and symbolically execute
programs, IEEE Transaction on Software Engineering, SE-2, 1976.
-
Boris Beizer, Black-Box Testing - Techniques for Functional testing of Software and System, John Wiley & Sons,
Inc., 1995.
-
Steven J. Zeil, Faten H. Afifi and Lee J. White, Testing for Liner Errors in Nonlinear computer programs, ACM
Transaction on Software Engineering and Methodology, 1-4, 1992.
-
William E. Howden, Functional Program Testing, IEEE Transactions on Software Engineering, Vol. SE-6, No. 2, 1980.
-
Thomas J. Ostrand and Marc J. Balcer, The Category-Partition method
for specifying and generating functional tests, Communications of ACM 31, 1988.
-
Cem Kaner, Jack Falk and Hung Quoc Nguyen, Testing Computer Software, John Wiley & Sons, Inc., 1999.
|