Conceito: Catálogo de Idéias de Teste
Uma Lista de Catálogo de Idéias de Teste com as idéias de teste que são mais prováveis para detectar muitas das falhas de software mais comuns. Essa orientação explica como criar uma.
Relacionamentos
Descrição Principal

Introdução

A maior parte da programação consiste em aproveitar os itens que têm sido usados ao longo do tempo, utilizando-os mais uma vez em um contexto distinto. Essas coisas normalmente fazem parte de determinadas estruturas de dados de classes (como listas vinculadas, tabelas hash ou bancos de dados relacionais) ou operações (como procurar, classificar, criar arquivos temporários ou exibir uma janela do navegador). Por exemplo, dois bancos de dados relacionais terão mais características em clichê.

O interessante sobre esses clichês é que eles possuem falhas. As pessoas não inventam novas maneiras imaginativas de inserir algo incorretamente em uma lista duplamente vinculada. Elas tendem a cometer os mesmos erros que elas e outras pessoas cometeram anteriormente. Um programador que exibe uma janela do navegador pode cometer um desses erros reincidentes:

  • cria uma nova janela quando uma já está aberta e deveria ser reutilizada
  • falha ao tornar uma janela do navegador obscura ou minimizada visível
  • utiliza o Internet Explorer quando o usuário escolheu um navegador padrão diferente
  • falha ao verificar se o JavaScript está ativado

Desde que as falhas sejam reincidentes, aqui estão as idéias de teste que podem encontrá-las. Coloque essas idéias de teste no seu catálogo de idéias de teste para que você possa reutilizá-las.

Como um Catálogo de Idéias de Teste Encontra Falhas

Uma das virtudes de um catálogo é que uma única idéia de teste pode ser útil para localizar mais de uma falha básica. Aqui está um exemplo de uma idéia que encontra dois defeitos.

A primeira falha foi localizada em um compilador C. Esse compilador assumiu opções na linha de comandos como "-table" ou "-trace" ou "-nolink". As opções foram abreviadas em sua menor forma exclusiva. Por exemplo, "-ta" era tão bom quanto "-table". Entretanto, "-t" não foi permitido porque era ambíguo: poderia significar "-table" ou "-trace".

Internamente, as opções da linha de comando eram armazenadas em uma tabela como esta:

-table
-trace
-nolink

Uma vez localizada a opção na linha de comando, ela era pesquisada na tabela. Haveria correspondência se fosse o prefixo de qualquer entrada da tabela, ou seja, "-t" corresponde a "-table". Uma vez localizada uma correspondência, o restante da tabela era pesquisado em busca de outra correspondência. Outra correspondência seria um erro porque indicaria ambigüidade.

O código que fazia a pesquisa tinha a seguinte aparência:

for (first=0; first < size; first++)
{
  if (matches(entry[first], thing_sought))
  { /* at least one match */
    for(dup=first+1; dup < size; dup++) /* search for another */
    if (matches(entry[dup], thing_sought)) /* extra match */
      break; /* error out */
    return first;
  }
}
return -1; /* Not found or ambiguity */

Você consegue ver o problema? É bastante sutil.

O problema é a instrução de divisão. Ela pretende dividir o loop incluso mais externo quando uma correspondência duplicada é localizada, mas, na realidade, divide o interno. Isso tem o mesmo efeito que não localizar uma segunda correspondência: o índice da primeira correspondência é retornado.

Observe que esse defeito pode ser encontrado somente se a opção sendo tentada corresponder duàs vezes na tabela, como "-t" faria.

Agora, vamos observar uma segunda falha totalmente diferente.

O código utiliza uma seqüência de caracteres. Ele deve substituir o último '=' na cadeia por um '+'. Se não houver '=', nada é feito. O código utiliza a rotina de biblioteca C padrão strchr. Este é o código:

    ptr = strchr(string, '=');  /* Find last = */ if (ptr != NULL_CHAR)     *ptr = '+';

Este problema também é um pouco sutil.

A função strchr retorna a primeira correspondência na cadeia, não a última. A função correta é strrchr. O problema era provavelmente um erro de digitação. (Na verdade, o verdadeiro problema é que não é muito inteligente colocar duas funções que são diferentes apenas por um erro de impressão em uma biblioteca padrão.)

