A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

Jpf@fe.up.pt www.fe.up.pt/~jpf TQS - Teste e Qualidade de Software (Software Testing and Quality) Discussão de Exercícios de Teste Baseado em Modelos.

Apresentações semelhantes


Apresentação em tema: "Jpf@fe.up.pt www.fe.up.pt/~jpf TQS - Teste e Qualidade de Software (Software Testing and Quality) Discussão de Exercícios de Teste Baseado em Modelos."— Transcrição da apresentação:

1 jpf@fe.up.pt www.fe.up.pt/~jpf
TQS - Teste e Qualidade de Software (Software Testing and Quality) Discussão de Exercícios de Teste Baseado em Modelos de Máquina de Estados (Problema da Stack) João Pascoal Faria

2 Exercício 8 Definir um conjunto de casos de teste para testar uma stack (da biblioteca standard) ou outro tipo de objecto com um ciclo de vida interessante. Cada caso de teste deve exercitar uma vida possível. Testar limites e excepções. Cobrir todos os estados e transições. Considera-se a classe Stack do Java Usa-se como fonte a especificação da API (javadoc), que é informal Constrói-se um modelo de estados e transições que servirá de base à definição dos casos de teste Também se mostram especificações formais, apenas para organizar ideias

3 Interface pública da stack
+void push(Object item) +Object pop() throws EmptyStackException +Object peek() throws EmptyStackException +boolean empty() Notas: Notação baseada nos diagramas de classes em UML Para simplificar, são omitidos os métodos herdados doutras classes Para simplificar, foi ignorado o facto de "push" devolver o próprio argumento Apenas especifica sintaxe e não semântica, logo não é suficiente como base para o teste

4 Modelo de estados e transições da stack
push(x) pop()[size>1] push(x) new Stack() Empty Not Empty peek() pop()[size=1] empty()/return true empty()/return false Notas: Notação dos diagramas de estados em UML Distinguem-se estados apenas na medida em que o comportamento do objecto é distinto Cada estado no diagrama é uma abstracção do estado interno do objecto Os eventos são as chamadas de operações O objecto reage aos eventos devolvendo valores e/ou mudando o seu estado interno Segue-se a seguinte convenção: a omissão da chamada de uma operação num estado, significa que a chamada é ilegal Como especificação é incompleto, pois não diz o que devolvem peek e pop (podia-se completar acrescentando uma variável de estado no estado Not Empty)

5 Estratégia de teste Quando se tem acesso às variáveis de instância do objecto (não é o caso presente), a seguir a invocar uma operação de alteração do estado do objecto, pode-se verificar se o estado final é o esperado acedendo directamente às variáveis de instância o que se procura verificar é a pós-condição (ver VDM++) Quando não se tem acesso às variáveis de instância do objecto (caso presente), a seguir a invocar uma operação de alteração do estado do objecto, só se pode verificar de forma indirecta se o estado final é o esperado, invocando uma ou mais operações de consulta quando essas operações não existem, o objecto não é testável ou é menos testável havendo um erro, não sabemos se está na operação de alteração ou na operação de consulta o que podemos verificar é o efeito de pares ou sequências de operações (ver axiomas OBJ) outro exemplo: para verificar se uma factura foi bem inserida num sistema a cuja base de dados não se tem acesso directo, tem de se usar uma funcionalidade de consulta de facturas Cada caso de teste deve exercitar uma vida possível do objecto, da criação até à destruição input: sequência de chamadas de operações (alternando normalmente operações de alteração e de consulta) output: sequência de valores devolvidos (a comparar com valores esperados) Interessa encontrar um conjunto de casos de teste que cubra todos os estados e todas as transições válidas, bem como casos de teste que exercitem transições não válidas Separar casos de teste com entradas válidas (tanto com valores normais como com valores fronteira) de casos de teste com entradas inválidas (possivelmente gerando excepções, um caso de teste para cada excepção)

6 Casos de teste Caso de teste 1, com entradas válidas normais (descrito informalmente) new Stack() empty() == true push(1) empty() == false peek() == 1 push(2) empty() == false peek() == 2 pop() == 2 empty() == false peek() == 1 pop() == 1 empty() == true Exercita todos os estados e transições válidos (excepto destruição de stack não vazia) Podemos confiar que os métodos de consulta só consultam? (Em C++ sim: usando const o compilador verifica) Caso de teste 2, com entradas inválidas new Stack(); peek() == EmptyStackException Caso de teste 3, com entradas inválidas new Stack(); pop() == EmptyStackException Caso de teste 4, entradas válidas normais new Stack(); push(1) Exercita destruição de stack não vazia. É necessário? Como se verificam erros? Forçando a eliminação do objecto invocando o garbage collector? Caso de teste 5, entradas válidas, valores fronteira new Stack(); push(null); peek() == null Caso de teste 6, com entradas válidas, valores fronteira new Stack(); push(1); push(1); pop() == 1; pop()==1; empty()==true input output esperado

