Tópicos

Introdução Início da página

As idéias de teste são baseadas em modelos de erros, em noções dos erros plausíveis em software e na melhor maneira de descobrir esses erros. Esta diretriz mostra como criar idéias de teste a partir de boolean expressions e expressões relacionais. Primeiro, ela motiva as técnicas através de um exame do código e, depois, descreve como aplicá-las se o código ainda não tiver sido escrito ou não estiver disponível.

Boolean Expressions Início da página

Considere o seguinte fragmento de código, extraído de um sistema (imaginário) de gerenciamento de detonação de bombas. Ele é parte do sistema de segurança e controla se o pressionamento do botão "detonar bomba" é obedecido.

if (publicIsClear || technicianClear) {
    bomb.detonate();
}

O código está incorreto. Os || deveriam ser &&. Esse erro terá efeitos graves. Em vez de detonar a bomba quando o técnico e o público tiverem se afastado, o sistema detonará quando qualquer um dos dois tiver se afastado.

Que teste localizaria esse erro?

Considere um teste em que o botão é pressionado quando o técnico e o público tiverem se afastado. O código permitirá a detonação da bomba. Mas — e isso é importante — o código correto (o que usa &&) teria o mesmo resultado. Assim, o teste não consegue localizar esse erro.

Da mesma forma, esse código incorreto apresentará um comportamento correto quando o técnico e o público estiverem próximos à bomba: a bomba não será detonada.

Para localizar o erro, é preciso ter um caso em que o código escrito seja avaliado de forma diferente do código que deveria ter sido escrito. Por exemplo, o público deve ter se afastado, mas o técnico ainda está próximo à bomba. Aqui estão todos os testes em formato de tabela:

publicIsClear

technicianClear

O código escrito...

O código correto...

 

verdadeiro

verdadeiro

detona

teria detonado

o teste é inútil (para esse erro)

verdadeiro

falso

detona

não teria detonado

teste útil

falso

verdadeiro

detona

não teria detonado

teste útil

falso

falso

não detona

não teria detonado

o teste é inútil (para esse erro)


Os dois testes intermediários são úteis para localizar esse erro específico. Entretanto, observe que são redundantes: como qualquer um deles localizará o erro, não será necessário executar os dois.

A expressão poderia apresentar outros erros. Abaixo são apresentadas duas listas de erros comuns em boolean expressions. Os erros à esquerda são todos detectados pela técnica abordada aqui. Os erros à direita talvez não sejam. Assim, essa técnica não detecta todos os erros desejados, mas mesmo assim é útil.

Erros detectados

Erros possivelmente não detectados

Uso do operador incorreto: a||b deveria ser a&&b Uso da variável incorreta: a&&b&&c deveria ser a&&x&&d
Negação omitida ou incorreta: a||b deveria ser !a||b ou !a||b deveria ser a||b Expressão muito simples: a&&b deveria ser a&&b&&c
Ausência de parênteses na expressão: a&&b||c deveria ser a&&(b||c) Expressões com mais de um dos erros na coluna da esquerda
Expressão extremamente complexa: a&&b&&c deveria ser a&&b
(Esse erro não é muito provável, mas pode ser localizado facilmente com testes úteis por outros motivos.)
 

Como essas idéias são usadas? Suponha que você receba uma boolean expression como a&&!b. Você poderia criar uma tabela real como esta:

a

b

a&&!b
(código escrito)

talvez devesse ser
a||!b

talvez devesse ser
!a&&!b

talvez devesse ser
a&&b

...

verdadeiro

verdadeiro

falso

verdadeiro

falso

verdadeiro

...

verdadeiro

falso

verdadeiro

verdadeiro

falso

falso

...

falso

verdadeiro

falso

falso

falso

falso

...

falso

falso

falso

verdadeiro

verdadeiro

falso

...


Se investigar todas as possibilidades, você descobrirá que a primeira, a segunda e a quarta possibilidade são suficientes. A terceira expressão não localizará erros que não seriam localizados por uma das outras. Assim, não é necessário testá-la. (À medida que as expressões se tornam mais complexas, as economias decorrentes de casos desnecessários aumentam rapidamente.)