Essa falha só pode ser localizada quando há dois ou mais sinais de igual na entrada. Ou seja:

  • "a=b" retornaria o resultado correto, "a+b".
  • "noequals" retornaria o resultado correto, "noequals".
  • "a=b=c" retornaria incorretamente "a+b=c", não o correto "a=b+c"

O que é interessante e útil aqui é que temos dois defeitos com causas completamente diferentes (erro tipográfico, equívoco com uma construção C) e manifestações diferentes no código (função errada chamada, uso incorreto da instrução de divisão) que pode ser encontrada pela mesma idéia de teste (procure por algo que ocorra duàs vezes).

Um Bom Catálogo de Idéias de Teste

O que torna um catálogo adequado?

  • Ele contém um pequeno conjunto de idéias de teste que pode localizar um conjunto muito maior de falhas básicas.
  • É fácil ler rapidamente (skim). Você deve ser capaz de ignorar as idéias de teste que não sejam relevantes para a sua situação.
  • Contém somente idéias de teste que você utilizará. Por exemplo, alguém que não lida com navegadores da Web não deve ter que ficar ignorando idéias de teste para os programas que utilizam navegadores da Web. Alguém que trabalha com softwares de jogos precisa de um catálogo menor que alguém que trabalha com softwares nos quais a segurança é vital. A pessoa que lida com jogos pode se concentrar apenas nas idéias de teste com maior chance de localizar falhas.

Considerando essas regras, é melhor que exista mais de um catálogo. Alguns dados e operações são comuns a todas as programações, então suas idéias de teste podem ser colocadas em um catálogo que todos os programadores possam utilizar. Outras são específicas de um determinado domínio; por isso, as idéias de teste correspondentes podem ser incluídas em um catálogo de idéias de teste específico do domínio.

Um catálogo de amostra (Obter o Adobe Reader), utilizado no seguinte exemplo, é um de boa qualidadae a partir do qual começar. Idéias de Teste para Combinações de ANDs e ORs fornece outro exemplo.

Um Exemplo de Como Usar um Catálogo de Idéias de Teste

Aqui está como você pode usar o catálogo de amostra.  Suponha que você esteja implementando este método:

    void applyToCommonFiles(Directory d1,         Directory d2,         Operation op);

applyToCommonFiles utiliza dois diretórios como argumentos. Quando um arquivo no primeiro diretório possui o mesmo nome que um arquivo no segundo, applyToCommonFiles executa alguma operação nesse par de arquivos. Gera subdiretórios.

O método para utilizar o catálogo é varrê-lo, procurando títulos maiores que correspondem a sua situação. Considere as idéias de teste sob cada título para ver se elas são relevantes, e então grave aqueles que são relevantes em uma Lista de Idéias de Teste.

Nota: Essa descrição passo a passo pode fazer com que o uso do catálogo pareça trabalhoso. A leitura sobre a criação da lista de verificação demora mais do que a verdadeira criação de uma lista.

Portanto, no caso de applyToCommonFiles, você pode aplicar o catálogo do modo descrito em todo o restante desta seção.

A primeira entrada é para Qualquer Objeto. Algum desses argumentos poderia ser um ponteiro nulo? Esse é um assunto do contrato entre applyToCommonFiles e os responsáveis pela chamada. O acordo pode determinar que os chamadores não passarão por um ponteiro nulo. Se eles passarem, você não poderá confiar no comportamento esperado: applyToCommonFiles pode executar qualquer ação. Nesse caso, nenhum teste é apropriado, já que nada applyToCommonFiles esteja errado. Entretanto, applyToCommonFiles é necessário para verificar ponteiro nulo, a idéia de teste seria útil. Vamos admitir a última hipótese, que fornece a primeira Lista de Idéias de Teste:

  • d1 é nulo (caso de erro)
  • d2 é nulo (caso de erro)
  • op é nulo (caso de erro)

A entrada do catálogo de idéia é Cadeias. Os nomes dos arquivos são seqüências de caracteres e são comparados para ver se há correspondências. A idéia de testar com a cadeia vazia ("") não parece útil. Presume-se que algumas rotinas de comparação de cadeia padrão serão utilizadas e elas manipularão as cadeias vazias corretamente.