7 Casos de teste – outra forma de apresentação
Inputs Outputs esperados Comentário 1 new Stack() empty() push(1) empty() peek() push(2) empty() peek() pop() empty() peek() pop() empty() true false 1 false 2 2 false 1 1 true Caso de teste com entradas válidas normais. Exercita todos os estados e transições válidos (excepto destruição de stack não vazia). Podemos confiar que os métodos de consulta só consultam? (Em C++ sim: usando const o compilador verifica) 2 new Stack() peek() EmptyStackException Caso de teste com entradas inválidas. 3 new Stack() pop() ...

8 * Especificação formal da stack em VDM++, com base num modelo para o estado interno
class Stack instance variables elems : seq of Object; operations Stack() ext wr elems post elems = [ ]; push (item: Object) ext wr elems post elems = [item] ^ ~elems; pop() res : Object pre elems <> [ ] post res = hd elems and elems = tl ~elems; empty() res : bool post res = (elems = [ ]); peek() res : Object post res = hd elems; end Stack Escolhe-se uma representação para o estado interno de uma stack. Não tem de corresponder à implementação, serve apenas para especificar formalmente a semântica das operações! Cláusula que lista as variáveis de instância cujo valor pode ser alterado pela operação. concatenate Pré-condição. Condição nos argumentos de chamada e estado inicial do objecto a que tem de obedecer qualquer chamada válida. tail Pós-condição. Condição que relaciona o resultado da operação e o estado final do objecto com os argumentos de chamada e o estado inicial do objecto (indicado com ~). valor antigo head

9 * Especificação formal da stack em OBJ, prescindindo de modelo para o estado interno
Mais abstracta: especifica semântica de operações por axiomas, sem necessidade de escolher uma representação de dados interna (cf. noção de ADT)! Mas é mais difícil saber se a especificação está completa! Spec: Stack; Extend Object by Sorts: Stack; Operations: newstack:  Stack push: Stack  Object  Stack pop: Stack  Stack empty: Stack  Bool peek: Stack  Object Variables://não confundir com var. instância s: Stack; x: Object Axioms: pop(newstack) = EmptyStackException; peek(newstack) = EmptyStackException; pop(push(s,x)) = s; peek(push(s,x)) = x; empty(newstack) = true; empty(push(s,x)) = false; Uma stack é sempre representada por uma expressão de construção, push(push(push(newstack, 1), 2), 3) Axiomas permitem simplificar/avaliar expressões peek(pop(push(push(newstack, 1), 2))) = = peek(push(newstack, 1)) = 1 empty(pop(push(push(newstack, 1), 2))) = = empty(push(newstack, 1)) = false

10 * Casos de teste com base nos axiomas
Caso de teste 1 new Stack() pop() == EmptyStackException Caso de teste 2 new Stack() peek() == EmptyStackException Caso de teste 3 new Stack() s2  clone() push(1) pop() equals(s2) == true pode-se confiar em clone e equals? Caso de teste 4 new Stack() push(1) peek() == 1 Caso de teste 5 new Stack() empty() == true Caso de teste 6 new Stack() push(1) empty() == false

11 * Especificação formal da stack como processo em CSP (Communicating Sequential Processes)
começa por se comportar como EmptyStack Mais operacional! executa a acção enviar o valor "true" (mensagem) pelo canal "empty" e depois comporta-se como EmptyStack Stack = EmptyStack EmptyStack = empty! true  EmptyStack  peek! EmptyStackException  EmptyStack  pop! EmptyStackException  EmptyStack  push? x  OneElemStack(x); EmptyStack OneElemStack(x) = empty! false  OneElemStack(x)  peek! x  OneElemStack(x)  pop! x  Skip  push? y  OneElemStack(y); OneElemStack(x) "" indica selecção ("ou") processos executa a acção receber o valor x (mensagem) pelo canal "push" e depois comporta-se como a composição sequencial dos processos OneElemStack(x) e EmptyStack "Skip" indica terminação com sucesso ";" indica composição sequencial de processos

12 * Caso de teste aleatório como processo em CSP
|| indica paralelismo (composição em paralelo) bloqueia (falha) escolha não determinística interna Test = TestDriver || Stack TestDriver = empty? b  if b=true then TestDriver else Stop ⊓ peek? z  if z=EmptyStackException then TestDriver else Stop ⊓ pop? z  if z=EmptyStackException then TestDriver else Stop ⊓ push! x  TestDriver1(x); TestDriver ⊓ TestDriver1(x) = empty? b  if b=false then TestDriver1(x) else Stop ⊓ peek? z  if z=x then TestDriver1(x) else Stop ⊓ pop? z  if z=x then Skip else Stop ⊓ push! y: Object  TestDriver1(y); TestDriver1(x) Processo "dual" da Stack


Carregar ppt "Jpf@fe.up.pt www.fe.up.pt/~jpf TQS - Teste e Qualidade de Software (Software Testing and Quality) Discussão de Exercícios de Teste Baseado em Modelos."

Apresentações semelhantes


Anúncios Google