Evidentemente, uma pessoa sensata não criaria esse tipo de tabela. Felizmente, você não precisará criá-la. É fácil memorizar os casos necessários para expressões simples. (Consulte a próxima seção.) Para expressões mais complexas, como A&&B||C, consulte Idéias de Teste para Combinações de ANDs e ORs, que lista idéias de teste para expressões com dois ou três operadores. Para expressões ainda mais complexas, é possível usar um programa para gerar idéias de teste.

Tabelas de Boolean Expressions Simples Início da página

Se a expressão for A&&B, teste com:

A

B

verdadeiro

verdadeiro

verdadeiro

falso

falso

verdadeiro


Se a expressão for A||B, teste com:

A

B

verdadeiro

falso

falso

verdadeiro

falso

falso


Se a expressão for A1 && A2 && ... && An, teste com:

A1, A2, ... e An são todos verdadeiros

A1 é falso, todo o resto é verdadeiro

A2 é falso, todo o resto é verdadeiro

...

An é falso, todo o resto é verdadeiro


Se a expressão for A1 || A2 || ... || An, teste com:

A1, A2, ... e An são todos falsos

A1 é verdadeiro, todo o resto é falso

A2 é verdadeiro, todo o resto é falso

...

An é verdadeiro, todo o resto é falso


Se a expressão for A, teste com:

A

verdadeiro

falso


Assim, quando precisar testar a&&!b, você poderá aplicar a primeira tabela acima, inverter o sentido de b (porque é negado) e obter esta lista de Idéias de Teste:

  • A verdadeiro, B falso
  • A verdadeiro, B verdadeiro
  • A falso, B falso

Expressões Relacionais Início da página

Um outro exemplo de código com erro é:

if (finished < required) {
    siren.sound();
}

O sinal de < deveria ser <=. Esses erros são bastante comuns. Da mesma forma que com boolean expressions, você pode criar uma tabela de valores de teste e ver quais detectam o erro:

finished

required

o código escrito...

o código correto...

1

5

faz soar a sirene

teria feito soar a sirene

5

5

não faz soar a sirene

teria feito soar a sirene

5

1

não faz soar a sirene

não teria feito soar a sirene


Em termos mais gerais, o erro poderá ser detectado sempre que finished=required. Com base em análises de erros plausíveis, podemos obter estas regras para idéias de teste:

Se a expressão for A<B ou A>=B, teste com

A=B

A ligeiramente menor que B


Se a expressão for A>B ou A<=B, teste com

A=B

A ligeiramente maior que B


O que significa "ligeiramente "? Se A e B forem números inteiros, A deverá ser uma unidade menor ou maior que B. Se forem números de ponto flutuante, A deverá ser um número bem próximo a B. (Provavelmente não é necessário que seja o número de ponto flutuante mais próximo de B.)

Regras para Boolean Expressions e Expressões Relacionais Combinadas Início da página

A maioria dos operadores relacionais ocorre em boolean expressions, como neste exemplo:

if (finished < required) {
    siren.sound();
}

As regras para expressões relacionais resultariam nestas idéias de teste:

  1. finished é igual a required
  2. finished é ligeiramente menor que required

As regras para boolean expressions resultariam nestas idéias de teste:

  1. finished < required deve ser verdadeiro
  2. finished < required deve ser falso

Mas se finished for ligeiramente menor que required, finished < required será verdadeiro, logo, não terá sentido escrever a última expressão.

E se finished for igual a required, finished < required será falso, logo, também não terá sentido escrever a última expressão.

Assim, se uma expressão relacional não contiver operadores booleans (&& e ||), ignore o fato de que ela é também uma boolean expression.

Os fatos são um pouco mais complicados com combinações de operadores booleans e relacionais, como esta:

if (count<5 || always) {
   siren.sound();
}

A partir da expressão relacional, observa-se que:

  • count é ligeiramente menor que 5
  • count é igual a 5

A partir da boolean expression, observa-se que:

  • count<5 é verdadeiro, always é falso
  • count<5 é falso, always é verdadeiro
  • count<5 é falso, always é falso

Essas expressões podem ser combinadas em três idéias de teste mais específicas. (Aqui, observe que count é um número inteiro.)

  1. count=4, always é falso
  2. count=5, always é verdadeiro
  3. count=5, always é falso

