• Nenhum resultado encontrado

A técnica estrutural estabelece os requisitos de teste com base nos aspectos elementares dos programas. Essa técnica abstrai um programaP em um grafo orientado, conhecido como Grafo de Fluxo de Controle (CFG - Control Flow Graph), representado por (G = (N, E, s)), no qual são identificados vértices ou nós (N) que correspondem a blocos indivisíveis de comandos executados sequencialmente, arestas (E) que especificam possíveis fluxos de controle entre os vértices, além de um único nó de entrada s 2 N e um único nó de saída.

A Figura5ilustra o grafo de fluxo de controle da função main do programa Identifier (Figura 4). Este programa, extraído do livro de Maldonado et al. (2004), determina quando um dado de entrada é um identificador válido ou não. Neste código é possível perceber uma

3.3. Teste Estrutural de Programas Sequenciais 29

numeração à esquerda dos comandos que não faz parte do código em si e foi inserida para ilustrar a qual vértice do CFG o comando pertence. Portanto, as nove primeiras linhas com identificação /* 1 */, resultarão no vértice 1 do grafo da Figura5. O mapeamento dos comandos em um único vértice tem como premissa a execução sequencial do primeiro comando de um bloco, bem como dos demais comandos deste mesmo bloco e ainda a não existência de desvio de execução para nenhum comando pertencente ao bloco.

/***************************************************************************************/ Identifier.c

ESPECIFICAÇÃO: O programa deve determinar se um identificador é ou não válido em ‘Silly Pascal’ (uma estranha variante do Pascal). Um identificador válido deve começar com uma letra e conter apenas letras e dígitos. Além disso, deve ter no mínimo 1 caractere e no máximo 6 caracteres de comprimento.

/***************************************************************************************/ #include <stdio.h> |

main() | int valid_s(char ch)

/* 1 */ { | /* 1 */ {

/* 1 */ char achar; | /* 1 */ if(((ch >= ’A’) &&

/* 1 */ int length, valid_id; | (ch <= ’Z’)) ||

/* 1 */ length = 0; | ((ch >= ’a’) &&

/* 1 */ valid_id = 1; | (ch <= ’z’)))

/* 1 */ printf ("Identificador: "); | /* 2 */ {

/* 1 */ achar = fgetc (stdin); | /* 2 */ return (1); /* 1 */ valid_id = valid_s(achar); | /* 2 */ }

/* 1 */ if(valid_id) | /* 3 */ else

/* 2 */ { | /* 3 */ {

/* 2 */ length = 1; | /* 3 */ return (0);

/* 2 */ } | /* 3 */ }

/* 3 */ achar = fgetc (stdin); | /* 4 */ }

/* 4 */ while(achar != ’\n’) |

/* 5 */ { | int valid_f(char ch)

/* 5 */ if(!(valid_f(achar))) | /* 1 */ {

/* 6 */ { | /* 1 */ if(((ch >= ’A’) &&

/* 6 */ valid_id = 0; | (ch <= ’Z’)) ||

/* 6 */ } | ((ch >= ’a’) &&

/* 7 */ length++; | (ch <= ’z’)) ||

/* 7 */ achar = fgetc (stdin); | ((ch >= ’0’) &&

/* 7 */ } | (ch <= ’9’)))

/* 8 */ if(valid_id && | /* 2 */ {

(length >= 1) && (length < 6)) | /* 2 */ return (1);

/* 9 */ { | /* 2 */ }

/* 9 */ printf ("Valido\n"); | /* 3 */ else

/* 9 */ } | /* 3 */ { /* 10 */ else | /* 3 */ return (0); /* 10 */ { | /* 3 */ } /* 10 */ printf ("Invalid\n"); | /* 4 */ } /* 10 */ } | /* 11 */ } |

Figura 4 – Código fonte do programa sequencial Identifier que determina quando um dado de entrada é um identificador válido ou não (este código contém ao menos um defeito). A numeração à esquerda dos comandos representam blocos indivisíveis de execução que serão mapeados em vértices do CFG (MALDONADO et al.,2004).

Os critérios que compõem a técnica estrutural são categorizados com base na com- plexidade, no fluxo de controle e no fluxo de dados (MALDONADO, 1991; PRESSMAN,

2011)

A complexidade ciclomática é uma métrica de software que quantifica a complexidade lógica de um programa com um valor numérico. Este valor define o número de caminhos inde-

Figura 5 – CFG da função main do programa Identifier, em que os vértices representam os blocos indivisíveis de comandos e as arestas representam os possíveis fluxos de controle entre os vértices (MALDONADO et al.,2004).

pendentes no conjunto base de um programa, fornecendo um limite superior para a quantidade de testes que devem ser derivados com o objetivo de garantir que todos os comandos tenham sido executados pelo menos uma vez (BARBOSA et al.,2007;PRESSMAN,2011).

