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) Teste baseado em modelos (visuais e formais): exemplo.

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) Teste baseado em modelos (visuais e formais): exemplo."— 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) Teste baseado em modelos (visuais e formais): exemplo da stack (v2.0) João Pascoal Faria

2 Enunciado Definir um conjunto de casos de teste para testar uma stack (da biblioteca standard), com base num modelo de máquina de estados. Cada caso de teste deve exercitar uma vida possível. Testar limites e excepções. Cobrir todos os estados e transições. Considerar a classe Stack do Java Usar como fonte a especificação da API (javadoc), que é informal Constrói-se um modelo de máquina de estados (modelo visual) que servirá de base à definição dos casos de teste Também se mostram modelos formais (especificações formais) que funcionam como especificações completas da stack e geração de casos de teste a partir desses modelos

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 Estado interno não é visível 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 Obtenção do modelo de máquina de estados finito
Estado interno da stack: lista de items armazenados Número (quase) infinito de estados possíveis (limitado apenas por memória disponível) Estados a considerar na máquina de estados finita são abstracções do estados interno Grupos de estados internos Condições sobre o estado interno Distinguem-se estados apenas na medida em que o comportamento do objecto é distinto Diferentes métodos disponíveis Comportamento diferente dos métodos

5 Modelo de máquina de estados
evento (chamada de método) condição estado transição push(x) pop()[size>1] push(x) new Stack() Empty Not Empty peek() pop()[size=1] empty()/return false empty()/return true acção Notas: Notação dos diagramas de estados em UML O objecto reage aos eventos devolvendo valores e/ou mudando o seu estado interno Convenção seguida: 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)

6 Estratégia de teste Se as variáveis de instância (campos) do objecto fossem públicas, a seguir a invocar uma operação de alteração do estado do objecto, podia-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++) Como não temos acesso às variáveis de instância do objecto, 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)

7 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

8 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() ...

9 * Especificação formal da stack por contractos em VDM++, usando um 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 (abstracta) para o estado interno da stack. Não tem de corresponder à implementação, serve apenas para formalizar a semântica das operações! concatenar Cláusula que lista as variáveis de instância cujo valor pode ser alterado pela operação. valor antigo Pré-condição: Condição nos argumentos de chamada e estado inicial do objecto a que tem de obedecer qualquer chamada válida tail head 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 ~)

10 * Teste baseado em contractos
Pré-condições e pós-condições Testes baseados em cobertura de condições / decisões Teste com entradas inválidas: Violando pré-condições Se pré-condição tiver algum tipo conjunção (and), pode-se desdobrar em vários casos (violar uma parte de cada vez) Teste com entradas válidas: Obedecendo a pré-condições Se pré-condição tiver algum tipo de disjunção (or), pode-se desdobrar em vários casos (satisfazer uma parte de cada vez) Se pós-condição tiver algum tipo de disjunção (or), pode-se desdobrar em vários casos Pode-se combinar com cobertura de domínios: no caso de tipos com número reduzido de valores possíveis (por exemplo booleanos), cobrir os vários casos Verificação de cada invocação de operação: Se a pré-condição for violada, deve ser lançada uma excepção Senão, deve-se verificar a pós-condição

11 * Especificação formal da stack como ADT por axiomas em OBJ
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; Mais abstracta: especifica semântica de operações por axiomas, sem necessidade de escolher uma representação de dados interna! Mas é mais difícil saber se a especificação está completa! 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

12 * Teste baseado 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

13 * Especificação formal da stack como processo em CSP (Communicating Sequential Processes)
começa por se comportar como EmptyStack envia a mensagem "true" 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) ou processos recebe uma mensagem para a variável x pelo canal "push" e depois comporta-se como a composição sequencial dos processos OneElemStack(x) e EmptyStack push peek empty pop termina processo (mais adequado para modelar concorrência)

14 * Teste aleatório como processo dual em CSP
Test = TestDriver || Stack bloqueia (falha) escolha não determinística composição em paralelo Processo "dual" da 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) push peek empty pop Stack


Carregar ppt "Jpf@fe.up.pt www.fe.up.pt/~jpf TQS - Teste e Qualidade de Software (Software Testing and Quality) Teste baseado em modelos (visuais e formais): exemplo."

Apresentações semelhantes


Anúncios Google