Disciplinas > Teste > Conceitos > Lista de Idéias de Teste

Tópicos

Introdução Início da página

As informações usadas no design de testes são provenientes de vários locais: modelos de design, interfaces de classificador, diagrama de estados e o próprio código. Em determinado ponto, as informações do documento de origem devem ser transformadas em testes executáveis:

  • Entradas específicas feitas no software em teste,
  • em determinada configuração de hardware e software,
  • inicializadas em um estado conhecido,
  • com resultados específicos esperados.

É possível passar diretamente das informações do documento de origem para os testes executáveis. Mas normalmente é útil adicionar uma etapa intermediária. Nela, as idéias de teste são incluídas em uma Lista de Idéias de Teste. A lista é usada para criar testes executáveis.

O que são Idéias de Teste?Início da página

Uma idéia de teste (ou requisito de teste) é uma declaração resumida sobre um teste que poderia ser realizado. Como exemplo, vamos utilizar uma função que calcula uma raiz quadrada. Eis uma lista de idéias de teste:

  • fornecer como entrada um número um pouco menor que zero
  • fornecer zero como entrada
  • testar um número que tenha uma raiz quadrada perfeita, como 4 ou 16 (o resultado é exatamente 2 ou 4?)

Cada uma dessas situações poderia ser facilmente convertida em um teste executável com descrições exatas de entradas e resultados esperados.

Há duas vantagens nessa forma intermediária menos específica. Uma é que as idéias de teste são mais revisáveis e compreensíveis que testes completos - é mais fácil entender o raciocínio em que se baseiam. A outra é que as idéias de teste suportam testes mais eficientes, como descrito abaixo em Design de teste usando a lista.

Todos os exemplos de raiz quadrada descrevem entradas, mas as idéias de teste podem descrever qualquer elemento de um teste executável. Por exemplo, "imprimir em uma LaserJet IIIp" descreve a configuração do teste, enquanto "testar com o banco de dados cheio" descreve a configuração e inicialização do sistema. Essas últimas idéias de teste são em si incompletas. Imprimir o que na impressora? Fazer o que com esse banco de dados cheio? Contudo, elas garantem que idéias importantes não sejam esquecidas, idéias que surgirão posteriormente no design de teste.