Mas aguarde... Se houver cadeias sendo comparadas, e quanto ao caso? Suponha d1 contém um arquivo com o nome de "File". d2 também contém um arquivo com o nome de "file". Deve haver correspondência entre esses arquivos? No UNIX, certamente não. No Microsoft® Windows®, quase certamente deve haver. Esta é outra idéia de teste:

  • Os arquivos são correspondentes nos dois diretórios, mas o caso dos nomes é diferente.

Observe que essa idéia de teste não é diretamente proveniente do catálogo. No entanto, o catálogo direcionou nossa atenção para um aspecto específico do programa (os nomes de arquivos como cadeias) e nossa criatividade nos propiciou uma idéia adicional. É importante não utilizar o catálogo de forma muito restritiva, utilize-o como uma técnica geradora de debates, uma maneira de inspirar novas idéias.

A próxima entrada é Coletas. Um diretório é um conjunto de arquivos. Muitos programas que lidam com conjuntos falham no conjunto vazio. Alguns que lidam com o conjunto vazio (ou conjuntos com vários elementos) falham em conjuntos com exatamente um elemento. Portanto, estas idéias são úteis:

  • d1 está vazio
  • d2 está vazio
  • d1 tem exatamente um arquivo
  • d2 tem exatamente um arquivo

A próxima idéia consiste em usar um conjunto do maior tamanho possível. applyToCommonFiles normalmente seria utilizado em diretórios pequenos. Em seguida, um usuário os aplica a duas imensas árvores de diretórios com milhares de arquivos, apenas para descobrir que o programa não dispõe de memória suficiente para lidar com esse caso real.

Nesse momento, testar o tamanho máximo absoluto de um diretório não é importante; ele só precisa ser grande o suficiente para o usuário. Entretanto, pelo menos deve haveralgum teste com mais de três arquivos em um diretório.

  • d1 contém arquivos demais
  • d2 contém arquivos demais

A idéia de teste final (duplicar elementos) não se aplica a diretórios de arquivos. Ou seja, se você possui um diretório com dois arquivos que possuem o mesmo nome, você tem um problema independente do applyToCommonFiles-seu sistema de arquivos está corrompido.

A próxima entrada do catálogo é Procurando. Essas idéias podem ser traduzidas para applyToCommonFiles termos como:

  • d1 e d2 não têm arquivos em comum (todos os nomes são diferentes)
  • d1 e d2 têm exatamente um arquivo em comum (é alfabeticamente o último elemento no diretório)
  • d1 e d2 têm mais de um arquivo em comum

A idéia de teste final marca applyToCommonFiles. Ele retorna assim que encontra a primeira correspondência? O comentário entre parênteses na penúltima idéia de teste pressupõe que o programa buscará os arquivos de um diretório usando alguma rotina de biblioteca que os retorne classificados em ordem alfabética. Caso contrário, pode ser melhor utilizar o último arquivo como a correspondência. Antes de passar muito tempo localizando como os arquivos estão ordenados, pergunte-se qual é a probabilidade de localizar defeitos mais facilmente colocando o elemento correspondente por último. Colocar um elemento por último em um conjunto será mais útil se o código percorrer explicitamente o conjunto usando um índice. Se estiver usando um iterador, é muito improvável que a ordem seja importante.

Vamos observar mais uma entrada no catálogo de amostra. A entrada Estruturas vinculadas lembra que estamos comparando diretório árvores, não apenas simples coletas de arquivos. Decidindo como testar applyToCommonFiles nos força a confrontar a falta de conclusão de sua descrição.

Se a estrutura de diretórios se parecer com esta:

Um Diagrama de Estrutura de Diretórios

Figura 1: Uma estrutura de diretório

O applyToCommonFiles desce no diretório Cdir? Isso não faz muito sentido. Não pode haver correspondência com nenhum outro item da outra árvore de diretórios. Na verdade, parece que se os arquivos em subdiretórios podem corresponder somente se os nomes do subdiretório corresponderem. Ou seja, suponha que exista esta estrutura de diretórios:

Segundo Diagrama de Estrutura de Diretório