Observe que count=5 é usado duas vezes. Talvez seja melhor usá-lo somente uma vez, para permitir o uso de algum outro valor — afinal, por que testar count com 5 duas vezes? Não seria melhor testar uma vez com 5 e outra vez com algum outro valor de modo que count<5 seja falso? Seria, mas é perigoso tentar porque é fácil cometer um erro. Suponha que você tentasse o seguinte:

  1. count=4, always é falso
  2. count=5, always é verdadeiro
  3. count<5 é falso, always é falso

Suponha que haja um erro que possa ser detectado com count=5. Isso significa que o valor 5 fará com que count<5 produza falso no segundo teste, quando o código correto teria produzido verdadeiro. No entanto, imediatamente é feito um OR desse valor falso com o valor de always, que é verdadeiro. Isso significa que o valor de toda a expressão está correto, ainda que o valor da subexpressão relacional esteja incorreto. O erro passará despercebido.

O erro não passará despercebido se o outro count=5 não for tão específico.

Problemas semelhantes ocorrerão quando a expressão relacional estiver do lado direito do operador boolean.

Como é difícil saber quais subexpressões devem ser exatas e quais podem ser gerais, convém tornar todas elas exatas. A alternativa é usar o programa de boolean expression mencionado acima. Ele produz idéias de teste corretas para uma combinação arbitrária de boolean expressions e expressões relacionais.

Idéias de teste sem Código Início da página

Conforme explicado em Conceitos: Teste Anterior ao Design, geralmente é preferível projetar os testes antes de implementar o código. Dessa forma, ainda que as técnicas sejam motivadas por exemplos de código, geralmente elas serão aplicadas sem código. Como?

Determinados artefatos de design, como diagramas de estados e diagramas de seqüência, usam boolean expressions como guardas. Esses casos são diretos; basta adicionar as idéias de teste das boolean expressions à lista de verificação de idéias de teste do artefato. Consulte Diretrizes: Idéias de Teste para Diagramas de Estados e de Atividades.

O caso mais complicado é quando as boolean expressions são implícitas em vez de explícitas. Geralmente, isso ocorre em descrições de APIs. A seguir é apresentado um exemplo. Considere este método:

List matchList(Directory d1, Directory d1,
               FilenameFilter excluder);

A descrição do comportamento desse método poderia ser esta:

Retorna uma Lista dos nomes de caminho absolutos de todos os arquivos que aparecem em ambos os Diretórios. Os subdiretórios são descendentes. [...] Os nomes de arquivo que correspondem a excluder são excluídos da lista retornada. A exclusão (excluder) aplica-se somente a diretórios de nível superior e não a nomes de arquivo em subdiretórios.

As palavras "e" e "ou" não aparecem. Mas quando um nome de arquivo é incluído na lista de retorno? Quando ele aparece no primeiro diretório e no segundo diretório e está em um diretório de nível inferior ou não está excluído especificamente. Em código:

if (appearsInFirst && appearsInSecond &&
    (inLowerLevel || !excluded)) {
  add to list
}

Aqui estão as idéias de teste para essa expressão em formato de tabela:

appearsInFirst

appearsInSecond

inLower

excluded

verdadeiro

verdadeiro

falso

verdadeiro

verdadeiro

verdadeiro

falso

falso

verdadeiro

verdadeiro

verdadeiro

verdadeiro

verdadeiro

falso

falso

falso

falso

verdadeiro

falso

falso


A abordagem geral para descobrir boolean expressions implícitas no texto é primeiro listar as ações descritas (como "retorna um nome correspondente"). Em seguida, escrever uma boolean expression que descreva os casos em que uma ação é adotada e derivar idéias de teste de todas as expressões.

Esse processo dá margem a incompatibilidades. Por exemplo, uma pessoa poderia escrever a boolean expression usada acima. Uma outra poderia dizer que existem efetivamente duas ações distintas: primeiro, o programa descobre nomes correspondentes e, em seguida, os filtra. Assim, em vez de uma expressão, existem duas:

descobrir uma correspondência:
ocorre quando um arquivo está no primeiro diretório e um arquivo com o mesmo nome está no segundo diretório
filtrar uma correspondência:
ocorre quando os arquivos correspondentes estão no nível superior e o nome corresponde ao excluder

