Testes baseados na especificação - interface - Criado: abril/2001 Últ. atualiz.: jun/2009
Ordem Testes de interface Testes baseados em modelos: Modelos de estado Casos de uso
Tópicos Introdução Partição de equivalência Análise de valores-limite Grafo causa-efeito Gramática
Testes caixa preta Especificação: Requisitos Projeto Independente de notação Partição de equivalência Valores Limite Grafo causa-efeito Tabela de decisão Baseada em linguagem pode ser: Lotos, Labelled transition systems, etc Dependente de notação Baseada em modelo Baseada em linguagem de especificação
Testes caixa preta Testes de interface Especificação: Requisitos Projeto Independente de notação Partição de equivalência Valores Limite Grafo causa-efeito Tabela de decisão ... Testes de interface Baseada em linguagem pode ser: Lotos, Labelled transition systems, etc Dependente de notação Baseada em modelo Baseada em linguagem de especificação
Motivação - aplicabilidade Testes de interface são aplicáveis: Quando só se tem a descrição da interface do software em teste Nos testes de robustez Para criar dados para testes cx branca ou cx preta
Como gerar os dados para esse serviço? ?xml version="1.0"?> <definitions name="StockQuote" targetNamespace="http://example.com/stockquote.wsdl" xmlns:tns="http://example.com/stockquote.wsdl" ... <types> <schema targetNamespace="http://example.com/stockquote.xsd" xmlns="http://www.w3.org/2000/10/XMLSchema"> <element name="TradePriceRequest"> <complexType> <all> <element name="tickerSymbol" type="string"/> </all> </complexType> </element> </schema> </types> Exemplo de WSDL Como gerar os dados para esse serviço?
Partições de equivalência: princípio entradas válidas entradas inválidas domínio de entrada domínio de saída sistema
Partições de equivalência Princípio: O domínio de entrada (ou saída) do programa/função é dividido em um número finito de partições de equivalência supõe-se que dados pertencentes a uma partição têm capacidade de revelar as mesmas classes de falhas uma classe de equivalência representa um conjunto de estados válidos e inválidos para uma dada condição de entrada Geração de testes: selecionar um ou mais dados de cada partição Critério de cobertura: cada partição deve ser considerada ao menos 1 vez
Partição de equivalência: passos Decompor o programa em funções Identificar as variáveis que determinam o comportamento de cada função Particionar os valores de cada variável em classes de equivalência (válidas e inválidas) Especificar os casos de teste: eliminar as classes impossíveis ou os casos desinteressantes selecionar casos de testes cobrindo as classes válidas das diferentes variáveis para cada classe inválida escolha um caso de teste que cubra 1 e somente 1 de cada vez
Determinação das classes de equivalência
Determinação das classes de equivalência
Exemplo 1 Função: Valores válidos para X: Supor uma função que calcula o valor de Valores válidos para X: X -2 X 1 NSF-SWENET
Exemplo 1 Determinação das classes de equivalência: Condições Classes Válidas Classes Inválidas de entrada X -2 C1. X -2 C3. -2 < X < 1 X 1 C2. X 1
Exemplo 1 Casos de teste: selecionar casos de testes cobrindo as classes válidas das diferentes variáveis C1 C2 C3 variável valor X -5 X -2 X 1 X 5 -2 < X < 1 X 0
Exemplo 2 Função MDC, que calcula o máximo divisor comum de dois inteiros (ambos não podem ser negativos) MDC(a,b) = c onde c é um inteiro positivo c é divisor comum de a e b (i.e., c divide a e c divide b) c é maior que todos os divisores comuns de a e b. Exemplo: MDC(45, 27) = 9 MDC (7,13) = 1 MDC(-12, 15) = 3 MDC(13, 0) = 13 MDC(0, 0) indefinido NSF-SWENET
Exemplo 2 - Descrição O algoritmo do MDC pode aceitar quaisquer inteiros como entrada. Neste exemplo vamos considerar que 0, inteiros positivos e inteiros negativos são valores especiais, i.e., são tratados diferentemente pelo programa.
Exemplo 2 – Classes de Equivalência Variáveis Classes de equivalência a C1. a < 0 C2. a = 0 C3. a > 0 b C4. b < 0 C5. b = 0 C6. b > 0
Exemplo 2 – Casos de teste Classes de equivalência 1 2 3 4 5 6 1 2 3 4 5 6 7 8 9 casos de teste Condições: a<0, b<0 a<0, b=0 a<0, b>0 . 1. 2. 3. 4. 5. 6. 7. 8. 9.
Análise de valores-limite Critério de seleção que identifica valores nos limites das classes de equivalência Exemplos: valor mínimo (máximo) igual ao mínimo (máximo) válido uma unidade abaixo do mínimo uma unidade acima do máximo arquivo vazio arquivo maior ou igual à capacidade máxima de armazenamento cálculo que pode levar a “overflow” (“underflow”) erro no primeiro (último) registro
Exemplo 1 - Análise de valores limites No exemplo 1, após determinar as classes de equivalência, devemos fazer uma análise de valores-limites para a escolha dos valores de cada classe (ou partição) de equivalência. Assim, considerando que a função roda em um processador de 32 bits, temos: C1. X -2 -231, -100, -2.1, -2 C2. X 1 1, 1.1,100, 231-1 C3. -2 < X < 1 -1.9, -1, 0, 0.9 NSF-SWENET
Exemplo 2 - Análise de valores limites Para a função MDC Valores limites C1. -231, -1 a = C2. 0, C3. 1, 231-1 C4. -231, -1 b = C5. 0, C6. 1, 231-1
MDC – Plano de Testes (2) Ainda falta algum teste? Complete ... NSF-SWENET
Alguns valores-limites interessantes Tipo do dado Valores Inteiro 0, 1, -1, MaxInt, MinInt Real 0., 1., -1., DblMin, DblMax Boolean Inversão de estado (V F, F V) String Null, string do tamanho da memória virtual, string com caracteres especiais (fim de arquivo, formatação, etc) Descritor de arquivo (tipo inteiro) 0, 1, -1, MaxInt, MinInt descritor de: arquivo aberto para leitura, arquivo aberto para escrita, arquivo vazio, arquivo apagado após o descritor ter sido atribuído Fonte: Projeto Ballista - http://www.ece.cmu.edu/~koopman/ballista/
Limitação Testes baseados em partições de equivalência ou análise de valores-limite: consideram cada valor de entrada isoladamente e se existirem combinações de valores que constituam situações interessantes a serem testadas?
Análise causa - efeito Necessária quando se deseja testar combinações de entradas Utiliza tabelas de decisão e árvores de decisão grafo causa-efeito como modelo auxiliar
Definições Causas: Efeitos: condições de entrada (valor lógico) ações realizadas em resposta às diferentes condições de entrada
Árvore de decisão: exemplo do mdc (a, b) mdc(a,b) = a b = 0 mdc(a, b) 0 0 a exceção = 0 = 0 b Árvores de decisão também podem ser usadas para representar combinações de condições de entrada. A vantagem com relação à representação na forma de tabela é que a visualização é melhor. No entanto essa forma apresenta algumas limitações: é mais propensa a falhas (omissão) requer mais espaço para armazenamento do que a tabela de decisão 0 mdc(a, b)=b
Tabela de decisão Condições de entrada (causas) e1 ... Ações (efeitos) V ... F Condições de entrada (causas) e1 ... X Ações (efeitos) regra
Construção da tabela de decisão a 0 V V F F b 0 V F V F mdc(a, b) = a mdc(a,b) = b mdc(a, b) exceção
Utilidade da tabela de decisão Facilita a determinação de quais testes aplicar. Permite que se analise a especificação para determinar: Redundâncias: duas regras iguais, i.e, mesmas causas levando aos mesmos efeitos Contradições: duas regras com as mesmas causas levando a efeitos diferentes Omissões: não há regras para todas as combinações de causas. Redundâncias e contradições não são necessariamente erros: podem indicar concorrência. Omissões podem indicar situações irrelevantes ou até mesmo impossíveis é preciso fazer uma análise
Limitação das tabelas de decisão Tamanho: 3 causas 23 combinações (regras) 5 causas 25 regras ... 8 causas 28 regras Será que vale a pena testar todas as regras?
Exemplo Supor um sistema bancário que trate somente duas transações: depósito nº da conta quantia saque nº da conta quantia Requisitos: se o comando é depósito e o nº da conta é válido então a quantia é depositada se o comando é saque e o nº da conta é válido e a quantia é válida (0 < quantia saldo) então a quantia sacada se o comando ou nº da conta ou a quantia for inválido então exibir mensagem de erro apropriada
Causas: Efeitos: c1. Comando é depósito c2. Comando é saque c3. Nº da conta é válido c4. Quantia é válida Efeitos: e1. Exibir “comando inválido” e2. Exibir “nº da conta inválido” e3. Exibir “quantia inválida” e4. Depositar a quantia e5. Sacar a quantia nº de regras = 2 4 = 16 será que todas interessam ?
Grafo causa-efeito: notação básica Identidade c1 e1 Negação c1 e1 c2 Ou c1 e1 c2 E
Exemplo: grafo causa-efeito Causas: c1. Comando é depósito c2. Comando é saque c3. Nº da conta é válido c4. Quantia é válida Efeitos: e1. Exibir “comando inválido” e2. Exibir “nº da conta inválido” e3. Exibir “quantia inválida” e4. Depositar a quantia e5. Sacar a quantia c1 e1 c2 e2 c3 e3 e4 c4 e5
Conversão em tabela de decisão Escolher um efeito como ação a ser executada, ie, marcar um “” na regra correspondente a este efeito. Rastrear no grafo quais as combinações de causas que levam a esse efeito e marcar um “V” ou “F” na posição correspondente na tabela Para cada combinação criada, verificar se ocorrem ou não os outros efeitos
Conversão: OU Se e1 = x1 x2: Se e1 = (x1 x2): não escolha x1 = x2 =V Se e1 = (x1 x2): considere todas as combinações que façam com que x1 x2 = F x1 e x2 podem ser causas ou nós intermediários
Exemplo: tabela de decisão Id. 1 2 3 4 5 c1 F c2 F c3 × c4 × e1 e2 e3 e4 e5
Conversão: E Se e1 = x1 x2: Se e1 = (x1 x2): considere todas as combinações que façam com que x1 = x2 = V Se e1 = (x1 x2): considere somente uma combinação que faça com que x1 x2 = F para a combinação escolhida inclua uma e somente uma combinação que leve ao resultado desejado x1 e x2 podem ser causas ou nós intermediários
Exemplo: tabela de decisão Id. 1 2 3 4 5 6 7 c1 F V F c2 F F V c3 × F F c4 × × × e1 e2 e3 e4 e5 c1 c2 c3 e2
Exemplo: tabela de decisão Id. 1 2 3 4 5 6 7 c1 F V F V F V F c2 F F V F V F V c3 × F F V V V V c4 × × × F F V V e1 e2 e3 e4 e5
Geração de testes Tabela de decisão Árvore de decisão critério: exercitar cada regra pelo menos 1 vez Árvore de decisão critério: exercitar cada caminho da raiz até a folha pelo menos 1 vez Eliminar os casos de teste que não fazem sentido ou que são redundantes.
Exemplo: casos de teste Regra 1: comando {depósito, saque}, nº conta, quantia Regra 2: comando = depósito, nº de conta inválido, quantia Regra 3: comando = saque, nº de conta inválido, quantia ...
Restrições c1 c2 E c1 c2 I c1 c2 O Exclusivo Inclusivo Somente um e1 no máximo 1 (0+) Inclusivo no mínimo 1 (1+) Somente um 1 e somente 1 (1) e1 e2 R e1 e2 M Exige e1 e2 Mascara e1 e2
Exemplo: uso de restrição c1 e1 E c2 e2 c3 e3 c4 e4 M e5
Outras formas de gerar dados de teste Além das técnicas vistas, outras podem ser usadas para a geração de dados de teste: Testes aleatórios Uso de heurísticas Algoritmos de otimização Recozimento simulado (simulated annealing), colônia de formigas, hill climbing, ... Algoritmos evolutivos: algoritmos genéticos, otimização extrema, ...
Testes aleatórios Testes gerados aleatoriamente Independem do tipo de dado: inteiros, reais, cadeias de caracteres, ... Todos tratados como cadeias de bits que são alteradas aleatoriamente Não é a melhor forma, em geral, de se conseguir uma boa cobertura de algum critério, mas é fácil de implementar Existem diversas ferramentas: Fuzz, Ridle Úteis em testes de robustez
Uso de gramáticas Gramáticas são adequadas para representar: Exemplos: Entradas de tamanho variável e não limitado Estruturas recursivas Condições-limite Exemplos: Entradas textuais complexas Árvores ex.: documentos XML e HTML são árvores descritas textualmente Estrutura de programas Também podem ser consideradas como árvores descritas textualmente Gramáticas livres de contexto
Exemplo de gramática Cadeias válidas stream ::= action* Símbolo inicial Símbolo não terminal Cadeias válidas stream ::= action* action ::= actG | actB actG ::= “G” s n actB ::= “B” t n s ::= digit1-3 t ::= digit1-3 n ::= digit2 ”.” digit2 digit ::= “0” | “1” | “2” | “3” | “4” | “5” produção ou regra G 17 03.01 B 13 15.20 G 1 04.23 B 123 45.34 Símbolo terminal : zero ou mais repetições m-n: no mínimo m e no máximo n repetições n: exatamente n repetições
Testes baseados em gramáticas Casos de teste = cadeias geradas a partir da gramática Alguns critérios: Cobertura de produções: um caso de teste deve exercitar pelo menos uma produção Cobertura de terminais: um caso de teste deve conter pelo menos um terminal Condições-limite: casos de teste devem exercitar cada produção recursiva: Número mínimo de vezes Número mínimo + 1 Número máximo - 1 Número máximo de vezes
Exemplo de derivação de testes Cobertura de produções nro estabelecido de repetições stream action2 action action actB action G s n action G digit1-3 digit2 ”.” digit2 action G digitdigitdigit digitdigit.digitdigit action G 143 21.01 action ...
Ainda a geração de testes Cobertura probabilística Pode-se associar probabilidades às produções, para indicar qual produção selecionar a cada passo Prioriza produções mais utilizadas Geração de dados inválidos: Obtidos simplesmente aplicando-se mutações às produções ou aos terminais Objetivo: determinar se o programa reage adequadamente a entradas inválidas Ex.: Mutação de produção: B 123 45.34 15 123 45.34 Mutação de terminal: B 123 45.34 B 123 01.34
Exercício 1 Considere uma função com duas variáveis de entrada: Cliente e Qtd, e uma variável de saída, Desconto. Cliente pode ser do tipo A, B ou C e Qtd pode variar de 1 a 1000. A função calcula Desconto de acordo com as seguintes regras: Clientes do tipo A não recebem desconto se nº de itens comprados for inferior a 10; recebem 5% desconto para compras entre 10 e 99 itens; 10% de desconto acima de 100 itens. Clientes do tipo B recebem 5% de desconto para compras abaixo de 10 itens; 15% de desconto entre 10 e 99 itens; 25% de desconto acima de 100 itens. Clientes do tipo C não recebem desconto se nº de itens comprados for inferior a 10; 20% de desconto entre 10 e 99 itens; 25% de desconto acima de 100 itens.
Exercício 2 Considere a tela de login em um sistema mostrada ao lado. O usuário deve fornecer: login: código alfanumérico de 8 caracteres. Se o código é inválido ou não é reconhecido pelo sistema, este solicita ao usuário que o forneça novamente, até que um código válido seja fornecido. senha: código alfanumérico de 5 caracteres. Se a senha é incorreta, o usuário tem uma chance a mais para fornece-la. Se ambas as tentativas falharem, o usuário deve recomeçar todo o processo. Sistema - Tela de Entrada - × Login Senha Cancelar Entrar
Referências R.Binder. “Testing OO Systems”, 2000. P.Jalote. “An Integrated Approach to Sw Engineering”, 2ª ed., 1997, cap9.2.3 G.J.Myers. “The Art of Software Testing”, 1979, cap.4. R.S.Pressman. “Engenharia de Software”, 3ª edição, 1995, cap. 18.5.3. NSF-SWENET. “Unit Testing”. SWENET Module. Obtido em maio/2005.