Teste Estrutural
Upcoming SlideShare
Loading in...5
×

Like this? Share it with your network

Share
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
3,338
On Slideshare
3,321
From Embeds
17
Number of Embeds
1

Actions

Shares
Downloads
67
Comments
0
Likes
0

Embeds 17

http://www.slideshare.net 17

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Teste Estrutural Arndt von Staa Departamento de Informática PUC-Rio Outubro 2008
  • 2. Especificação
    • Objetivo desse módulo
      • Apresentar os conceitos de teste estrutural visando o teste de unidades.
    • Justificativa
      • O teste estrutural é utilizado tipicamente para testar módulos e classes e, assim, verificar se os componentes elementares possuem o nível de qualidade necessário.
  • 3. Sumário
    • Critérios de valoração
    • Princípios de teste estrutural
    • Teste de unidades
    • Grafo da estrutura do código
    • Arrasto
    • Critérios de cobertura
    • Teste de funções encapsuladas
    • Critério cobertura de caminhos
    • Critério fluxo de dados
    • Teste de exceções
    • Análise estática
    • Recursos locais
    • Módulos dublê
  • 4. Critérios de seleção
    • Caixa fechada : dependem exclusivamente da especificação
    • Caixa aberta : dependem da estrutura do código executável
    • Caixa entre-aberta : usualmente dependem da estrutura dos dados mas não do código executável
    • Geração : criação (manual ou não) sistemática da massa de testes
    • Geração automatizada : criação da massa de testes por intermédio de um programa
    • Teste : execução (manual ou não) da massa de testes
    • Teste automatizado : execução da massa de teste sem intervenção humana
  • 5. Critérios de valoração
    • Ao testar uma comparação a <= b , escolha sempre os três casos:
        • a = b – 
        • a = b
        • a = b + 
      •  é o menor valor possível que torne verdadeira a relação a +  >= b quando for verdadeira a relação a < b .
        • para valores inteiros  é 1 .
        • para valores vírgula flutuante
          • erro absoluto :
            • a –  <= b <= a + 
            • depende da magnitude de a e b
          • erro relativo :
            • 1 –  <= b / a <= 1 + 
            • independe da magnitude
            •  pode ser o número de algarismos significativos desejado
            • procure usar sempre que possível erro relativo ao testar
  • 6. Critérios de valoração
    • Caso listas de strings sejam ordenadas precisa testar a sensibilidade dos caracteres nas diferentes posições: primeiro, segundo, meio, penúltimo, último
    • Para caracteres temos os problemas
      • descontinuidade dos valores numéricos
        • caracteres ASCII minúsculos, maiúsculos e diacríticos estão em regiões diferentes
      • vários caracteres diferentes representarem o mesmo caractere de comparação
        • a == A == á == à == â == ã == ä == ...
      • ASCII e Unicode são diferentes
  • 7. Critérios de valoração
    • Qual a relação: José ? JOSÉ ? JOSE ? jÓsÉ
      • cada caractere tem um valor numérico e a comparação simples utiliza esse valor
        • strcmp e memcmp
        • Jóse > Jose [ ó > o ] ; jóse > Jose [ j > J ]
    • Onde fica o caractere Euro: € na tabela Unicode?
      • Em ASCII latin é 80 hexadecimal ou 128 decimal
  • 8. Critérios de valoração: tabela ISO / ASCII
    • 0 1 2 3 4 5 6 7 8 9 A B C D E F
    • 2 ! &quot; # $ % & ' ( ) * + , - . /
    • 3 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
    • 4 @ A B C D E F G H I J K L M N O
    • 5 P Q R S T U V W X Y Z [ ] ^ _
    • 6 ` a b c d e f g h i j k l m n o
    • 7 p q r s t u v w x y z { | } ~ 
    • 8 €  ‚ ƒ „ … † ‡ ˆ ‰ Š ‹ Œ  Ž 
    • 9  ‘ ’ “ ” • – — ˜ ™ š › œ  ž Ÿ
    • A   ¡ ¢ £ ¤ ¥ ¦ § ¨ © ª « ¬ ­ ® ¯
    • B ° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿
    • C À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï
    • D Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß
    • E à á â ã ä å æ ç è é ê ë ì í î ï
    • F ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý þ ÿ
    parte ASCII parte ISO
  • 9. Critérios de valoração: equalização de chars
    • static const char ConversionTable[ ] = // ISO ASCII Latin, idiom: portuguese
    • {
    • // 0 1 2 3 4 5 6 7 8 9 A B C D E F
    • /*0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, ' ', ' ', 0, 0, ' ', 0, 0,
    • /*1*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    • /*2*/ ' ', '!','&quot;', '#', '$', '%', '&',''', '(', '}', '*', '+', ',', '-', '.', '/',
    • /*3*/ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
    • /*4*/ '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
    • /*5*/ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '[','apos;, ']', '^', '_',
    • /*6*/ ''', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
    • /*7*/ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', 0,
    • /*8*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    • /*9*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    • /*A*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    • /*B*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    • /*C*/ 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 0, 0,
    • /*D*/ 0, 'n', 'o', 'o', 'o', 'o', 'o', 0, 0, 'u', 'u', 'u', 'u', 0, 0, 0,
    • /*E*/ 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 0, 0,
    • /*F*/ 0, 'n', 'o', 'o', 'o', 'o', 'o', 0, 0, 'u', 'u', 'u', 'u', 0, 0, 0
    • } ;
    • for ( i == 0 ; i < len ; i++ ) // assumindo que o tamanho seja igual
    • {
    • if ( ConversionTable[ strA[ i ]] < ConversionTable[ strB[ i ]] ) return IS_LESS ;
    • if ( ConversionTable[ strA[ i ]] > ConversionTable[ strB[ i ]] ) return IS_GREATER ;
    • }
    • return IS_EQUAL ;
  • 10. Critérios de valoração
    • Cada elemento de uma enumeração deve ser testado
      • caracteres são enumerações
      • dependendo do caso pode-se simplificar
        • testando intervalos 'a' <= ch <= 'z‘
          • mas... veja a tabela anterior
      • listas de estados da União são enumerações
        • testar encontrar
        • testar não encontrar
  • 11. Critérios de valoração
    • Ao testar valores de tamanho variável
        • por exemplo: arquivos, vetores, strings
      • gere casos de teste para
        • tamanho zero
        • tamanho mínimo-1 , caso exista limite inferior
        • tamanho mínimo
        • tamanho médio
        • tamanho máximo
        • tamanho máximo+1
  • 12. Critérios de valoração
    • Ao acessar valores pertencentes a um conjunto dinamicamente criado , considere sempre
        • conjunto vazio
        • conjunto contendo exatamente um elemento
        • e conjunto contendo três ou mais elementos
      • acesse
        • o primeiro elemento
        • um elemento mais ou menos no meio do conjunto
        • o último elemento
  • 13. Critérios de valoração
    • Ao procurar elementos pertencentes a conjuntos
      • o elemento inexistente imediatamente anterior ao primeiro
        • em um conjunto ordenado deve ser possível gerar um valor anterior ao primeiro elemento
      • o primeiro elemento
      • o elemento inexistente entre o primeiro e o segundo
        • segundo a ordem de procura do algoritmo empregado
      • um elemento mais ou menos no meio do conjunto
      • um elemento inexistente mais ou menos no meio do conjunto
      • o elemento inexistente entre o penúltimo e o último
      • o último elemento
      • o elemento inexistente imediatamente após ao último
  • 14. Critérios de valoração
    • Ao testar nomes de arquivos
      • nome ( string ) nulo
      • nomes com caracteres ilegais, ex.: ? * / < > &quot; |
      • sempre para os casos existe e não existe
        • nome sem extensão
        • nome com extensão igual ao default
        • nome com extensão diferente do default
        • nome com duas extensões (ex. xpto.x.y)
        • nome com diretório absoluto
        • nome com diretório relativo
  • 15. Critérios de valoração
    • Caso existam, as relações inversas foram exploradas nos testes?
      • isso pode ser generalizado para redundâncias judiciosamente inseridas no código
    • Caso existam, formas de calcular alternativas foram utilizadas como oráculos?
      • trata-se aqui de redundância de forma de calcular
    • Foram forçadas as ocorrências das condições de erro ?
      • foram exercitados todos os throw , condições de retorno e mensagens de erro?
    • As características de desempenho estão dentro dos limites estabelecidos?
    Adaptado de: [ Hunt & Thomas, 2004]
  • 16. Critérios de valoração
    • Os valores estão em conformidade com um formato especificado (ou sub-entendido)?
      • o formato de armazenamento é respeitado sempre?
        • ex. formato para armazenar data
      • o formato de apresentação é respeitado sempre?
        • ex. formato de exibir data
    Adaptado de: [ Hunt & Thomas, 2004]
  • 17. Critérios de valoração
    • Os valores estão ordenados (ou não) conforme especificado?
    • O domínio dos valores (mínimo e máximo) são respeitados?
      • o domínio de valores plausíveis é controlado?
    • O código depende de condições que estão fora do seu controle?
      • objetos externos utilizados precisam estar em determinado estado?
      • o usuário precisa estar autorizado?
    • A cardinalidade (número de objetos de um conjunto) ou a contagem estão corretas?
    • A temporização é respeitada?
      • os eventos ocorrem na ordem correta?
      • De acordo com as restrições de tempo especificadas?
    Adaptado de: [ Hunt & Thomas, 2004]
  • 18. Critérios de valoração
    • Todos os atributos e referências dos objetos alterados devem ser verificados
      • pode tornar necessária a introdução de redundâncias
        • ver teste baseado em assertivas
          • == Test emptying empty list
          • =emptylist Lista_1
          • =getnumelem Lista_1 0
          • =movefirst Lista_1 0
          • =movelast Lista_1 0
          • =moveelem Lista_1 -1 0
          • =moveelem Lista_1 1 0
          • =getelem Lista_1 &quot;ø&quot;
          • =deleteelem Lista_1 false
          • == Insert an element into empty list
          • =insertafter Lista_1 &quot;abcdefg&quot;
          • =getnumelem Lista_1 1
          • =moveelem Lista_1 -1 0
          • =moveelem Lista_1 1 0
          • =getelem Lista_1 &quot;abcdefg&quot;
    O último parâmetro indica o número de elementos caminhados &quot; ø &quot; simboliza o string inexistente
  • 19. Critérios de valoração
    • Podem-se definir mais padrões de valoração
      • crie e mantenha um “ manual de testes ” com os padrões de valoração
      • registre nele os problemas encontrados com alguma freqüência e como se deve realizar os testes para identificar a ocorrência desses problemas
    • Este critério – valoração – é um exemplo de critério baseado em lista de controle
      • à medida que se vai identificando mais condições potenciais causadoras de problemas, acrescenta-se ao “manual de teste” uma descrição de como realizar os correspondentes testes
      • se determinada condição se mostra inútil, ou sua solução inadequada, pode-se removê-la da lista
  • 20. Teste de unidade
    • Objetivos
      • verificar se cada função ou método realiza o que se espera
        • em condições de uso normais
        • em condições de uso anormais
          • exceções
          • violações das assertivas (contratos)
      • verificar se as classes (módulos) estão completas e corretas
      • verificar se a documentação técnica é coerente com o que se encontra implementado
      • verificar a coerência das interfaces com o que está implementado
      • permitir o reteste completo realizado com freqüência
  • 21. Teste de unidade
    • De maneira geral, conhecida a interface da unidade a testar, cria-se um módulo de controle de teste que permite exercitar detalhadamente a unidade a testar
  • 22. Teste de unidade : exemplo de arcabouço de apoio ao teste
  • 23. Critérios de teste estrutural
    • Critérios
      • todas instruções todos nós [Delamaro et al, 2007]
      • todas arestas todas decisões
      • todas condições
      • todos caminhos
      • fluxo de dados
  • 24. Grafo da estrutura do código
    • Processo genérico para gerar massas de teste:
      • criar o grafo da estrutura do código a testar
        • pode envolver chamadas a funções ou métodos
      • com base no grafo e no critério de cobertura escolhidos gerar os casos de teste
      • qual a diferença com relação afluxogramas?
    • Convenções utilizadas
    Início de função ou método, chamada de função ou método Seqüência de um ou mais comandos Término de função, return , throw
  • 25. Grafo da estrutura do código: exemplo
    • 01 STR_CString ::
    • 02 STR_CString( long idStringParm )
    • 03 {
    • 04 #ifdef _DEBUG
    • 05 EXC_ASSERT( idStringParm < 0 ) ;
    • 06 #endif
    • 07 unsigned long idStr = ( idStringParm & STR_ID ) ;
    • 08 if ( ( idStringParm & STR_MEM ) == STR_MEM )
    • 09 {
    • 10 BuildStr( idStr ) ;
    • 11 } else
    • 12 {
    • 13 BuildStr( STR_MsgNotImplemented & STR_ID ) ;
    • 14 } // if
    • 15 } // End of function: STR !Construct a
    • string given an idString
    01 08 10 13 14 15 21 21
  • 26. Grafo da estrutura do código: exemplo
    • 21 void STR_CString ::
    • 22 BuildStr( unsigned long idStr )
    • 23 {
    • 24 char * pStr = GetStringAddress( idStr ) ;
    • 25 if ( pStr != NULL )
    • 26 {
    • 27 BuildString( vtStrMem[ i ].tamStr , pStr ) ;
    • 28 return ;
    • 29 } // if
    • 30 char Msg[ TAL_dimBuffer ] ;
    • 31 pStr = GetStringAddress( STR_ErrorUndefinedId ) ;
    • 32 if ( pStr != NULL )
    • 33 {
    • 34 sprintf( Msg , pStr , idStr ) ;
    • 35 } else {
    • 36 sprintf( Msg , ILLEGAL_STR_TABLE , idStr ) ;
    • 37 } /* if */
    • 38 BuildString( strlen( Msg ) , Msg ) ;
    • 39 } // End of function: STR $Build string for
    • a given Id
    21 71 25 27 30 51 71 32 34 36 38 51 39
  • 27. Grafo da estrutura do código: exemplo
    • 51 void STR_CString ::
    • 52 BuildString( const int LengthParm ,
    • 53 const char * const pStringParm )
    • 54 {
    • 55 delete pCharString ;
    • 56 Length = LengthParm ;
    • 57 pCharString = new char[ Length + 1 ] ;
    • 58 if ( Length > 0 )
    • 59 {
    • 60 if ( pStringParm != NULL )
    • 61 {
    • 62 memcpy( pCharString , pStringParm ,
    • Length ) ;
    • 63 } else
    • 64 {
    • 65 memset( pCharString , STR_NULLChar ,
    • Length ) ;
    • 66 } /* if */
    • 67 } /* if */
    • 68 pCharString[ Length ] = 0 ;
    • 69 } // End of function: STR $Build a string of
    • a given size
    51 58 60 62 65 66 67 69
  • 28. Grafo da estrutura do código: exemplo
    • 71 char * STR_CString ::
    • 72 GetStringAddress( long idString )
    • 73 {
    • 74 unsigned long idStr = ( idString & STR_ID ) ;
    • 75 for( int i = 0 ; i < NUM_STR_MEM ; i ++ )
    • 76 {
    • 77 if ( vtStrMem[ i ].idStr == idStr )
    • 78 {
    • 79 char * pStr = vtpStrTxt[
    • vtStrMem[ i ].inxStrTxt ] ;
    • 80 pStr += vtStrMem[ i ].inxStrTxtOrg ;
    • 81 return pStr ;
    • 82 } // if
    • 83 } // for
    • 84 return NULL ;
    • 85 } // End function: STR &Get pointer to memory
    • resident string table
    71 75 77 83 79 84 85
  • 29. Arrasto
    • Como testar repetições?
    • O custo do teste cresce com o número de iterações
      • portanto o número de iterações a testar deverá ser
        • pequeno de modo a minimizar o custo
        • mas suficientemente grande para que o teste seja uma boa aproximação de um teste confiável
    • Recordação: um teste é confiável caso ele detecte todos os defeitos porventura existentes no código
  • 30. Arrasto
    • Arrasto
      • é o maior dos menores números de iterações necessárias para que todas as variáveis ou estados inicializados antes e modificados durante a repetição passem a depender exclusivamente de valores computados em iterações anteriores de uma mesma instância de execução dessa repetição
    • Exemplos:
        • A[0] = 0 ; A[1] = 0 ; A[2] = 0 ; A[3] = 0 ;
        • memset( A , 0 , sizeof( A )) ;
        • pElem = ProcurarSimbolo( pTabela , pSimbolo ) ;
      • todos têm Arrasto == 0
    • Arrasto : força de resistência ao avanço de um objeto em um fluido, resultante da ação do meio
  • 31. Arrasto: exemplos
    • for ( i = 0 ; i < 10 ; i++ ) ...
    • for ( pElem = pOrg ; pElem != NULL ; pElem = pElem->pProx ) ...
    • fgets, fputs, fread, fwrite
    • tpEstado Corrente ;
    • Corrente = DefinirPrimeiro ( ValorProcurado ) ;
    • while ( ! Terminou ( Corrente ))
    • {
    • if ( Comparar ( ObterValor ( Corrente ), ValorProcurado )
    • == EH_IGUAL )
    • { return Corrente ;
    • } /* if */
    • Corrente = DefinirProximo ( Corrente , ValorProcurado ) ;
    • } /* while */
    • return ESTADO_NIL ;
    • Todos têm Arrasto == 1
  • 32. Arrasto
    • O arrasto é o número mínimo de iterações a realizar para que todos os valores que possam ser modificados durante a repetição tenham sido de fato modificados
      • corresponde ao número mínimo de iterações para atingir o estado “genérico”
    • Os casos de teste a para as repetições são:
      • caso 0 iteração (caso especial)
      • caso 1 iteração (base da indução)
      • caso n >= arrasto + 1 iterações ( simula o passo de indução)
      • devem sempre ser considerados os casos de término:
        • break ou return no corpo da iteração
        • atingiu a condição de término
  • 33. Critério de cobertura de instruções
    • Cobertura de instruções ( todos os nós )
      • Cada instrução é executada pelo menos uma vez no conjunto de todos os casos de teste
      • dado o grafo
        • cada caso percorre pelo menos um vértice (nó) ainda não percorrido
        • até que todos os vértices tenham sido percorridos
    • Escolher
      • x e y : x && y => true
      • x e z : x || z => true
      • e após a execução de P2 uma ou mais vezes: x || y => false
  • 34. Critério de cobertura de instruções: exemplo
    • 71 char * STR_CString ::
    • 72 GetStringAddress( long idString )
    • 73 {
    • 74 unsigned long idStr = ( idString & STR_ID ) ;
    • 75 for( int i = 0 ; i < NUM_STR_MEM ; i ++ )
    • 76 {
    • 77 if ( vtStrMem[ i ].idStr == idStr )
    • 78 {
    • 79 char * pStr = vtpStrTxt[
    • vtStrMem[ i ].inxStrTxt ] ;
    • 80 pStr += vtStrMem[ i ].inxStrTxtOrg ;
    • 81 return pStr ;
    • 82 } // if
    • 83 } // for
    • 84 return NULL ;
    • 85 } // End function: STR &Get pointer to memory
    • resident string table
    71 75 77 83 79 84 85 Dois caminhos asseguram a cobertura 71 75 77 83 84 85 71 75 77 79 85
  • 35. Critério de cobertura de arestas
    • Cobertura de arestas
      • Cada aresta é percorrida pelo menos uma vez no conjunto de todos os casos de teste
      • rotulam-se as arestas e criam-se os casos de teste
        • cada caso percorre pelo menos uma aresta ainda não percorrida
        • até que todas as arestas tenham sido percorridas
      • executar repetições para:
        • n = 0 iterações
        • n = 1 iteração
        • n >= 2 iterações
    • Escolher
      • x e y : x && y => false
      • x e y : x && y => true
      • x e z : x || z => false antes de executar P2 pela primeira vez (0 ciclos)
      • x e z : x || z => true , e false imediatamente após a primeira execução de P2 (1 ciclo)
      • x e z : x || z => true , e false após n > 1 execuções de P2 (n ciclos)
  • 36. Critério de cobertura de arestas: exemplo
    • 71 char * STR_CString ::
    • 72 GetStringAddress( long idString )
    • 73 {
    • 74 unsigned long idStr = ( idString & STR_ID ) ;
    • 75 for( int i = 0 ; i < NUM_STR_MEM ; i ++ )
    • 76 {
    • 77 if ( vtStrMem[ i ].idStr == idStr )
    • 78 {
    • 79 char * pStr = vtpStrTxt[
    • vtStrMem[ i ].inxStrTxt ] ;
    • 80 pStr += vtStrMem[ i ].inxStrTxtOrg ;
    • 81 return pStr ;
    • 82 } // if
    • 83 } // for
    • 84 return NULL ;
    • 85 } // End function: STR &Get pointer to memory
    • resident string table
    71 75 77 83 79 84 85 0 ciclos: 71 75 84 85 71 75 77 79 85 1 ciclo 71 75 77 83 75 84 85 71 75 77 83 75 77 79 85 2 ciclos 71 75 77 83 75 77 83 75 84 85 71 75 77 83 75 77 83 75 77 79 85
  • 37. Critério de cobertura de condições
    • Cobertura de arestas mais:
      • cada expressão é testada de tantas maneiras quantas forem os elementos das tabelas de verdade
    • x T T F F
    • y T F T F
    • x && y T F F F
    • x T T F F
    • z T F T F
    • x || z T T T F
  • 38. Teste de funções encapsuladas
    • Funções encapsuladas ( static no módulo, private , protected ) não são acessíveis a partir da interface
    • Como testá-las?
      • A: criar um módulo para teste em que não são encapsuladas. Inconvenientes:
        • dificulta retestar – teste de regressão – módulos já aprovados
        • a mudança de teste para produção pode introduzir defeitos
      • B: considerar as funções encapsuladas como extensões de uma ou mais das funções externadas. Inconvenientes:
        • as massas de teste podem tornar-se muito extensas devido à explosão combinatória (discutido mais adiante)
        • nem todas as condições são passíveis de teste
      • C: criar funções de instrumentação disponíveis quando o módulo é compilado para fins de teste. Inconveniente:
        • ex. uma espécie de “getter” para funções
        • a variedade de formas de compilação pode introduzir defeitos
  • 39. Teste de funções encapsuladas: exemplo
    • 01 STR_CString ::
    • 02 STR_CString( long idStringParm )
    • 03 {
    • 04 #ifdef _DEBUG
    • 05 EXC_ASSERT( idStringParm < 0 ) ;
    • 06 #endif
    • 07 unsigned long idStr = ( idStringParm & STR_ID ) ;
    • 08 if ( ( idStringParm & STR_MEM ) == STR_MEM )
    • 09 {
    • 10 BuildStr( idStr ) ;
    • 11 } else
    • 12 {
    • 13 BuildStr( STR_MsgNotImplemented & STR_ID ) ;
    • 14 } // if
    • 15 } // End of function: STR !Construct a
    • string given an idString
    01 08 10 13 14 15 21 21 21 - Considerar idStringParm que (i) existem , (ii) não existem e (iii) a falta do string default para emitir a mensagem de não existência. Ver função BuildStr( long ) a seguir 51 - Considerar string de tamanho igual a 0, ver BuildString( int , char * ) a seguir 71 - Considerar repetições de procura 0, 1 e n iterações, ver GetStringAddress( long ) a seguir
  • 40. Teste de funções encapsuladas: exemplo
    • 21 void STR_CString ::
    • 22 BuildStr( unsigned long idStr )
    • 23 {
    • 24 char * pStr = GetStringAddress( idStr ) ;
    • 25 if ( pStr != NULL )
    • 26 {
    • 27 BuildString( vtStrMem[ i ].tamStr , pStr ) ;
    • 28 return ;
    • 29 } // if
    • 30 char Msg[ TAL_dimBuffer ] ;
    • 31 pStr = GetStringAddress( STR_ErrorUndefinedId ) ;
    • 32 if ( pStr != NULL )
    • 33 {
    • 34 sprintf( Msg , pStr , idStr ) ;
    • 35 } else {
    • 36 sprintf( Msg , ILLEGAL_STR_TABLE , idStr ) ;
    • 37 } /* if */
    • 38 BuildString( strlen( Msg ) , Msg ) ;
    • 39 } // End of function: STR $Build string for
    • a given Id
    21 71 25 27 30 51 71 32 34 36 38 51 39
  • 41. Teste de funções encapsuladas: exemplo
    • 51 void STR_CString ::
    • 52 BuildString( const int LengthParm ,
    • 53 const char * const pStringParm )
    • 54 {
    • 55 delete pCharString ;
    • 56 Length = LengthParm ;
    • 57 pCharString = new char[ Length + 1 ] ;
    • 58 if ( Length > 0 )
    • 59 {
    • 60 if ( pStringParm != NULL )
    • 61 {
    • 62 memcpy( pCharString , pStringParm ,
    • Length ) ;
    • 63 } else
    • 64 {
    • 65 memset( pCharString , STR_NULLChar ,
    • Length ) ;
    • 66 } /* if */
    • 67 } /* if */
    • 68 pCharString[ Length ] = 0 ;
    • 69 } // End of function: STR $Build a string of
    • a given size
    51 58 60 62 65 66 67 69 Como testar pStringParm == NULL sem adulterar os módulos cliente?
  • 42. Teste de funções encapsuladas: exemplo
    • 71 char * STR_CString ::
    • 72 GetStringAddress( long idString )
    • 73 {
    • 74 unsigned long idStr = ( idString & STR_ID ) ;
    • 75 for( int i = 0 ; i < NUM_STR_MEM ; i ++ )
    • 76 {
    • 77 if ( vtStrMem[ i ].idStr == idStr )
    • 78 {
    • 79 char * pStr = vtpStrTxt[
    • vtStrMem[ i ].inxStrTxt ] ;
    • 80 pStr += vtStrMem[ i ].inxStrTxtOrg ;
    • 81 return pStr ;
    • 82 } // if
    • 83 } // for
    • 84 return NULL ;
    • 85 } // End function: STR &Get pointer to memory
    • resident string table
    71 75 77 83 79 84 85
  • 43. Critério cobertura de caminhos
    • Um caminho (ou arco de execução) corresponde a uma seqüência de execução das instruções dentro de um conjunto de grafos da estrutura de código
      • em geral considera-se os caminhos que vão do início ao término da execução de uma função
        • chamadas de função encapsuladas podem ser tratadas
          • ou como pseudo-instruções
          • ou como referências a outro grafo a ser percorrido
        • chamadas a funções externadas podem ser tratadas como pseudo-instruções uma vez que podem ser testadas detalhadamente através da interface
      • em alguns casos pode ser interessante considerar somente um fragmento de um algoritmo complexo
  • 44. Cobertura de caminhos
    • A cobertura de caminhos tende a levar a uma explosão combinatória
      • o número de caminhos é proporcional ao produtório das alternativas aninhadas
    • Uma solução é transformar fragmentos do código em funções
      • dilema: como testar funções encapsuladas?
    O da ordem de
  • 45. Cobertura de caminhos
    • O critério cobertura de caminhos seleciona um conjunto de caminhos
      • cada caminho é um caso de teste abstrato
      • a valoração dos dados deve assegurar que se execute exatamente o caminho escolhido
      • o conjunto de caminhos selecionados forma a massa de testes
    • Para manter pequeno o custo do teste deseja-se
      • um conjunto pequeno de caminhos curtos
      • o conjunto de caminhos deve
        • ser completo  exercitar todo o código
        • simular a argumentação da corretude
          • auxiliar a argumentação da corretude
        • utilizar a estrutura do código
  • 46. Cobertura de caminhos: exemplo de seleção
    • 71 char * STR_CString ::
    • 72 GetStringAddress( long idString )
    • 73 {
    • 74 unsigned long idStr = ( idString & STR_ID ) ;
    • 75 for( int i = 0 ; i < NUM_STR_MEM ; i ++ )
    • 76 {
    • 77 if ( vtStrMem[ i ].idStr == idStr )
    • 78 {
    • 79 char * pStr = vtpStrTxt[
    • vtStrMem[ i ].inxStrTxt ] ;
    • 80 pStr += vtStrMem[ i ].inxStrTxtOrg ;
    • 81 return pStr ;
    • 82 } // if
    • 83 } // for
    • 84 return NULL ;
    • 85 } // End function: STR &Get pointer to memory
    • resident string table
    71 75 77 83 79 84 85 Caminhos 0 vezes: <71, 75 , 84, 85>; <71, 75 , 77 , 79, 85>; 1 vez: <71, 75 , 77, 83, 75 , 84, 85>; <71, 75 , 77, 83, 75 , 77, 79, 85>; 2 vezes: <71, 75 , 77, 83, 75 , 77, 83, 75 , 84, 85>; <71, 75 , 77, 83, 75 , 77, 83, 75 , 77, 79, 85>;
  • 47. Cobertura de caminhos
    • Processo de geração da lista de caminhos a testar
      • a partir de um diagrama da estrutura do código ou do grafo da estrutura do código
        • cria-se uma expressão algébrica que descreve o conjunto de todos os possíveis caminhos
          • em um programa estruturado a expressão será sempre uma expressão regular
          • Exemplo – cada elemento A, B, C é uma expressão regular
            • conjunto: A , B , C ; seqüência A B C ; seleção: ( A | B | C ) ; repetição: n 1 – n 2 [ A ]
            • não vale recursão que aninhe ex. a := ( b a c | b c )
        • com base na expressão algébrica e no critério de valoração geram-se os caminhos a serem percorridos
  • 48. Cobertura de caminhos
    • Cálculo da expressão algébrica dos caminhos
      • rotulam-se os blocos e instruções
      • percorre-se o código
        • externa-se o rótulo da instrução ou do bloco visitado
        • se o bloco for início de controle de repetição externa-se ‘ [ ’
          • calcula-se o arrasto e externa-se o valor arrasto + 1
          • ao terminar o controle de repetição externa-se ‘ ] ’
        • se for início de controle de seleção externa-se ‘ ( ’
          • ao atingir um else ou else if externa-se ‘ | ’
          • ao terminar o controle de repetição externa-se ‘ ) ’
          • caso o else final seja vazio, i.e. não existe, externa-se ‘ | ) ’
        • se for uma chamada de função encapsulada e
          • se o modo de cobertura de chamada de funções é percorrimento das funções encapsuladas , passa-se a percorrer a função servidora chamada, ao retornar retoma-se o percorrimento da função cliente
          • se o modo de cobertura de chamadas de funções é pseudo-instrução , externa-se nada
  • 49. Cobertura de caminhos
    • // (A) Intercalar arquivos
    • // (B) Abrir arquivos
    • // (E) Inicializar
    • // Ler primeiro registro de arquivo A
    • // Ler primeiro registro de arquivo B
    • // (C 2) Intercalar pares de registros
    • while ( tem registro a processar )
    • // (G) Transferir registro de A para S
    • if ( chave buffer A < chave buffer B )
    • transferir de buffer A para S
    • // (H) Transferir registro de A e B para D
    • else if ( chave buffer A ==
    • chave buffer B )
    • transferir registro de A para D
    • transferir registro de B para D
    • // (I) Transferir registro de B para S
    • else
    • transferir de buffer B para S
    • // (D) Fechar arquivos
    • Expressão de caminhos
    • A
    • ABE
    • ABEC[3
    • ABEC[3(G
    • ABEC[3(G|H|I
    • ABEC[3(G|H|I)]D
  • 50. Cobertura de caminhos
    • Com a expressão A B C E [ 3 F ( G | H | I ) ] D c ria-se a lista dos caminhos a testar , usando a expressão como gerador  casos de teste abstratos
      • 0 ciclos (caminhos dos casos especiais)
        • ABCED
      • 1 ciclo (caminhos da base da indução)
        • ABCEFGD
        • ABCEFHD
        • ABCEFID
      • 3 (== arrasto + 1) ciclos (caminhos do passo de indução)
        • ABCEFGFGFGD
        • ABCEFGFGFHD
        • ABCEFGFGFID
        • ABCEFGFHFGD
        • ABCEFGFHFHD
        • ABCEFGFHFID
        • . . .
  • 51. Transformação em caso de teste úteis Os casos gerados foram casos de teste abstratos
  • 52. Transformação em caso de teste úteis
    • Casos de teste valorados determinam os valores e coman-dos a serem utilizados como dados dos casos de teste
      • Crie os arquivos A0 = {}, B0 = {}, A1 = { c1 }, B11 = { c1 } , A3 = { c1 , c2 , c3 } , B12 = { c3 } , . . .
      • Arq A vazio, Arq B vazio  A0 , B0
      • Arq A com 1, Arq B vazio  A1 , B0
      • Arq A com 1, Arq B com 1 e chaves de ambos iguais  A1 , B11
      • Arq A vazio, Arq B com 1  A0 , B11
      • Arq A com 3, Arq B vazio  A3 , B0
      • Arq A com 3, Arq B com 1, chave em B igual à chave do 3º. de A  A3 , B12
      • . . .
  • 53. Transformação em caso de teste úteis
    • Casos de teste úteis estabelecem os resultados esperados em função dos dados
      • Criar arquivos S0 = {} , E0 = {} , S1 = { c1 } , E11 = { c1 , c1 } , S2 = { c1 , c2 } , S3 = { c1 , c2 , c3 } , E12 = { c3 , c3 } , . . .
      • A0 , B0  S0 , E0
      • A1 , B0  S1 , E0
      • A1 , B11  S0 , E11
      • A0 , B11  S1 , E0
      • A3 , B0  S3 , E0
      • A3 , B12  S2 , E12
      • . . .
  • 54. Transformação em caso de teste úteis
    • Dica para automação
      • criar todos os arquivos requeridos
      • criar um programa de teste específico que
        • para cada caso de teste recebe linhas com os nomes dos 4 arquivos
        • executa a intercalação com os dois primeiros arquivos
        • compara os arquivos resultantes com os dois últimos
      • o módulo de intercalação pode ser implementado contendo uma função que recebe quatro parâmetros
        • neste caso pode-se utilizar o arcabouço de apoio ao teste
      • o programa de intercalação pode ser implementado como um programa principal recebendo 4 parâmetros da linha de comando
        • neste caso pode-se implementar um batch ( .bat ) ou um programa LUA que controla a execução
  • 55. Exemplo de roteiro de teste
    • Um roteiro de teste estabelece um cenário de teste e fornece uma série de instruções a serem utilizadas durante os testes manuais ou automatizados:
    • == Intercalar A e B vazios
    • =intercalar A0 B0 S0 E0
    • == Intercalar A contendo 1 registro com B vazio
    • =intercalar A1 B0 S1 E0
    • == Intercalar A e B contendo 1 registro, chaves iguais
    • =intercalar A1 B11 S0 E11
    • == Intercalar A vazio com B contendo 1 registro
    • =intercalar B0 A1 S1 E0
    • . . .
  • 56. Problema do teste caixa aberta
    • O grande problema do teste caixa aberta é a explosão de casos de teste
      • quanto mais controles aninhados em uma função exponencialmente maior é o número de casos de teste
    • Outro problema é o fato de falhas poderem depender do caminho usado até a chamada de uma função
      • este é um problema de integração
    • Uma proposta é utilizar instrumentação (contadores de passagem) para verificar a parcela de cobertura alcançada
      • inserir um contador de passagem
        • em cada início de arco de fluxo de controle
        • antes de cada comando de retorno ( return , throw )
  • 57. Fluxo de dados
    • Método de teste fluxo de dados tende a ser uma forma de inspecionar caminhos a fim de identificar caminhos potencialmente defeituosos
    • Dado um caminho, examinam-se as operações de criação, uso, atribuição, e destruição que são realizadas sobre cada um dos dados
      • CRUD – Create, Retrieve, Update, Destroy
    • Considerando o código de funções (métodos)
      • muitos compiladores modernos geram advertências para caminhos potencialmente incorretos
        • limitações óbvias: o problema é não computável no caso geral
        • quando receberem uma advertência, corrijam o código
          • usualmente é erro mesmo
        • nem todas as advertências são geradas 
  • 58. Fluxo de dados
    • Dados são sujeitos às seguintes operações:
      • D - definição: declaração, construção, inicialização, atribuição, parâmetro recebido, parâmetro retornado, ...
        • Dc declaração ou construção com valores neutros, ou sem valor
      • L - destruição: destruição, indefinição, liberação, tornar desnecessário, …
      • U - uso:
        • Uc - computação: acesso, elemento de fórmula, argumento passando valor, …
        • Up - controle: uso em um predicado, variável de controle, …
      • * estado irrelevante - não definido, não existe, …
        • antes de declarar
        • após return ou throw
        • após destruição
        • quando não for mais necessário dispor do elemento ou da instância
  • 59. Fluxo de dados
      • a = expressão
        • todas as variáveis da expressão são do gênero uc
        • a variável a é do gênero D
      • read( a, b, c, …)
        • todas as variáveis são do gênero D
      • write( a, b, c, …)
        • todas as variáveis são do gênero Uc
      • free( pX ) ou delete obj
        • o espaço apontado por pX , ou o objeto obj são do gênero L
      • f( int * parm ) - declaração
        • o ponteiro parm e o respectivo espaço são do gênero D
      • *parm
        • o ponteiro parm é do gênero Uc e o respectivo espaço é D
      • f( parg ) - chamada passando referência
        • o ponteiro parg é Uc o espaço depende do contrato: * , D ou Uc
  • 60. Fluxo de dados
      • while ( exp )
        • todas as variáveis em exp são do gênero Up
      • for ( a = b ; a < l ; a++ )
        • a é do gênero D (a = b, a ++) e Uc (a < l )
        • b é do gênero Uc
      • if ( exp)
        • todas as variáveis em exp são do gênero Up
      • switch ( exp)
        • todas as variáveis em exp são do gênero Up
      • OBS: exp não deve conter efeitos colaterais!!!
        • proibido: while ( --i ) ou while ( scanf( ... ) != 0 ) ...
  • 61. Fluxo de dados: conversão para caminhos
    • Todas as definições
      • exercitar cada uma das definições existentes pelo menos uma vez
    • Todos usos
      • exercitar pelo menos uma vez cada um dos usos Uc e Up pelo menos uma vez
    • Todos DU caminhos
      • sempre relativos a um atributo (variável) específico
      • exercitar pelo menos uma vez cada um dos caminhos que iniciam em uma definição até a próxima definição ou liberação da variável de referência
  • 62. Fluxo de dados: inspeção
    • Seqüências envolvendo pares:
      • DU - vale
      • UU - vale
      • LD - vale
      • UpD - vale
      • UcD - provavelmente vale
      • DcD - vale
      • DD - advertência definição múltipla
      • DcL – advertência se não tiver caminho alternativo: para que definir e destruir sem utilizar?
      • DL - possivelmente vale
      • LU - erro: destrói depois usa
      • LL - erro: destrói duas vezes
  • 63. Fluxo de dados: inspeção
    • Seqüências envolvendo estado indefinido:
      • *L - erro, não definida e destruída
      • *D - vale, primeira definição no caminho
      • *U - erro, usado antes de definir
      • L* - vale, última coisa feita é destruição
      • D* - advertência, definido e nunca utilizado
      • U* - provavelmente é erro se a variável for um objeto ou recurso não ancorado
        • objetos e recursos não ancorados precisam ser liberados sempre que se tornem irrelevantes
      • * - provavelmente erro, variável declarada mas não definida (inicializada)
  • 64. Fluxo de dados: exemplo grafo de código
  • 65. Fluxo de dados: inspeção envolvendo x *DcDU* *DcU*
  • 66. Fluxo de dados: inspeção envolvendo z *LU UD * *LU D * *LL DUUD * *LL DUD *
  • 67. Fluxo de dados: inspeção
    • 21 void STR_CString ::
    • 22 BuildStr( unsigned long idStr )
    • 23 {
    • 24 char * pStr = GetStringAddress( idStr ) ;
    • 25 if ( pStr != NULL )
    • 26 {
    • 27 BuildString( vtStrMem[ i ].tamStr , pStr ) ;
    • 28 return ;
    • 29 } // if
    • 30 char Msg[ TAL_dimBuffer ] ;
    • 31 pStr = GetStringAddress( STR_ErrorUndefinedId ) ;
    • 32 if ( pStr != NULL )
    • 33 {
    • 34 sprintf( Msg , pStr , idStr ) ;
    • 35 } else {
    • 36 sprintf( Msg , ILLEGAL_STR_TABLE , idStr ) ;
    • 37 } /* if */
    • 38 BuildString( strlen( Msg ) , Msg ) ;
    • 39 } // End of function: STR $Build string for
    • a given Id
    21 71 25 27 30 51 71 32 34 36 38 51 39 idStr  22 D 27 Uc L ; 22 D 34 Uc L ; 22 D 36 Uc L pStr  24 D 25 Up 27 Uc L ; 24 D 25 Up 31 D 32 Up 34 Uc L ; 24 D 25 Up 31 D 32 Up L Msg  30 D 34 D 38 Uc L ; 30 D 36 D 38 Uc L
  • 68. Teste de exceções
    • Quando usar exceções?
      • abordagem ortodoxa : somente quando ocorre uma situação anômala  erro, exemplos
        • assertiva não vale
        • dispositivo não existe, mas deveria existir
        • faltou memória
        • anomalia na seqüência de execução
        • componente interno, ex. base de dados, recebeu dados não válidos
      • abordagem não ortodoxa : um instrumento de controle da execução
        • retorno de uma função que fica “longe” de quem trataria a condição de retorno
        • argumento: condições de retorno são chatas e acabam sendo ignoradas
          • mas try catch finally em tudo quanto é lugar não é igualmente chato?
  • 69.
    • Projetar para testabilidade
      • estabeleça um padrão de implementação para exceções
        • idealmente deveria ser válido para todos os projetos da organização
      • simplifique a captura ( catch )
        • evitar uma lista longa de catch es
      • detalhe a causa para gerar a exceção
        • expressão ou condição que provocou o throw
      • determine onde foi e por que foi sinalizada a exceção
        • módulo, linha de código onde se encontra o throw
      • forneça informação de contexto do ponto da sinalização
        • ex. pilha de execução, se der
    Teste de exceções
  • 70. Teste de exceções
  • 71. Teste de exceções
    • Como testar exceções?
  • 72. Teste de exceções: instrumentação Forçar ocorrência de erro
  • 73. Teste de exceções: arcabouço teste C++
    • == Add numbers of different size, should generate loss of data
    • =ConvertIntToBCD 0 4 -3785328
    • =ConvertIntToBCD 1 5 108303031
    • =Add 0 1
    • =ExceptionProgram 0 lossOfData 'c'
    • == Convert 10 siz 1 to BCD, should generate overflow exception
    • =ConvertIntToBCD 0 1 10
    • =ExceptionProgram 0 overflow 'c'
    • -----------------------
    • 46 == Add numbers of different size, should generate loss of data
    • >>> 1 Line 49 Tester caught a program exception >>
    • ERROR: Loss of data while assigning a BCD number .
    • Exception thrown in Line: 536 File: ..sourcescdarit.cpp
    • <<< 0 Line 50 Expected exception has been ignored.
    • 106 == Convert 10 siz 1 to BCD, should generate overflow
    • >>> 1 Line 107 Tester caught a program exception >>
    • ERROR: Overflow in BCD conversion
    • Exception thrown in Line: 161 File: ..sourcescdarit.cpp
    • <<< 0 Line 108 Expected exception has been ignored.
  • 74. Teste de exceções
    • Assegurar que
      • cada throw foi executado pelo menos uma vez no conjunto de todos os casos de teste
      • cada catch foi executado uma vez no conjunto de todos os casos de teste
    • Problema
      • provocar throws pode ser “fácil” ao testar módulos
      • mas testar o par throw => catch pode ser bastante difícil
      • o ponto em que se encontra o throw pode distar muito (caminho longo de chamadas) do ponto em que se encontra o correspondente catch
        • envolve muitas classes ou módulos
        • torna-se difícil forçar a ocorrência da causa
        • é difícil também forçar causas que são detectadas pelo interpretador (Java, C#) ou pelo run-time (C++)
  • 75. Teste de exceções: análise estática
    • Cria-se o grafo de estrutura do código completo:
      • procure envolver todos os módulos
        • se der: todas as bibliotecas
        • se existe byte code (Java, .Net) pode-se criá-lo a partir do byte code
        • como tratar redefinições de funções (herança)?
          • conservador: todas as possibilidades de herdar
      • para cada throw percorrer o grafo em ordem inversa da ativação até atingir o correspondente catch
        • se não encontrar  defeito grave
        • se encontrar: examinar se o tratador está em conformidade com o throw
          • catch all nem sempre é uma boa solução
          • pode existir um catch inserido incorretamente (aspectos)
          • pode existir um throw inserido incorretamente => não obedece ao padrão
  • 76. Recursos locais e exceções
    • Recursos locais e exceções
      • ao terminar um método através de uma exceção os recursos ancorados localmente não são liberados
      • recursos alocados localmente são uma potencial fonte de vazamento de recursos
  • 77. Recursos locais e exceções
    • Solução Java:
    • use a construção try{ ... } finally{ ... }
      • as referências para recursos são declaradas null
      • os recursos locais são alocados
      • o bloco try contém o código que potencialmente pode gerar exceções
        • se um recurso é transferido para uma estrutura com âncora externa ao método, a referência deve passar a ser null
      • os recursos locais são desalocados pelo bloco finally
  • 78. Recursos locais e exceções
    • Solução C++:
      • use objetos locais ao invés de referências para objetos
        • CAlgo AlgumObjeto ;
      • se necessário crie um struct encapsulado que contenha as referências e o respectivo destrutor e aloque uma instância (objeto) local deste struct . Esboço:
        • struct SAncora {
        • CRecurso * pRecurso ;
        • SAncora( ){ pRecurso = NULL ; }
        • ~SAncora( ){ delete pRecurso ; }
        • } ; // struct
        • SAncora Ancora ;
        • Ancora.pRecurso = new CRecurso( ) ;
    • Bjarne Stroustrup's C++ Style and Technique FAQ http://www.research.att.com/~bs/bs_faq2.html
  • 79. Recursos locais e exceções
    • #include <stdio.h>
    • class CRecurso {
    • public: int X ;
    • public: CRecurso( ) { X = 10 ; }
    • public: ~CRecurso( ) { printf( &quot; Destruiu CRecurso&quot; ) ; }
    • public: void Mata( ) { throw &quot;abcd&quot; ; }
    • } ;
    • int UmaFunc( ) {
    • struct SAncora {
    • CRecurso * pRecurso ;
    • SAncora( ){ pRecurso = NULL ; printf( &quot; Construiu ancora&quot; ) ; }
    • ~SAncora( ){ delete pRecurso ; printf( &quot; Destruiu ancora&quot; ) ; }
    • } Ancora ; // struct
    • Ancora.pRecurso = new CRecurso( ) ;
    • Ancora.pRecurso->Mata( ) ;
    • return Ancora.pRecurso->X ;
    • } // UmaFunc
    void main( ) { try { printf( &quot; Recurso: %d&quot;, UmaFunc( )) ; } catch ( ... ) { printf( &quot; Cancelou com throw&quot; ) ; } }
  • 80. Módulos dublê
    • Módulo dublê ( test double , analogia: stunt double ) é um módulo que toma o lugar de outro durante os testes
      • visa auxiliar o teste automatizado
    • Tipos de módulos dublê
      • controle ( driver ) – controla a realização do teste
        • não é bem um dublê...
        • módulo de teste específico, arcabouço de apoio ao teste
      • fictício ( dummy ) – são dados e objetos passados mas nunca usados, ex. enchimento de lista de parâmetros
      • simulado ( fake ) – implementam alguma funcionalidade mas de forma simplificada, ex. base de dados residente em memória
      • enchimento ( stub ) – geram respostas, em geral fixas
      • imitação ( mock object ) – implementam uma simulação da especificação
  • 81. Módulos dublê: exemplo de enchimento
    • int F( int ParametroX ) { return 10 ; }
    • int G( int ParametroX ) { return ParametroX / 2 ; }
    • int H( int ParametroX )
    • {
    • tpElem * pElem = ProcurarTabela( ParametroX ) ;
    • if (pElem == NULL ) throw new CException( MsgErroParametro ) ;
    • return pElem->valRetorno
    • }
    • int L( int ParametroX )
    • {
    • int numLidos = RDR_ReadLine( &quot; ii &quot; , &Controle , &Valor ) ;
    • if ( ( Controle != ParametroX ) || ( numLidos != 2 ))
    • throw new CException( MsgErroSincronismo) ;
    • return Valor ;
    • }
    a ser tratada pelo arcabouço de teste
  • 82. Módulos dublê: módulos de imitação
    • Quando utilizar módulos (objetos) de imitação?
      • o objeto real possui comportamento não determinístico
        • permite seqüenciar os eventos
      • o objeto real é trabalhoso para ser construído
      • o objeto real possui comportamento difícil de provocar
        • exemplo: erros de comunicação
      • o objeto real é lento
      • o objeto real é ou contém interface com o usuário
      • o teste precisa controlar a forma com que usa o objeto
        • protocolo de interação
        • uso de uma função de call back
      • o objeto real ainda não existe
        • desenvolvimento de software embarcado
        • desenvolvimento com várias equipes
  • 83. Módulos dublê: módulos de imitação
    • Exemplo
    • public void testProcurarPedido( )
    • {
    • Database db = new MockDatabase( ) ;
    • db.expectQuery( &quot; select idPedido from Pedidos where
    • idCliente is 123 &quot; ) ;
    • db.returnResult( &quot; Pedido 2 &quot; , &quot; Pedido 3 &quot; ) ;
    • ...
    • }
  • 84. Módulos dublê: módulos de imitação void * CED_Malloc( size_t Tamanho , int Linha , char * NomeArquivo ) { tpElemListaEspacos * pEspaco ; if ( LimiteMemoria > 0 ) { if ( LimiteMemoria < EspacoTotalAlocado + ( long ) Tamanho ) { return NULL ; ou throw exceção de falta de memória } /* if */ } /* if */ if ( LimiteNumEspacos > 0 ) { if ( numEspacosAlocados >= LimiteNumEspacos ) { return NULL ; } /* if */ } /* if */ pEspaco = ( tpElemListaEspacos * ) malloc( sizeof( tpElemListaEspacos ) + Tamanho ) ; if ( pEspaco == NULL ) { return NULL ; } /* if */ #define malloc CED_Malloc( Tam , __LINE__ , __FILE__ )
  • 85. Módulos dublê: módulos de imitação
    • public interface Ambiente {
    • public long getTime( ) ;
    • ...
    • }
    • --- Implementação de produção
    • public class Contexto implements Ambiente {
    • public long getTime( ) {
    • return System.currentTimeMillis( ) ;
    • }
    • ...
    • }
    • --- Implementação de imitação
    • public class MockContexto implements Ambiente {
    • private long currentTime ;
    • public long getTime( ) { return currentTime ; }
    • public void setTime( long aTime ) { currentTime = aTime ; }
    • ...
    • }
  • 86. Módulos dublê: módulos de imitação
    • public class OrderEasyTester extends TestCase {
    • private static String TALISKER = &quot;Talisker&quot;;
    • private MockControl warehouseControl;
    • private Warehouse warehouseMock;
    • public void setUp() {
    • warehouseControl = MockControl.createControl(Warehouse.class);
    • warehouseMock = (Warehouse) warehouseControl.getMock();
    • }
    • public void testFillingRemovesInventoryIfInStock() {
    • //setup - data
    • Order order = new Order(TALISKER, 50);
    • //setup - expectations
    • warehouseMock.hasInventory(TALISKER, 50);
    • warehouseControl.setReturnValue(true);
    • warehouseMock.remove(TALISKER, 50);
    • warehouseControl.replay();
    • //exercise
    • order.fill(warehouseMock);
    • //verify
    • warehouseControl.verify();
    • assertTrue(order.isFilled()); }
    record / replay metaphor extraído de Fowler, M.; Mocks Aren’t Stubs
  • 87. Módulos dublê: módulos de imitação
    • Existem diversas bibliotecas MockObject disponíveis
      • http://www.easymock.org
      • http://www.jMock.org
      • http://www.nMock.org
      • .NET EasyMock http://sourceforge.net/projects/easymocknet/
      • ... ?
  • 88. Referências bibliográficas
    • Beck, K.; Test-Driven Development by Example ; Reading, Massachusetts: Addison-Wesley; 2003
    • Delamaro, M.E.; Maldonado, J.C.; Jino, M.; Introdução ao Teste de Software ; Rio de Janeiro, RJ: Elsevier / Campus; 2007
    • Fowler, M.; Mocks Aren’t Stubs ; Buscado em: 23/09/2008; URL: martinfowler.com/articles/mocksArentStubs.html
    • Hunt, A.; Thomas, D.; Pragmatic Unit Test: in Java with JUnit ; Raleigh, North Carolina: The Pragmatic Bookshelf; 2004
    • Mackinnon, T.; Freeman, S.; Craig, P.; “ Endo-Testing: Unit Testing with Mock Objects ”; in: Succi, G.; Marchesi, M.; eds.; Extreme Programming Examined ; Reading, Massachusetts: Addison-Wesley; 2001; pags 287-302; Buscado em: 25/10/2005; URL: http://www.connextra.com/aboutUs/mockobjects.pdf
    • Myers, G.J.; The Art of Software Testing , 2nd edition; New York: John Wiley & Sons; 2004
    • Staa, A.v.; Programação Modular ; Rio de Janeiro, RJ: Elsevier / Campus; 2000
  • 89.
    • FIM