As idéias de teste geralmente baseiam-se em modelos de falha, noções sobre quais falhas são plausíveis no software e sobre qual a melhor forma de descobri-las. Por exemplo, considere fronteiras. É seguro supor que a função de raiz quadrada seja implementada de maneira semelhante a esta:

 double sqrt(double x) { if (x < 0) // erro de sinal ... 

É plausível que < seja digitado incorretamente como <=. As pessoas sempre cometem esse tipo de erro; portanto, convém verificar. Não será possível detectar a falha se X tiver o valor 2, pois a expressão incorreta (x<=0) e a expressão correta (x<0) seguirão a mesma ramificação da instrução if. Da mesma forma, se X tiver o valor -5, não será possível encontrar a falha. A única maneira é atribuir a X o valor 0, o que justifica a segunda idéia de teste.

Nesse caso, o modelo de falha é explícito. Em outros casos, é implícito. Por exemplo, sempre que um programa manipula uma estrutura vinculada, convém testá-la com uma circular. É possível ocorrer falhas que levem a uma estrutura circular difícil de ser tratada. Para fins de teste, elas não precisam ser enumeradas - basta saber que uma falha é provável o suficiente para justificar a execução do teste.

Os links a seguir fornecem informações sobre como obter idéias de teste a partir de diversos tipos de modelos de falha. Os dois primeiros são modelos de falha explícita; o último usa falhas implícitas.

É possível aplicar esses modelos de falha a vários artefatos diferentes. Por exemplo, o primeiro descreve o que fazer com boolean expressions. Elas podem ser encontradas no código, em condições de guarda em diagramas de estados e de seqüência, e em descrições de idioma nacional dos comportamentos de método (como pode ser encontrado em uma API publicada).

Às vezes, também é útil haver diretrizes para artefatos específicos. Eis o que está disponível:

Observe que uma Lista de Idéias de Teste específica pode conter idéias de teste provenientes de vários modelos de falha. Também pode conter idéias de teste derivadas de mais de um artefato.

Design de teste por meio da lista Início da página

Suponha que você esteja projetando testes para um método que procura uma seqüência de caracteres em um conjunto seqüencial. Ele pode obedecer ou ignorar maiúsculas e minúsculas na pesquisa, retornando o índice da primeira correspondência encontrada ou -1 se nenhuma for encontrada.

 int Collection.find(String string, Boolean ignoreCase); 

Estas são algumas idéias de teste para o método:

  1. correspondência localizada na primeira posição
  2. correspondência localizada na última posição
  3. nenhuma correspondência localizada
  4. duas ou mais correspondências no conjunto
  5. maiúsculas e minúsculas ignoradas; correspondência localizada, mas não haveria correspondência se as maiúsculas e minúsculas fossem obedecidas
  6. as maiúsculas e minúsculas foram obedecidas e uma correspondência exata foi localizada
  7. maiúsculas e minúsculas obedecidas; foi ignorada uma seqüência de caracteres em que haveria correspondência se as maiúsculas e minúsculas fossem ignoradas

Seria simples implementar sete testes, um para cada idéia de teste. Contudo, idéias de teste distintas podem ser combinadas em um único teste. Por exemplo, esse teste satisfaz às idéias de teste 2, 6 e 7:

Configuração: conjunto inicializado em ["amanhecer", "Amanhecer"]
Chamada: collection.find("Amanhecer", falso)
Resultado esperado: o valor retornado é 1 (seria 0 se "amanhecer" não fosse ignorado)

(Observe que fazer com que idéias de teste sejam não-específicas facilita sua combinação.)

É possível satisfazer a todas as idéias de teste em três testes. Por que três testes que satisfazem a sete idéias de teste seriam melhores que sete testes separados?

  1. Durante a criação de um grande número de testes simples, é comum criar o teste N+1 copiando o teste N, ajustando-o o suficiente para atender à nova idéia de teste. O resultado, especialmente em sistemas mais complexos, é que o teste N+1 provavelmente testa o programa quase da mesma maneira que o teste N: ele segue praticamente os mesmos caminhos através do código.

    Um número menor de testes, cada um satisfazendo a várias idéias de teste, não permite utilizar a abordagem "copiar e ajustar". Cada teste será bastante diferente do último, testando o código de várias maneiras e seguindo caminhos distintos.

    Por que isso seria melhor? Se a Lista de Idéias de Teste estivesse completa, com uma idéia de teste para cada falha do programa, a maneira como os testes foram escritos não seria importante. Mas, na lista, sempre faltam algumas idéias de teste que poderiam localizar erros. Fazer com que cada teste seja muito diferente do último — adicionando uma variedade aparentemente desnecessária — aumentará a chance de que, por azar, um teste passe por cima de um erro. Na verdade, teste menores e mais complexos aumentam a chance de o teste satisfazer a uma idéia de teste que você não sabia ser necessária.

  2. Às vezes, quando você cria testes mais complexos, surgem novas idéias de teste. Isso ocorre com menos freqüência em testes simples, porque, como quase todas as suas ações são semelhantes às do último teste, sua criatividade diminui.

Contudo, há motivos para não criar testes complexos:

  1. Se cada teste satisfizer a uma única idéia de teste e o teste da idéia 2 falhar, você saberá imediatamente qual é a causa mais provável: o programa não lida com uma correspondência na última posição. Se um teste satisfizer às idéias 2, 6 e 7, será mais difícil isolar a falha.

  2. É mais difícil compreender e manter testes complexos. O que o teste está experimentando é menos óbvio.

  3. É mais difícil criar testes complexos. Criar um teste que satisfaça a cinco idéias de teste normalmente leva mais tempo que criar cinco testes que satisfaça a apenas uma. Além disso, é mais fácil cometer erros—quando você pensa que está satisfazendo a todas as cinco mas está satisfazendo a apenas quatro.

Na prática, você precisa encontrar um equilíbrio razoável entre complexidade e simplicidade. Por exemplo, o primeiro conjunto de testes ao qual você submete o sistema (o teste de regressão) deve ser simples, de fácil compreensão e manutenção e destinado a identificar os problemas mais óbvios. Os testes posteriores devem ser mais complexos, mas não tão complexos que não possam ser mantidos.

Depois de terminar um conjunto de testes, é bom verificar se eles contêm os erros característicos de design de teste abordados em Conceitos: Teste do Desenvolvedor.

Uso de idéias de teste antes do teste Início da página

Uma Lista de Idéias de Teste é útil para revisões e inspeções dos artefatos de design. Por exemplo, considere esta parte de um modelo de design:

Fig. 1: Associação entre as Classes Departamento e Funcionário

As regras para a criação de idéias de teste a partir desse modelo fariam com que você considerasse o caso em que um departamento possui vários funcionários. Ao percorrer um design e perguntar "E se, nesse ponto, o departamento tivesse muitos funcionários?", você poderá descobrir erros de design ou análise. Por exemplo, você poderá perceber que apenas um funcionário de cada vez pode ser transferido entre departamentos. Poderá haver um problema se a corporação estiver propensa a eliminar reorganizações em que muitos funcionários precisam ser transferidos.

Tais falhas, em que uma possibilidade não foi notada, são chamadas de falhas de omissão. Como nas falhas em si, você provavelmente omitiu testes que detectam essas falhas no seu esforço de teste. (Consulte, por exemplo, [GLA81], [OST84], [BAS87], [MAR00] e outros estudos que mostram com que freqüência as falhas de omissão passam para a implantação.)

O papel do teste durante o design é abordado em mais detalhes em: Conceitos: Teste Anterior ao Design.

Idéias de Teste e Rastreabilidade Início da página

A rastreabilidade é uma questão de compensação. Seu valor justifica o custo de mantê-la? Essa questão deve ser considerada em Atividade: Definir Necessidades de Avaliação e Rastreabilidade.

Quando a rastreabilidade vale a pena, convém rastrear os testes em relação aos artefatos que os inspiraram. Por exemplo, pode haver rastreabilidade entre uma API e seus testes. Se a API for alterada, você saberá quais testes também deverão ser alterados. Se o código que implementa a API for alterado, você saberá quais testes deverão ser executados. Se um teste o intrigar, você poderá encontrar a API que ele pretende testar.

A Lista de Idéias de Teste adiciona outro nível de rastreabilidade. Você pode rastrear desde um teste até as idéias de teste a que ele satisfaz e, em seguida, desde as idéias de teste até o artefato original.



Copyright  © 1987 - 2001 Rational Software Corporation


Exibir o Rational Unified Process usando quadros

Rational Unified Process