Critérios baseados na complexidade exploram as informações de complexidade ciclomá- tica do CFG do programa para derivar requisitos de teste, sendo o critério de McCabe (MCCABE,

1976) o mais conhecido deles. Basicamente, esse critério requer que seja executado um conjunto de caminhos linearmente independentes do grafo do programa (MCCABE,1976;PRESSMAN,

2011).

Caminho independente é qualquer caminho do programa que insira pelo menos um novo conjunto de instruções de processamento ou uma nova condição. O caminho independente em um CFG deve incluir pelo menos uma aresta que não tenha sido percorrida antes que o caminho seja definido (BARBOSA et al.,2007). Esta métrica fornece uma medida quantitativa da dificuldade para a condução dos testes (PRESSMAN,2011).

Os critérios baseados em fluxo de controle usam somente elementos como comandos ou desvios presentes no programa para derivar os requisitos de teste. Dentre os principais critérios baseados no fluxo de controle estão (MYERS; SANDLER,2004;BARBOSA et al.,2007):

3.3. Teste Estrutural de Programas Sequenciais 31

pelo menos uma vez;

• Todas-Arestas: requer que se exercite pelo menos uma vez cada aresta do CFG, ou seja, cada desvio de fluxo de controle presente no programa;

• Todos-Caminhos: requer que todos os caminhos sejam executados ao menos uma vez. Para a realização da atividade de teste espera-se que no mínimo a cobertura do critério Todos-Nós seja empregada. Isso garante que todos os comandos do programa em teste foram executados pelo menos uma vez. Entretanto, os testes que utilizam apenas os critérios Todos- Nós e Todos-Arestas têm se mostrado ineficazes, não revelando defeitos simples presentes até mesmo em alguns programas pequenos (BARBOSA et al.,2007). Outra consideração é a impraticabilidade, em geral, da cobertura do critério Todos-Caminhos já que a presença de laços pode elevar o número de caminhos a uma quantidade muito grande ou infinita deles (BARBOSA et al.,2007).

Visando contornar as situações expostas anteriormente,Rapps e Weyuker(1985) pro- puseram um conjunto de critérios baseados em fluxo de dados que tem como característica derivar casos de teste através da análise das associações entre a definição de uma variável e seus possíveis usos subsequentes. Os autores tinham como meta inserir mais rigor no teste estrutural e para tanto criaram uma série de novos conceitos. Dentre os conceitos estão a extensão do CFG para um grafo rotulado conhecido como Grafo Def-Uso (def-use graph), Figura6, na qual são inseridas informações a respeito do fluxo de dados do programa a partir da verificação dos pontos do código, onde existem definição de variáveis, ou seja, a atribuição de um valor a uma variável, e uso da variável representando o ponto em que este valor é utilizado. O uso de variável pode ser de dois tipos: uso predicativo (p-uso ou up) ou uso computacional (c-uso ou uc). O uso predicativo ocorre quando a variável é utilizada em uma condição e afeta de forma direta o fluxo de controle do programa; já no uso computacional a variável é usada em uma computação.

Outros conceitos são os de caminhos livre de definição e Du-caminho. Um caminho é categorizado como livre de definição quando uma variável x é definida em um nó i, usada em um nó j ou em uma aresta que chega a j, e o caminho (i,n1, ...,nm,j), m > 0 não apresente

nenhuma definição de x nos nós (n1, ..., nm) percorrido do nó i ao nó j e do nó i a aresta (nm, j)

(DELAMARO; MALDONADO; JINO,2007). Du-caminho é um caminho simples (no qual não existe repetição de nós exceto possivelmente o primeiro e o último) livre de definição em relação a uma variável x do nó i até o nó j que possui uma definição da variável x no nó i e um uso no nó j (MALDONADO,1991).

Os principais critérios baseados em fluxo de dados são apresentados abaixo:

• Todas-Definições: todas as definições de variáveis devem ser exercitadas pelo menos uma vez por um p-uso ou c-uso;

Figura 6 – Grafo Def-Uso da função main do programa Identifier em que é possível perceber onde as definições, usos computacionais e usos predicativos ocorrem (MALDONADO et al.,2004).

• Todos-Usos: requer que se exercite todas as associações de definição e uso (c-usos e p-usos) das variáveis por pelo menos um caminho livre de definição. Este critério pode ainda ser representado pelas variações Todos-p-Usos, Todos-p-Usos/Alguns-c-Usos e Todos-c-Usos/Alguns-p-Usos;

• Todos-Du-Caminhos: requer que se exercite todas as associações de definição e uso (c-usos e p-usos) das variáveis por todos os caminhos livres de definição e livres de laço que cubram essa associação.

Na Tabela1são apresentados alguns exemplos de elementos e critérios relacionados ao programa Identifier4.

Muitos dos critérios baseados em fluxo de dados exigem que o uso de uma variável ocorra de modo explícito e, além disso, a presença de caminhos não executáveis não garantem a inclusão do critério Todas-Arestas (FRANKL,1987).

3.4. Teste Estrutural de Programas Concorrentes 33