Essas abordagens diferentes podem resultar em idéias de teste diferentes e, portanto, em testes diferentes. Mas as diferenças provavelmente não têm muita importância. Ou seja, o tempo seria empregado de uma forma mais produtiva em outras técnicas e na produção de mais testes do que preocupando-se com a expressão correta e testando alternativas. Se você estiver curioso sobre os tipos de diferenças que poderiam surgir, continue lendo.

A segunda pessoa obteria dois conjuntos de idéias de teste.

idéias de teste sobre a descoberta de uma correspondência:

  • o arquivo está no primeiro diretório, o arquivo está no segundo diretório (verdadeiro, verdadeiro)
  • o arquivo está no primeiro diretório, o arquivo não está no segundo diretório (verdadeiro, falso)
  • o arquivo não está no primeiro diretório, o arquivo está no segundo diretório (falso, verdadeiro)

idéias de teste sobre a filtragem de uma correspondência (uma vez que uma tenha sido descoberta):

  • arquivos correspondentes estão no nível superior, o nome corresponde ao excluder (verdadeiro, verdadeiro)
  • arquivos correspondentes estão no nível superior, o nome não corresponde ao excluder (verdadeiro, falso)
  • arquivos correspondentes estão em algum nível inferior, o nome corresponde ao excluder (falso, verdadeiro)

Suponha que esses dois conjuntos de idéias de teste sejam combinados. As idéias do segundo conjunto só têm importância quando o arquivo está em ambos os diretórios; assim, elas podem ser combinadas apenas com a primeira idéia do primeiro conjunto. O resultado disso seria:

arquivo no primeiro diretório

arquivo no segundo diretório

no nível superior

combina com o excluder

verdadeiro

verdadeiro

verdadeiro

verdadeiro

verdadeiro

verdadeiro

verdadeiro

falso

verdadeiro

verdadeiro

falso

verdadeiro


Duas das idéias de teste sobre a descoberta de uma correspondência não aparecem nessa tabela. Podemos adicioná-las da seguinte forma:

verdadeiro

falso

-

-

falso

verdadeiro

-

-


As células em branco indicam que as colunas são irrelevantes.

Agora, essa tabela ficaria bastante semelhante à tabela da primeira pessoa. A semelhança pode ser enfatizada com o uso da mesma terminologia. A tabela da primeira pessoa tem uma coluna denominada "inLower" e a da segunda pessoa tem uma coluna denominada "in top level". É possível convertê-las invertendo o sentido dos valores. Fazendo isso, obtemos esta versão da segunda tabela:

appearsInFirst

appearsInSecond

inLower

excluded

verdadeiro

verdadeiro

falso

verdadeiro

verdadeiro

verdadeiro

falso

falso

verdadeiro

verdadeiro

verdadeiro

verdadeiro

verdadeiro

falso

-

-

falso

verdadeiro

-

-


As três primeiras linhas são idênticas à tabela da primeira pessoa. As duas últimas diferem somente porque essa versão não especifica valores especificados pela primeira. Isso leva a uma suposição sobre a forma como o código foi escrito. A primeira considerou uma boolean expression complexa:

if (appearsInFirst && appearsInSecond &&
    (inLowerLevel || !excluded)) {
  add to list
}

A segunda considera boolean expressions aninhadas:

if (appearsInFirst && appearsInSecond) {
    // found match.
    if (inTopLevel && excluded) {
        // filter it
    }
}     

A diferença entre as duas é que as idéias de teste da primeira detecta dois erros não detectados pelas idéias da segunda porque esses erros não se aplicam.

  1. Na primeira implementação, pode haver um uso incorreto de parênteses. Os parênteses ao redor de || estão corretos ou incorretos? Como a segunda implementação não tem || nem parênteses, o erro não pode existir.
  2. Os requisitos de teste da primeira implementação verificam se o segundo && deve ser um ||. Na segunda implementação, o && explícito é substituído pelo && implícito das instruções if aninhadas. Não há || para o erro &&, por si só. (Talvez o aninhamento esteja incorreto, mas essa técnica não considera isso.)


Copyright  (c) 1987 - 2001 Rational Software Corporation


Exibir o Rational Unified Process usando quadros

Rational Unified Process