Figura 2: Uma segunda estrutura de diretórios

Os arquivos denominados "File" não correspondem porque estão em subdiretórios diferentes. Os subdiretórios devem ser descendentes apenas se tiverem o mesmo nome em dois lugares: d1 d2. Isso leva a estas idéias de teste:

  • algum subdiretório em d1 não é localizado em d2 (não é gerado)
  • algum subdiretório em d2 não é localizado em d1 (não é gerado)
  • algum subdiretório aparece em d1 e d2 (gerado)

Contudo, isso levanta outras questões. A operação deve (op) ser aplicada aos subdiretórios correspondentes ou apenas aos arquivos correspondentes? Se for aplicada aos subdiretórios, deve ser aplicada antes de ser gerado ou depois? Isso faz diferença se, por exemplo, a operação excluir o arquivo ou o diretório correspondente. Por esse motivo, a operação deve ser permitida para modificar a estrutura de diretórios? E mais especificamente: qual é o comportamento correto de applyToCommonFiles ? (Essa é a mesma questão que surge com os iteradores.)

Esses tipos de questões normalmente surgem quando você lê cuidadosamente uma descrição de método de criação de idéias de teste. Mas vamos deixá-los de lado por enquanto. Qualquer que sejam as respostas, haverá idéias de teste para elas. As idéias de teste que verificam se o código implementa corretamente as respostas.

Vamos retornar para o catálogo. Ainda não consideramos todas as idéias de teste. A primeira vazia (nada na estrutura)-pede um diretório vazio. Já vimos isso na entrada Coletas. Também já vimos a estrutura mínima não vazia , que é um diretório com um único elemento. Esse tipo de redundância não é incomum, mas é fácil de ser ignorada.

E quanto a uma estrutura circular? As estruturas do diretório não podem ser circulares. Um diretório não pode estar dentro de um de seus descendentes ou dentro de si mesmo, pode? E os atalhos (no Windows) ou links simbólicos (no UNIX)? Se houver um atalho na árvore de diretórios de d1 que aponte para voltar parad1, applyToCommonFiles deve manter-se descendente pra sempre? A resposta poderia levar a uma ou mais novas idéias de teste:

  • d1 é circular em virtude de atalhos ou links simbólicos
  • d2 é circular em virtude de atalhos ou links simbólicos

Dependendo do comportamento correto, pode haver mais idéias de teste.

Finalmente, e quanto a profundidade maior que um? Idéias de teste anteriores irão assegurar que testamos a geração de um nível de subdiretório, mas deveríamos verificar se o applyToCommonFiles continuar descendente:

  • descende por meio de vários níveis (>1) de subdiretórios de d1
  • descende por meio de de vários níveis (>1) de subdiretórios de d2

Criando e Mantendo Seu Próprio Catálogo de Idéias de Teste

Conforme mencionado anteriormente, o catálogo genérico não irá conter todas as idéias de teste que você precisa. Mas os catálogos específicos aos domínios não foram publicados fora das empresas que os criaram. Se você os quiser, terá de criá-los. Eis algumas sugestões.

  • Não preencha um catálogo com as suas especulações sobre as idéias que seriam boas para encontrar defeitos. Lembre-se que cada idéia de teste incluída no catálogo custa tempo e dinheiro:
    • seu tempo para manter o catálogo
    • o tempo de outros programadores para pensar na idéia de teste
    • provavelmente o tempo de outros programadores para implementar um teste

    Adicione apenas as idéias que tenham um registro de controle demonstrado. Você deve ser capaz de apontar pelo menos uma falha real que teria sido capturada pela idéia de teste. O ideal é que essa falha não tenha sido identificada por outro teste, ou seja, uma falha relatada pelo campo. Uma boa maneira de criar catálogos consiste em percorrer o banco de dados de erros de sua empresa e perguntar como cada falha poderia ter sido detectada anteriormente.


  • Não é possível que funcione se a criação e a manutenção de um Catálogo de Idéias de Teste for algo que você faz no tempo livre. Você precisará de tempo especialmente alocado para essa tarefa, como para qualquer outra importante. Recomendamos que você crie e mantenha seu Catálogo de Idéias de Teste durante a Atividade: Melhorar Ativos de Teste.