• Nenhum resultado encontrado

Uma Abordagem Leve para Testar o Comportamento Excepcional

N/A
N/A
Protected

Academic year: 2021

Share "Uma Abordagem Leve para Testar o Comportamento Excepcional"

Copied!
185
0
0

Texto

(1)“Uma Abordagem Leve para Testar o Comportamento Excepcional” Por. Rafael Brito Di Bernardo Dissertação de Mestrado. Universidade Federal de Pernambuco [email protected] www.cin.ufpe.br/~posgraduacao. RECIFE, Novembro/2011.

(2) Universidade Federal de Pernambuco Centro de Informática Pós-graduação em Ciência da Computação. Rafael Brito Di Bernardo. “Uma Abordagem Leve para Testar o Comportamento Excepcional”. Trabalho apresentado ao Programa de Pós-graduação em Ciência da Computação do Centro de Informática da Universidade Federal de Pernambuco como requisito parcial para obtenção do grau de Mestre em Ciência da Computação.. Orientador: Fernando Castor Co-Orientador: Sérgio Soares. RECIFE, Novembro/2011.

(3) Catalogação na fonte Bibliotecária Jane Souto Maior, CRB4-571. Di Bernardo, Rafael Brito. Uma abordagem leve para testar o comportamento excepcional / Rafael Brito Di Bernardo - Recife: O Autor, 2011. xiii, 166 p: il., fig., tab. Orientador: Fernando José Castor de Lima Filho. Dissertação (mestrado) - Universidade Federal de Pernambuco. CIn, Ciência da Computação, 2011. Inclui bibliografia e apêndice. 1. Engenharia de software. 2. Teste de software. I. Lima Filho, Fernando José Castor de (orientador). II. Título. 005.1. CDD (23. ed.). MEI2012 – 019.

(4)

(5) Dedico esta dissertação a minha esposa Paula, minha filha Sarah, aos meus Pais e familiares que me deram todo o apoio necessário. Agradeço a Deus por me permitir alcançar mais esta conquista na minha vida..

(6) Agradecimentos Gostaria de agradecer em primeiro lugar a Deus por me possibilitar esta experiência, me ajudar a caminhar nesta etapa da minha vida e me fortalecer em todos os momentos. Sem Ele nada disso teria acontecido. Agradeço a minha esposa Paula e minha filha Sarah por me apoiarem nesta jornada incentivando sempre o meu crescimento. Agradeço também por compreenderem os momentos que não pude estar mais presente devido à dedicação a este trabalho. Agradeço aos meus pais, Pascoal e Loide, e toda a minha família por sempre incentivarem o meu crescimento acadêmico, profissional e pessoal. Sou agradecido por mais uma vez ter a oportunidade de ser orientando do professor Fernando Castor sempre disponível, atencioso e cuidadoso para que o trabalho fosse conduzido da melhor maneira possível. Agradeço ao meu co-orientador Sérgio Soares pelo suporte necessário inclusive por ter me recebido no programa de mestrado antes mesmo do professor Fernando assumir nesta instituição de ensino. Também sou agradecido aos Professores Nélio Cacho, Roberta Coelho, Fernando Castor, Sérgio Soares e ao Ricardo Sales por terem contribuído para as publicações relacionadas a este trabalho.. iv.

(7) Resumo. Muitos dos problemas encontrados no uso do mecanismo de tratamento de exceções são causados pela falta de projeto e teste do comportamento excepcional de um sistema em fases iniciais do desenvolvimento de software. Como consequência, exceções são propagadas de forma inesperada durante causando impacto negativo na confiabilidade de um software. Neste trabalho apresentamos uma abordagem que possibilita projetar testes desde as atividades iniciais do desenvolvimento e verificar, em tempo de execução, como as exceções trafegam ao longo de um sistema. Através da especificação do fluxo excepcional esperado é possível determinar se uma exceção foi propagada corretamente. Um segundo uso desta abordagem destina-se ao auxilio das atividades de manutenção de um sistema. Para isto, uma versão inicial existente é especificada e os testes são executados nas novas versões ao longo da evolução do sistema. Com isso é possível verificar a consistência do comportamento excepcional a cada nova versão. Um benefício da abordagem proposta deve-se ao fato de que os testes escritos servem como a própria documentação viva do sistema mantendo-a sempre atualizada. Para a avaliação desta abordagem foram selecionados três sistemas: aTunes, jEdit e Health Watcher. Através do seu uso foram descobertos dezesseis bugs. Deste total doze foram erros inéditos não reportados na base de bugs destes projetos. Não somente bugs foram descobertos com a utilização desta abordagem. Do ponto de vista de testes automatizados, como artefatos de documentação, foram apontadas diversas diferenças entre as versões dos sistemas com relação aos fluxos excepcionais testados. Para auxiliar a automação dos testes, a abordagem foi implementada como uma extensão do framework JUnit. Os testes especificados nesta extensão contém informações complementares sobre o fluxo excepcional esperado. Palavras-chave: Tratamento de exceções, teste, comportamento excepcional, especificação do comportamento excepcional.. v.

(8) Abstract. Many of the problems found in the use of exception handling are caused by the lack of testing and a priori design of the exceptional behavior. As a consequence, exceptions flow in unforeseen ways during the execution of a software system, having a negative impact on reliability. This work presents an approach that allows testing activities from the initial development and check, at runtime, the exceptions travels over a system. By specifying the expected path is possible to determine if an exceptional flow occurred as expected. A second use of this approach is intended to aid the maintenance activities of a system. For this, an initial version of system is specified and the tests are performed in all new versions during the system evolution. With this approach it is possible to check the consistency of the exceptional behaviour with each new version. One benefit of the proposed approach due to the fact that the written tests serves as proper documentation keeping it always updated. To evaluate this approach we selected three systems: aTunes, jEdit and Health Watcher. Through its use sixteen bugs were discovered. Twelve errors were not reported in bugs database of evaluated projects. Not only bugs were discovered using this approach. From the viewpoint of automated testing as documentation, several differences were noted between the version of system streams related to the exceptional tested. To assist the testing automation, the approach was implemented as an extension of the JUnit framework. The tests specified in this extension contains additional information about the expected exceptional flow. Keywords: Exception handling, testing, exceptional behaviour, specification of exceptional behaviour.. vi.

(9) Sumário. Lista de Figuras. xv. Lista de Tabelas. xvi. Lista de acrônimos. xvii. 1 Introdução. 1. 2 Fundamentos 2.1 Tolerância a falhas . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 5 5. 2.1.1 2.1.2 2.1.3. Falha, erro e defeito . . . . . . . . . . . . . . . . . . . . . . . Classificação de falhas . . . . . . . . . . . . . . . . . . . . . . Tolerância a falhas . . . . . . . . . . . . . . . . . . . . . . . .. 6 6 6. Detecção de erros . . . . . . . . . . . . . . . . . . . . . . . . . Confinamento de erros . . . . . . . . . . . . . . . . . . . . . .. 7 7. 2.2. Recuperação de erros . . . . . . . . . . . . . . . . . . . . . . . 2.1.4 Tratamento de falhas . . . . . . . . . . . . . . . . . . . . . . . Tratamento de Exceções . . . . . . . . . . . . . . . . . . . . . . . . .. 7 8 8. 2.3 2.4. Tratamento de Exceções em Java . . . . . . . . . . . . . . . . . . . . . Teste de Software . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 10 12. 2.4.1. Estratégia de teste . . . . . . . . . . . . . . . . . . . . . . . . Teste de Unidade . . . . . . . . . . . . . . . . . . . . . . . . . Teste de Componente . . . . . . . . . . . . . . . . . . . . . . .. 13 13 13. Teste de integração . . . . . . . . . . . . . . . . . . . . . . . . Teste de Sistemas . . . . . . . . . . . . . . . . . . . . . . . . .. 13 14. Teste estrutural . . . . . . . . . . . . . . . . . . . . . . . . . . Teste Funcional . . . . . . . . . . . . . . . . . . . . . . . . . . Particionamemnto de equivalência . . . . . . . . . . . . . . . .. 14 15 15. Análise do Valor Limite . . . . . . . . . . . . . . . . . . . . . Grafo Causa-Efeito . . . . . . . . . . . . . . . . . . . . . . . .. 15 16. Error-Guessing . . . . . . . . . . . . . . . . . . . . . . . . . . JUnit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Test-Driven Development . . . . . . . . . . . . . . . . . . . . . . . . .. 16 16 19. 2.6.1. 19. 2.4.2 2.4.3. 2.5 2.6. Etapas do TDD . . . . . . . . . . . . . . . . . . . . . . . . . .. vii.

(10) Passo 1: Pensar . . . . . . . . . . . . . . . . . . . . . . . . . .. 19. Passo 2: Barra vermelha . . . . . . . . . . . . . . . . . . . . . Passo 3: Barra verde . . . . . . . . . . . . . . . . . . . . . . . Passo 4: Refatoração . . . . . . . . . . . . . . . . . . . . . . .. 19 20 21. Passo 5: Repetir . . . . . . . . . . . . . . . . . . . . . . . . . Programação Orientada a Aspectos . . . . . . . . . . . . . . . . . . . .. 21 21. 2.7.1 2.7.2. Pontos de Junção . . . . . . . . . . . . . . . . . . . . . . . . . Aspectj . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Sintaxe básica do Aspectj . . . . . . . . . . . . . . . . . . . .. 22 23 23. Advice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 24. 3 Abordagem Proposta 3.1 Motivação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 27 27. 3.1.1 Priorizando os fluxos excepcionais . . . . . . . . . . . . . . . . Tipos de fluxos excepcionais . . . . . . . . . . . . . . . . . . . . . . . Teste do comportamento Excepcional . . . . . . . . . . . . . . . . . .. 30 32 34. 3.3.1. Utilizando a abordagem em aplicações existentes . . . . . . . . Selecionando os fluxos excepcionais mais importantes . . . . .. 34 35. Criação dos casos de testes . . . . . . . . . . . . . . . . . . . . Execução dos testes . . . . . . . . . . . . . . . . . . . . . . . . Verificação dos resultados . . . . . . . . . . . . . . . . . . . .. 35 36 36. Verificação de inconsistência e correção dos erros . . . . . . . . Reaplicação dos testes . . . . . . . . . . . . . . . . . . . . . .. 36 36. Utilizando a abordagem em novos sistemas . . . . . . . . . . . Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . Monitorando exceções . . . . . . . . . . . . . . . . . . . . . .. 36 41 46. 3.3.5 Forçando exceções . . . . . . . . . . . . . . . . . . . . . . . . Como montar o ambiente de testes . . . . . . . . . . . . . . . . . . . .. 48 48. 2.7. 3.2 3.3. 3.3.2 3.3.3 3.3.4 3.4. 4 Avaliação. 51. 4.1 4.2 4.3. Avaliação do sistema aTunes . . . . . . . . . . . . . . . . . . . . . . . Avaliação do sistema jEdit . . . . . . . . . . . . . . . . . . . . . . . . Health Watcher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 53 55 59. 4.4. Conclusão . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 63. viii.

(11) 5 Trabalhos Relacionados 5.1 5.2 5.3. Verificação Estática . . . . . . . . . . . . . . . . . . . . . . . . . . . . Abordagens baseadas no teste do comportamento excepcional . . . . . Abordagem baseada no processo de desenvolvimento . . . . . . . . . .. 6 Considerações Finais. 65 65 66 67 69. 6.1 6.2. Conclusão . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Publicações relacionadas . . . . . . . . . . . . . . . . . . . . . . . . .. 69 70. 6.3. Trabalhos futuros . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 70. Appendices. 79. A Casos de teste A.1 Atunes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A.1.1 Atunes 1.5 TC01 . . . . . . . . . . . . . . . . . . . . . . . . .. 80 80 80. A.1.2 Atunes 1.5 TC02 . . . . . . . . . . . . . . . . . . . . . . . . . A.1.3 Atunes 1.5 TC03 . . . . . . . . . . . . . . . . . . . . . . . . .. 81 81. A.1.4 Atunes 1.5 TC04 . . . . . . . . . . . . . . . . . . . . . . . . . A.1.5 Atunes 1.5 TC05 . . . . . . . . . . . . . . . . . . . . . . . . . A.1.6 Atunes 1.5 TC06 . . . . . . . . . . . . . . . . . . . . . . . . .. 82 82 83. A.1.7 Atunes 1.5 TC07 . . . . . . . . . . . . . . . . . . . . . . . . . A.1.8 Atunes 1.5 TC08 . . . . . . . . . . . . . . . . . . . . . . . . .. 83 84. A.1.9 Atunes 1.5 TC09 . . . . . . . . . . . . . . . . . . . . . . . . . A.1.10 Atunes 1.5 TC10 . . . . . . . . . . . . . . . . . . . . . . . . . A.1.11 Atunes 1.5 TC11 . . . . . . . . . . . . . . . . . . . . . . . . .. 84 85 85. A.1.12 Atunes 1.5 TC12 . . . . . . . . . . . . . . . . . . . . . . . . . A.1.13 Atunes 1.5 TC14 . . . . . . . . . . . . . . . . . . . . . . . . .. 85 86. A.1.14 Atunes 1.6 TC01 . . . . . . . . . . . . . . . . . . . . . . . . . A.1.15 Atunes 1.6 TC02 . . . . . . . . . . . . . . . . . . . . . . . . . A.1.16 Atunes 1.6 TC03 . . . . . . . . . . . . . . . . . . . . . . . . .. 87 87 88. A.1.17 Atunes 1.6 TC04 . . . . . . . . . . . . . . . . . . . . . . . . . A.1.18 Atunes 1.6 TC05 . . . . . . . . . . . . . . . . . . . . . . . . .. 88 89. A.1.19 Atunes 1.6 TC06 . . . . . . . . . . . . . . . . . . . . . . . . . A.1.20 Atunes 1.6 TC07 . . . . . . . . . . . . . . . . . . . . . . . . . A.1.21 Atunes 1.6 TC08 . . . . . . . . . . . . . . . . . . . . . . . . .. 89 90 90. A.1.22 Atunes 1.6 TC09 . . . . . . . . . . . . . . . . . . . . . . . . .. 91. ix.

(12) A.1.23 Atunes 1.6 TC10 . . . . . . . . . . . . . . . . . . . . . . . . .. 91. A.1.24 Atunes 1.6 TC11 . . . . . . . . . . . . . . . . . . . . . . . . . A.1.25 Atunes 1.6 TC12 . . . . . . . . . . . . . . . . . . . . . . . . . A.1.26 Atunes 1.6 TC14 . . . . . . . . . . . . . . . . . . . . . . . . .. 92 92 93. A.1.27 Atunes 1.9 TC01 . . . . . . . . . . . . . . . . . . . . . . . . . A.1.28 Atunes 1.09 TC02 . . . . . . . . . . . . . . . . . . . . . . . .. 93 94. A.1.29 Atunes 1.09 TC03 . . . . . . . . . . . . . . . . . . . . . . . . A.1.30 Atunes 1.09 TC04 . . . . . . . . . . . . . . . . . . . . . . . . A.1.31 Atunes 1.09 TC07 . . . . . . . . . . . . . . . . . . . . . . . .. 94 94 95. A.1.32 Atunes 1.09 TC10 . . . . . . . . . . . . . . . . . . . . . . . . A.1.33 Atunes 1.09 TC11 . . . . . . . . . . . . . . . . . . . . . . . .. 95 96. A.1.34 Atunes 1.09 TC12 . . . . . . . . . . . . . . . . . . . . . . . . A.1.35 Atunes 1.09 TC13 . . . . . . . . . . . . . . . . . . . . . . . . A.1.36 Atunes 1.09 TC14 . . . . . . . . . . . . . . . . . . . . . . . .. 96 97 98. A.1.37 Atunes 1.09 TC15 . . . . . . . . . . . . . . . . . . . . . . . . A.1.38 Atunes 1.09 TC16 . . . . . . . . . . . . . . . . . . . . . . . .. 98 98. A.1.39 Atunes 1.09 TC17 . . . . . . . . . . . . . . . . . . . . . . . . 99 A.1.40 Atunes 1.10 TC11 . . . . . . . . . . . . . . . . . . . . . . . . 99 A.1.41 Atunes 1.10 TC02 . . . . . . . . . . . . . . . . . . . . . . . . 100 A.1.42 Atunes 1.10 TC03 . . . . . . . . . . . . . . . . . . . . . . . . 100 A.1.43 Atunes 1.10 TC04 . . . . . . . . . . . . . . . . . . . . . . . . 101 A.1.44 Atunes 1.10 TC07 . . . . . . . . . . . . . . . . . . . . . . . . 101 A.1.45 Atunes 1.10 TC10 . . . . . . . . . . . . . . . . . . . . . . . . 102 A.1.46 Atunes 1.1 TC11 . . . . . . . . . . . . . . . . . . . . . . . . . 102 A.1.47 Atunes 1.10 TC12 . . . . . . . . . . . . . . . . . . . . . . . . 103 A.1.48 Atunes 1.10 TC13 . . . . . . . . . . . . . . . . . . . . . . . . 104 A.1.49 Atunes 1.10 TC14 . . . . . . . . . . . . . . . . . . . . . . . . 104 A.1.50 Atunes 1.10 TC15 . . . . . . . . . . . . . . . . . . . . . . . . 104 A.1.51 Atunes 1.10 TC16 . . . . . . . . . . . . . . . . . . . . . . . . 105 A.1.52 Atunes 1.10 TC17 . . . . . . . . . . . . . . . . . . . . . . . . 105 A.1.53 Atunes 1.12 TC01 . . . . . . . . . . . . . . . . . . . . . . . . 106 A.1.54 Atunes 1.12 TC02 . . . . . . . . . . . . . . . . . . . . . . . . 106 A.1.55 Atunes 1.12 TC03 . . . . . . . . . . . . . . . . . . . . . . . . 107 A.1.56 Atunes 1.12 TC04 . . . . . . . . . . . . . . . . . . . . . . . . 108 A.1.57 Atunes 1.12 TC07 . . . . . . . . . . . . . . . . . . . . . . . . 108. x.

(13) A.1.58 Atunes 1.12 TC10 . . . . . . . . . . . . . . . . . . . . . . . . 109 A.1.59 Atunes 1.12 TC12 . . . . . . . . . . . . . . . . . . . . . . . . 109 A.1.60 Atunes 1.12 TC12 . . . . . . . . . . . . . . . . . . . . . . . . 110 A.1.61 Atunes 1.12 TC16 . . . . . . . . . . . . . . . . . . . . . . . . 110 A.1.62 Atunes 1.12 TC17 . . . . . . . . . . . . . . . . . . . . . . . . 111 A.1.63 Atunes 1.13 TC01 . . . . . . . . . . . . . . . . . . . . . . . . 111 A.1.64 Atunes 1.13 TC02 . . . . . . . . . . . . . . . . . . . . . . . . 112 A.1.65 Atunes 1.13 TC03 . . . . . . . . . . . . . . . . . . . . . . . . 112 A.1.66 Atunes 1.13 TC04 . . . . . . . . . . . . . . . . . . . . . . . . 113 A.1.67 Atunes 1.13 TC07 . . . . . . . . . . . . . . . . . . . . . . . . 113 A.1.68 Atunes 1.13 TC10 . . . . . . . . . . . . . . . . . . . . . . . . 114 A.1.69 Atunes 1.13 TC11 . . . . . . . . . . . . . . . . . . . . . . . . 114 A.1.70 Atunes 1.13 TC12 . . . . . . . . . . . . . . . . . . . . . . . . 115 A.1.71 Atunes 1.13 TC14 . . . . . . . . . . . . . . . . . . . . . . . . 115 A.1.72 Atunes 1.13 TC16 . . . . . . . . . . . . . . . . . . . . . . . . 116 A.1.73 Atunes 1.13 TC17 . . . . . . . . . . . . . . . . . . . . . . . . 116 A.2 jEdit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 A.2.1 jEdit 4.0 TC01 . . . . . . . . . . . . . . . . . . . . . . . . . . 117 A.2.2 jEdit 4.0 TC02 . . . . . . . . . . . . . . . . . . . . . . . . . . 117 A.2.3 jEdit 4.0 TC03 . . . . . . . . . . . . . . . . . . . . . . . . . . 118 A.2.4 jEdit 4.0 TC04 . . . . . . . . . . . . . . . . . . . . . . . . . . 118 A.2.5 jEdit 4.0 TC05 . . . . . . . . . . . . . . . . . . . . . . . . . . 119 A.2.6 jEdit 4.0 TC01 . . . . . . . . . . . . . . . . . . . . . . . . . . 119 A.2.7 jEdit 4.0 TC07 . . . . . . . . . . . . . . . . . . . . . . . . . . 120 A.2.8 jEdit 4.0 TC08 . . . . . . . . . . . . . . . . . . . . . . . . . . 120 A.2.9 jEdit 4.0 TC09 . . . . . . . . . . . . . . . . . . . . . . . . . . 121 A.2.10 jEdit 4.0 TC10 . . . . . . . . . . . . . . . . . . . . . . . . . . 121 A.2.11 jEdit 4.0 TC01 . . . . . . . . . . . . . . . . . . . . . . . . . . 121 A.2.12 jEdit 4.0 TC12 . . . . . . . . . . . . . . . . . . . . . . . . . . 122 A.2.13 jEdit 4.0 TC13 . . . . . . . . . . . . . . . . . . . . . . . . . . 122 A.2.14 jEdit 4.0 TC14 . . . . . . . . . . . . . . . . . . . . . . . . . . 123 A.2.15 jEdit 4.0 TC15 . . . . . . . . . . . . . . . . . . . . . . . . . . 123 A.2.16 jEdit 4.1 TC01 . . . . . . . . . . . . . . . . . . . . . . . . . . 123 A.2.17 jEdit 4.1 TC02 . . . . . . . . . . . . . . . . . . . . . . . . . . 124 A.2.18 jEdit 4.1 TC01 . . . . . . . . . . . . . . . . . . . . . . . . . . 124. xi.

(14) A.2.19 jEdit 4.1 TC03 . . . . . . . . . . . . . . . . . . . . . . . . . . 125 A.2.20 jEdit 4.1 TC04 . . . . . . . . . . . . . . . . . . . . . . . . . . 125 A.2.21 jEdit 4.1 TC05 . . . . . . . . . . . . . . . . . . . . . . . . . . 126 A.2.22 jEdit 4.1 TC06 . . . . . . . . . . . . . . . . . . . . . . . . . . 126 A.2.23 jEdit 4.1 TC07 . . . . . . . . . . . . . . . . . . . . . . . . . . 127 A.2.24 jEdit 4.1 TC08 . . . . . . . . . . . . . . . . . . . . . . . . . . 128 A.2.25 jEdit 4.1 TC09 . . . . . . . . . . . . . . . . . . . . . . . . . . 128 A.2.26 jEdit 4.1 TC10 . . . . . . . . . . . . . . . . . . . . . . . . . . 128 A.2.27 jEdit 4.1 TC11 . . . . . . . . . . . . . . . . . . . . . . . . . . 129 A.2.28 jEdit 4.1 TC12 . . . . . . . . . . . . . . . . . . . . . . . . . . 129 A.2.29 jEdit 4.1 TC13 . . . . . . . . . . . . . . . . . . . . . . . . . . 130 A.2.30 jEdit 4.1 TC14 . . . . . . . . . . . . . . . . . . . . . . . . . . 130 A.2.31 jEdit 4.1 TC15 . . . . . . . . . . . . . . . . . . . . . . . . . . 130 A.2.32 jEdit 4.2 TC01 . . . . . . . . . . . . . . . . . . . . . . . . . . 131 A.2.33 jEdit 4.2 TC02 . . . . . . . . . . . . . . . . . . . . . . . . . . 131 A.2.34 jEdit 4.2 TC03 . . . . . . . . . . . . . . . . . . . . . . . . . . 132 A.2.35 jEdit 4.2 TC05 . . . . . . . . . . . . . . . . . . . . . . . . . . 132 A.2.36 jEdit 4.2 TC06 . . . . . . . . . . . . . . . . . . . . . . . . . . 133 A.2.37 jEdit 4.2 TC09 . . . . . . . . . . . . . . . . . . . . . . . . . . 133 A.2.38 jEdit 4.2 TC10 . . . . . . . . . . . . . . . . . . . . . . . . . . 133 A.2.39 jEdit 4.2 TC11 . . . . . . . . . . . . . . . . . . . . . . . . . . 134 A.2.40 jEdit 4.2 TC12 . . . . . . . . . . . . . . . . . . . . . . . . . . 134 A.2.41 jEdit 4.2 TC13 . . . . . . . . . . . . . . . . . . . . . . . . . . 135 A.2.42 jEdit 4.2 TC14 . . . . . . . . . . . . . . . . . . . . . . . . . . 135 A.2.43 jEdit 4.2 TC15 . . . . . . . . . . . . . . . . . . . . . . . . . . 135 A.2.44 jEdit 4.3 TC01 . . . . . . . . . . . . . . . . . . . . . . . . . . 136 A.2.45 jEdit 4.3 TC02 . . . . . . . . . . . . . . . . . . . . . . . . . . 136 A.2.46 jEdit 4.3 TC05 . . . . . . . . . . . . . . . . . . . . . . . . . . 137 A.2.47 jEdit 4.3 TC06 . . . . . . . . . . . . . . . . . . . . . . . . . . 137 A.2.48 jEdit 4.3 TC10 . . . . . . . . . . . . . . . . . . . . . . . . . . 137 A.2.49 jEdit 4.3 TC11 . . . . . . . . . . . . . . . . . . . . . . . . . . 138 A.2.50 jEdit 4.3 TC12 . . . . . . . . . . . . . . . . . . . . . . . . . . 138 A.2.51 jEdit 4.3 TC13 . . . . . . . . . . . . . . . . . . . . . . . . . . 139 A.2.52 jEdit 4.3 TC14 . . . . . . . . . . . . . . . . . . . . . . . . . . 139 A.2.53 jEdit 4.3 TC15 . . . . . . . . . . . . . . . . . . . . . . . . . . 139. xii.

(15) A.2.54 jEdit 4.3.2 TC01 . . . . . . . . . . . . . . . . . . . . . . . . . 140 A.2.55 jEdit 4.3.2 TC01 . . . . . . . . . . . . . . . . . . . . . . . . . 140 A.2.56 jEdit 4.3.2 TC05 . . . . . . . . . . . . . . . . . . . . . . . . . 141 A.2.57 jEdit 4.3.2 TC06 . . . . . . . . . . . . . . . . . . . . . . . . . 141 A.2.58 jEdit 4.3.2 TC08 . . . . . . . . . . . . . . . . . . . . . . . . . 142 A.2.59 jEdit 4.3.2 TC10 . . . . . . . . . . . . . . . . . . . . . . . . . 142 A.2.60 jEdit 4.3.2 TC11 . . . . . . . . . . . . . . . . . . . . . . . . . 142 A.2.61 jEdit 4.3.2 TC12 . . . . . . . . . . . . . . . . . . . . . . . . . 143 A.2.62 jEdit 4.3.2 TC13 . . . . . . . . . . . . . . . . . . . . . . . . . 143 A.2.63 jEdit 4.3.2 TC14 . . . . . . . . . . . . . . . . . . . . . . . . . 144 A.2.64 jEdit 4.3.2 TC15 . . . . . . . . . . . . . . . . . . . . . . . . . 144 A.3 Health Watcher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 A.3.1 Health Watcher 1-2 OO TC01 . . . . . . . . . . . . . . . . . . 144 A.3.2 Health Watcher 1-2 OO TC02 . . . . . . . . . . . . . . . . . . 145 A.3.3 Health Watcher 1-2 OO TC03 . . . . . . . . . . . . . . . . . . 145 A.3.4 Health Watcher 1-2 OO TC04 . . . . . . . . . . . . . . . . . . 146 A.3.5 Health Watcher 1-2 OO TC05 . . . . . . . . . . . . . . . . . . 146 A.3.6 Health Watcher 1-2 OO TC06 . . . . . . . . . . . . . . . . . . 147 A.3.7 Health Watcher 1-2 OO TC07 . . . . . . . . . . . . . . . . . . 147 A.3.8 Health Watcher 1-2 OO TC08 . . . . . . . . . . . . . . . . . . 148 A.3.9 Health Watcher 1-2 OO TC09 . . . . . . . . . . . . . . . . . . 148 A.3.10 Health Watcher 1-2 OO TC10 . . . . . . . . . . . . . . . . . . 149 A.3.11 Health Watcher 1-2 OO TC11 . . . . . . . . . . . . . . . . . . 149 A.3.12 Health Watcher 1-2 OO TC12 . . . . . . . . . . . . . . . . . . 150 A.3.13 Health Watcher 1-2 OO TC13 . . . . . . . . . . . . . . . . . . 151 A.3.14 Health Watcher 1-2 OO TC14 . . . . . . . . . . . . . . . . . . 151 A.3.15 Health Watcher 1-2 OO TC15 . . . . . . . . . . . . . . . . . . 152 A.3.16 Health Watcher 1-2 OO TC16 . . . . . . . . . . . . . . . . . . 152 A.3.17 Health Watcher 1-10 AO TC01 . . . . . . . . . . . . . . . . . . 155 A.3.18 Health Watcher 1-10 AO TC02 . . . . . . . . . . . . . . . . . . 155 A.3.19 Health Watcher 1-10 AO TC03 . . . . . . . . . . . . . . . . . . 156 A.3.20 Health Watcher 1-10 AO TC04 . . . . . . . . . . . . . . . . . . 156 A.3.21 Health Watcher 1-10 AO TC05 . . . . . . . . . . . . . . . . . . 157 A.3.22 Health Watcher 1-10 AO TC06 . . . . . . . . . . . . . . . . . . 157 A.3.23 Health Watcher 1-10 AO TC07 . . . . . . . . . . . . . . . . . . 158. xiii.

(16) A.3.24 Health Watcher 1-10 AO TC08 . . . . . . . . . . . . . . . . . . 159 A.3.25 Health Watcher 1-10 AO TC09 . . . . . . . . . . . . . . . . . . 159 A.3.26 Health Watcher 1-10 AO TC10 . . . . . . . . . . . . . . . . . . 159 A.3.27 Health Watcher 1-10 AO TC11 . . . . . . . . . . . . . . . . . . 160 A.3.28 Health Watcher 1-10 AO TC12 . . . . . . . . . . . . . . . . . . 160 A.3.29 Health Watcher 1-10 AO TC13 . . . . . . . . . . . . . . . . . . 161 A.3.30 Health Watcher 1-10 AO TC14 . . . . . . . . . . . . . . . . . . 162 A.3.31 Health Watcher 1-10 AO TC15 . . . . . . . . . . . . . . . . . . 162 A.3.32 Health Watcher 1-10 AO TC16 . . . . . . . . . . . . . . . . . . 163. xiv.

(17) Lista de Figuras. 2.1. Recuperação por avanço e retrocesso [74]. . . . . . . . . . . . . . . . .. 7. 2.2 2.3 2.4. Mecanismo de Tratamento de Exceções . . . . . . . . . . . . . . . . . Hierarquia de exceções em Java . . . . . . . . . . . . . . . . . . . . . . Join points de um fluxo de execução [28] . . . . . . . . . . . . . . . . .. 10 11 23. 2.5. Exemplo de advice em AspectJ . . . . . . . . . . . . . . . . . . . . . .. 25. 3.1. Arquitetura em camadas de um sistema de informação . . . . . . . . .. 28. 3.2 3.3 3.4. Fluxos candidatos à criação de casos de teste . . . . . . . . . . . . . . Tipos de fluxos excepcionais: Completo, Mínimo[58]. . . . . . . . . . Visão da abordagem proposta para sistemas existentes[58]. . . . . . . .. 33 34 35. 3.5 3.6. Representação da propagação de exceções na arquitetura. . . . . . . . . Etapas da abordagem para novos sistemas. . . . . . . . . . . . . . . . .. 37 38. 3.7 3.8 3.9. Diagrama de componentes . . . . . . . . . . . . . . . . . . . . . . . . Diagrama de sequência . . . . . . . . . . . . . . . . . . . . . . . . . . Implementação do caso de teste . . . . . . . . . . . . . . . . . . . . .. 39 39 40. 3.10 Criação das classes básicas . . . . . . . . . . . . . . . . . . . . . . . . 3.11 Visão jUnite tool . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 41 42. 3.12 Exemplo de caso de teste . . . . . . . . . . . . . . . . . . . . . . . . . 3.13 Resultado de um caso de teste. . . . . . . . . . . . . . . . . . . . . . . 3.14 Transformação de tipo uma exceção. . . . . . . . . . . . . . . . . . . .. 44 45 46. 3.15 Criação de um projeto Aspectj. . . . . . . . . . . . . . . . . . . . . . . 3.16 Adicionando o JUnit ao projeto. . . . . . . . . . . . . . . . . . . . . .. 49 50. 3.17 Adicionando lib do JUnitE. . . . . . . . . . . . . . . . . . . . . . . . .. 50. 4.1. 56. Método savePictureToFile() . . . . . . . . . . . . . . . . . . . . . . . .. xv.

(18) Lista de Tabelas. 2.1. Desiginadores de ponto de junção [45] pg.74 . . . . . . . . . . . . . .. 24. 4.1 4.2 4.3. Métricas do sistema aTunes. . . . . . . . . . . . . . . . . . . . . . . . Resultado dos testes para as versões analisadas do aTunes. . . . . . . . Falhas encontradas no sistema aTunes . . . . . . . . . . . . . . . . . .. 53 54 54. 4.4 4.5. Métricas do jEdit. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Resultado dos testes para as versões analisadas do jEdit. . . . . . . . .. 57 57. 4.6 4.7 4.8. Falhas encontradas no sistema jEdit. . . . . . . . . . . . . . . . . . . . Métricas do Health Watcher. . . . . . . . . . . . . . . . . . . . . . . . Resultado dos testes para as versões analisadas do HW. . . . . . . . . .. 58 60 60. 4.9. Detalhamento das falhas encontradas no HW. . . . . . . . . . . . . . .. 61. xvi.

(19) Lista de acrônimos. GUI Graphical user interface TDD Test Driven Development LOC Lines of Code XP eXtreme Programming UFPE Universidade Federal de Pernambuco I/O Input and output operation AOP Aspect Oriented Programming GUI Graphics User Interface DAO Data Access Objects. xvii.

(20) 1. Introdução. Sistemas de software são geralmente compostos por um conjunto de componentes distribuídos. Estes componentes lidam com entradas de diversas fontes e executam em uma variedade extensa de ambientes que exigem alta confiabilidade. Várias técnicas podem ser utilizadas para atender essas exigências. Tratamento de exceções é uma dessas técnicas e está presente nas principais linguagens de programação [23]. Mecanismos de tratamento de exceções ajudam os desenvolvedores a construírem aplicações robustas, separando o comportamento excepcional do fluxo de controle normal [44]. Mecanismos de tratamentos de exceções oferecem abstrações para: (i) representar situações de erro dos módulos do sistema através de exceções; (ii) encapsular atividades de tratamento de exceções em tratadores de exceções; (iii) definir partes dos módulos do sistema como regiões protegidas para tratar ocorrências excepcionais; (iv) associar essas regiões protegidas aos tratadores, e (v) especificar explicitamente as interfaces excepcionais dos módulos. Se por um lado uma grande quantidade de código nos sistemas modernos é dedicada à detecção e tratamento de erros [8, 19, 24], por outro lado, lidar com as manifestações de erros / exceções em diferentes estágios de desenvolvimento ( por exemplo, elicitação de requisitos, projeto arquitetural e projeto de sistemas) tem recebido pouca atenção [26, 32]. Os desenvolvedores tendem a dar atenção ao comportamento normal da aplicação, não se concentrando na concepção das atividades excepcionais (detecção e tratamento de erros)[30] . Eles costumam lidar com a detecção e tratamento das exceções apenas nas atividades de implementação [23]. Como consequência, mecanismos de tratamento de exceções não são utilizados de maneira adequada, comprometendo a confiabilidade do sistema. O código gerado para tratar exceções geralmente é propenso a erros [3] devido à falta de atenção com relação ao comportamento excepcional ao longo das fases de desenvol-. 1.

(21) vimento de software. Este que inicialmente foi concebido para permitir a construção de um sistema mais robusto acaba por ser uma fonte de falhas [57]. Tendo em vista este problema, pesquisadores propuseram diferentes abordagens para aliviar os problemas introduzidos pelo mau uso do mecanismos de exceções. Estas abordagens são normalmente baseadas em analise estática, testes e no processo do desenvolvimento do software. Abordagens baseadas em análise estática de código foram propostas com o objetivo de revelar problemas relativos ao código de tratamento de exceções. Para dar suporte a esta abordagem, ferramentas de análise estática são utilizadas para descobrir o fluxo excepcional, do local onde a exceção é lançada ao local onde é capturada [9, 47, 55, 57]. Esta técnica, no contexto de tratamento de exceções, possibilita o entendimento de como um programa se comporta na presença de eventos excepcionais. No entanto, devido às limitações inerentes a esta abordagem, combinado com as características das linguagens modernas (como herança, polimorfismo e chamadas virtuais), tais abordagens costumam relatar muitos falsos positivos ao sinalizar problemas relacionados ao fluxo indevido de exceções[69]. Assim, a verificação manual é geralmente requerida para verificar se o fluxo excepcional detectado pode de fato ocorrer. Também não são úteis quando o sistema ainda está em desenvolvimento pois os fluxos excepcionais ainda não estão completos embora estes possam já estar especificados. Muitas abordagens de desenvolvimento propõem ajudar na diminuição deste problema [26, 32]. No entanto tais abordagem são fortemente baseadas em documentação incorporando um overhead que pode ser um impeditivo ao seu uso. Experiências [14] têm mostrado que metodologias ágeis são usadas com sucesso no desenvolvimento de aplicativos modernos. Essas metodologias são baseadas em automação de testes e pouca documentação. Também pode ser observado que os testes automatizados servem como a própria documentação com relação à especificação do sistema. No entanto, estas não levam em consideração explicitamente o teste do comportamento excepcional. Este trabalho tem por objetivo elaborar uma nova abordagem para especificação e verificação do comportamento excepcional em um sistema de software. Em particular, estamos interessados em verificar se, os fluxos de propagação das exceções, a partir dos pontos onde são lançadas até serem capturadas, estão corretos. Com o objetivo dar suporte aos testes do comportamento excepcional definidos pela abordagem proposta, foi implementada uma ferramenta como extensão do JUnit devido a este ser o framework mais utilizado para construção de testes de unidade automatizados. Em alguns cenários este framework foi utilizado [27, 56] de maneira mais ampla para dar suporte, por exem-. 2.

(22) plo, a testes de integração. Espera-se que através do uso da abordagem seja possível detectar erros relacionados ao tratamento de exceções nos sistemas avaliados permitindo a criação de sistemas mais confiáveis. Devido a restrições de recursos para a elaboração de um experimento controlado, este estudo não tem o objetivo avaliar a abordagem proposta para sistemas novos. Este apenas limita-se a avaliar a abordagem no cenário evolutivo para sistemas já existentes. Também não possui o objetivo de fornecer uma nova abordagem de priorização de seleção dos fluxos excepcionais a serem testados, apenas concentra-se em demostrar os critérios utilizados para a criação dos casos de testes para os sistemas avaliados. A perguntas que queremos responder neste trabalho é: A abordagem proposta permite a descobertas de bugs relacionados ao comportamento excepcional em um sistema de software? Para a abordagem proposta, o teste do comportamento excepcional, o qual a partir deste momento chamaremos de teste excepcional, é especificado de maneira similar ao JUnit, com pequenas adições referentes ao fluxo excepcional esperado. Um teste excepcional pode ser utilizado para especificar possíveis fluxos excepcionais e compará-los com os ocorridos em tempo de execução. Esta abordagem pode ser usada: (i) em sistemas pré-existentes nas fases posteriores ao desenvolvimento dando suporte às atividades de testes nas versões ao longo da evolução do sistema ou; (ii) antes do sistema ser implementado utilizando as premissas da metodologia TDD (Test Driven Development). Para avaliar a abordagem realizamos testes do comportamento excepcional de três sistemas. Dois deles são sistemas reais de código aberto e que possuem uma vasta base de usuários. São eles o jEdite 1 e o aTunes2 . O último sistema avaliado, Health Watcher 3 , é um sistema web implementado na linguagem Java e AspectJ. Este foi desenvolvido no meio acadêmico e é utilizados como referência por diversos estudos científicos. Através da avaliação dos três sistemas, foram descobertos dezesseis bugs, dos quais doze destes não haviam sido reportados anteriormente nos seus respectivos sistemas de gerenciamento de bugs. O resto desta dissertação está organizada da seguinte maneira. O capítulo 2 apresenta os fundamentos teóricos necessários para o entendimento do resto desta dissertação. Capítulo 3 apresenta inicialmente um exemplo motivacional explicando porque o JUnit falha na detecção de bugs causados pela propagação de exceções. Ainda neste capítulo apresentamos a abordagem proposta. No Capítulo 4 apresentamos os resultados obtidos 1 jedit.org 2. www.atunes.org. 3 http://www.comp.lancs.ac.uk/ greenwop/tao/implementation.htm. 3.

(23) através da avaliação realizada. O Capítulo 5 apresentamos os trabalhos diretamente relacionados com a abordagem proposta. Por fim, no Capítulo 6 fazemos as considerações finais deste trabalho e apresentamos, resumidamente, suas principais contribuições.. 4.

(24) 2. Fundamentos. Este capítulo tem por objetivo fornecer o embasamento teórico para o entendimento do resto desta dissertação. O primeiro ponto abordado são os conceitos sobre tolerância a falhas (Seção 2.1.3). O segundo tópico (Seção 2.3) aborda o funcionamento do mecanismo de tratamento de exceções. Devido ao uso da linguagem Java para implementar os sistemas avaliados assim como a extensão da ferramenta de testes JUnit, o terceiro tópico aborda tratamento de exceções no contexto da linguagem de programação Java. Na Seção 2.5 são abordados os fundamentos de teste de software. Devido à utilização de TDD (Test Driven Development), a Seção 2.6 aborda os fundamentos e etapas deste método. Por fim, são abordados os conceitos de programação orientada a aspectos e um pouco da linguagem AspectJ. Estes conceitos são importantes para o entendimento do módulo de monitoramento das exceções utilizado neste trabalho.. 2.1 Tolerância a falhas Tolerância a falhas é a área de pesquisa dedicada a estudar o comportamento de sistemas computacionais sujeitos à ocorrência de falhas [2]. Um sistema computacional consiste em um conjunto de componentes que interagem entre si [75] e com o ambiente do sistema. A característica dinâmica de um sistema de software é observada pela série de estados nos quais o sistema assume durante a sua execução, com a interação de seus componentes. Sob condições normais de processamento, o sistema irá avançar de um estado interno válido para o próximo por meio de uma transição válida. Em uma situação adversa, essa transição ocasionará um erro.. 5.

(25) 2.1. TOLERÂNCIA A FALHAS. 2.1.1 Falha, erro e defeito Um defeito (failure) no sistema ocorre quando o serviço prestado pelo sistema desviase de seu objetivo especificado (desvio da especificação). Um erro é a parte do estado interno do sistema que é suscetível a conduzir a um defeito subsequente, ou seja, o processamento posterior a partir deste estado pode levar a um defeito. Uma falha (fault) é a causa física ou algorítima do erro. A falha pode ocorrer dentro de um componente de hardware ou software.. 2.1.2 Classificação de falhas Podemos observar na literatura algumas classificações para falha [34, 75]. Laprie [34] as define como: • Falhas Físicas: causadas por fenômenos adversos e podem ser internas ou externas ao componente. Podemos citar como exemplo falhas geradas por componentes defeituosos, interferência eletromagnética, fadiga dos componentes físicos e variações ambientais. • Falhas humanas: são imperfeições inseridas na implementação de um sistema que podem ser de dois tipos: falhas de projeto (problemas de especificação e implementação de sistemas) ou interação (violação de procedimentos de funcionamento ou manutenção). Devido aos sistemas críticos serem construídos de modo a suportar falhas físicas, falhas humanas são consideradas o problema mais sério quando pensamos em computação crítica pois possuem um grande potencial de comprometer a confiabilidade e disponibilidade do sistema [33].. 2.1.3 Tolerância a falhas A confiabilidade é uma característica desejável para qualquer sistema de computação e requisito obrigatório para muitos deles. Embora a operação sem defeitos seja o seu objetivo, não há garantia de que sistemas de software vão estar livres de falhas e de seus efeitos ao longo do seu tempo de operação. A fim de proporcionar confiabilidade, apesar da presença de falhas, técnicas de tolerância a falhas devem ser adotadas. Quando há uma falha no sistema, a manifestação desta falha pode dar origem a erros. Estes, por consequência, podem resultar em defeitos. O objetivo da tolerância a falhas é evitar. 6.

(26) 2.1. TOLERÂNCIA A FALHAS. falhas e erros com o intuito de levar o sistema a um estado livre de erros. Vários autores apresentaram suas próprias classificações para as técnicas de tolerância a falhas. A mais comum é a classificação em quatro fases de aplicação [75]: detecção, confinamento, recuperação e tratamento. Detecção de erros O ponto inicial para todas as estratégias de tolerância a falhas é a detecção de um erro. Antes de ser detectada, uma falha se manifesta como um erro. Antes de sua manifestação como erro, a falha encontra-se em um estado de latência e assim não pode ser detectada. Enquanto uma falha não pode ser diretamente detectada, a manifestação da falha poderá gerar estados de erro em algum lugar do sistema [75]. A existência da falha pode estar presente em um sistema sem nunca se manifestar. Confinamento de erros Devido ao atraso entre a manifestação da falha e a sua detecção, informações erradas podem se espalhar no sistema. O confinamento é uma técnica que restringe limites para a propagação das informações erradas. Na elaboração de sistemas devem ser previstas restrições ao fluxo de informações para evitar fluxos acidentais e estabelecer interfaces de verificação para detecção de erros. Recuperação de erros. Figura 2.1 Recuperação por avanço e retrocesso [74].. Esta técnica é responsável por substituir um estado errôneo por um estado livre de erros com o objetivo de permitir a sua recuperação. Esta substituição pode ocorrer de. 7.

(27) 2.2. TRATAMENTO DE EXCEÇÕES. duas maneiras distintas conforme a Figura 2.1 : • Recuperação por retrocesso: consiste na passagem do estado do sistema para um estado consistente já ocorrido. • Recuperação por avanço: procura um novo estado livre de erros que permita ao sistema proceder com sua execução. Nesta maneira, somente é permitido a recuperação de erros os quais os danos podem ser antecipados.. 2.1.4 Tratamento de falhas A fase de tratamento de falhas é responsável por localizar a falha e recuperar o sistema para um estado livre de erros. Nesta fase, a falha é primeiramente isolada para depois ser reparada. O procedimento do reparo depende do tipo da falha. Falhas permanentes requerem que um componente falho seja substituído por outro componente. A localização da falha é realizada em duas etapas [74]: localização rápida, aplicada sobre um módulo ou subsistema e localização fina, mais demorada, onde o componente falho é determinado. Nas duas formas de localização são usados testes de diagnóstico (teste realizado comparando resultados gerados com os resultados previstos) e pode ser conduzido no sistema de forma manual ou automática [74]: • Diagnóstico manual: executado por um operador local ou remoto; • Diagnóstico automático: executado pelos componentes livres de falha do sistema. Após a localização da falha, o componente danificado é removido com o objetivo de reparar a falha do sistema. A restauração pode ocorre de maneira manual ou automática.. 2.2 Tratamento de Exceções Sistemas devem ser bem estruturados com o objetivo de serem tolerantes às manifestações de falhas em seus componentes. Desta forma, para lidar com esta complexidade adicional, tratamento de exceções provê um arcabouço para a estruturação de aplicações tolerantes a falhas. Esta técnica permite uma clara separação entre as atividades normais e excepcionais em um sistema de software. Um sistema de software consiste em um conjunto de componentes que interagem entre si para prover as demandas do ambiente do sistema [75]. Estes componentes recebem requisições de serviço e produzem respostas. Caso o componente responsável pela. 8.

(28) 2.2. TRATAMENTO DE EXCEÇÕES. resposta não consiga atendê-la, devolve uma exceção ao componente que requisitou. As respostas são classificadas em duas categorias: respostas normais e respostas excepcionais [25]. A atividade normal implementa os serviços normais do componente, enquanto a atividade excepcional provê mecanismos para tolerar as falhas que causam exceções. Exceções pode ser classificadas em três categorias: • Interface exception: sinalizada em resposta a uma requisição que não está em conformidade com a interface do componente requisitado. • Failure exception: sinalizada se um componente por algum motivo não pôde prover o serviço especificado. • Internal exception: são exceções lançadas pelo componente com o intuito de invocar seu próprio mecanismo de tolerância a falhas. Neste mecanismo, o tratador da exceção é responsável por trocar o fluxo de controle para o seu estado normal. Esta técnica estrutura o código de recuperação de erros de um sistema para que estes possam ser mais facilmente detectados, sinalizados e manipulados. Muitas linguagens de programação incorporam essa técnica. Elas fornecem construções para sinalizar a ocorrência de um erro e um conjunto de medidas de recuperação [6]. O mecanismo de tratamento de exceções é responsável por alterar o fluxo normal de controle em um programa para seu fluxo excepcional na ocorrência de uma exceção. No âmbito das linguagens de programação que implementam este mecanismo, exceções podem ser classificadas [10] em duas categorias: • Definida pelo usuário: as exceções são definidas e detectadas no nível da aplicação. • Predefinida: estas exceções são declaradas implicitamente e são associadas a condições detectadas em tempo de execução pela linguagem de programação. Os tratadores de exceções são inseridos em uma região particular do código normal, denominada de região protegida. Cada região protegida pode ter associado um conjunto de tratadores. Sendo assim, se uma exceção é lançada em uma região protegida, o fluxo de controle normal é desviado para o fluxo de controle excepcional. A Figura 2.2, ilustra três regiões protegidas. Cada uma destas pode ter um conjunto de tratadores associados. Caso alguma exceção ocorra em um dos blocos protegidos, o fluxo excepcional segue para o tratador compatível com a exceção sinalizada. Nesta. 9.

(29) 2.3. TRATAMENTO DE EXCEÇÕES EM JAVA. Figura 2.2 Mecanismo de Tratamento de Exceções. figura, a execução que inicia no bloco main segue seu fluxo para o método m1() que por sua vez faz chamada ao método m2(). Na execução de m2(), o mecanismo de exceção sinaliza uma exceção do tipo E1 e procura um tratador apropriado (neste caso, o tratador está associado à região protegida do método m1(). Após o tratamento no bloco catch que captura E1 no método m1(), o fluxo segue para a próxima linha logo abaixo da chamada a m1() em main().. 2.3 Tratamento de Exceções em Java Em Java, exceções são objetos de tipos herdados de uma classe especial chamada Throwable. A hierarquia de classes abaixo de java.lang.Throwable é dividida imediatamente em Error e Exception (Figura 2.3). Exceções podem ser checadas ou não checadas. Uma exceção é denominada checada quando deve ser tratada ou propagada explicitamente no programa. Já uma exceção não checada não obriga ao programador tratar ou propagar uma exceção. Esta categoria representa erros internos da linguagem Java ou erros de programação. O primeiro corresponde aos erros internos e indisponibilidade de recursos em tempo de execução apresentados pela máquina virtual Java. Esses tipos de exceções são derivados da classe Error e não devem ser lançados explicitamente pelo programador. O segundo diz respeito aos erros de programação. Exceções associadas a tais erros são instâncias de tipos derivados da exceção RuntimeException, como: • Divisão por zero (AritimeticException) • Tentativa de acessar objetos nulos (NullPointerException). 10.

(30) 2.3. TRATAMENTO DE EXCEÇÕES EM JAVA. • Passagem de argumentos inválidos (InvalidArgumentException) • Acesso a possições de arrays fora do limite (ArrayIndexOfBounds) • Conversão explícita de tipos indevida (ClassCastException). Figura 2.3 Hierarquia de exceções em Java .. Em Java, é denominado escopo protegido (ou contexto de tratamento de exceções [75]) o conjunto de instruções contidas dentro do bloco try. Este bloco pode ter zero ou mais cláusulas catch associadas. Cada cláusula catch declara um tipo de exceção correspondente ao tipo do erro que vai ser tratado. Blocos try-catch podem ser aninhados irrestritamente. Um bloco finally é executado sempre, independentemente da ocorrência de uma exceção no bloco protegido. No trecho de código abaixo podemos visualizar a construção básica do bloco try-catch: try { //Sequência de instruções que podem lançar exceções. //Se ocorrer uma exceção do tipo Exception //ou qualquer subtipo desta classe, o fluxo de //controle da execução segue para o bloco //catch no ponto onde a exceção ocorreu. } catch (Exception e) { //código de recuperação do erro. //pode conter outros blocos protegidos } finally { //este bloco sempre é executado //independentemente da ocorrência de uma exceção }. 11.

(31) 2.4. TESTE DE SOFTWARE. Antes que uma exceção seja capturada, em algum local do código do programa ou fora dele, é necessário que esta exceção seja lançada. A exceção lançada pode ser proveniente do seu próprio componente, de um componente externo ou até mesmo da máquina virtual Java. Independentemente de onde a exceção é originada, esta é lançada através da instrução throw. O trecho de código abaixo demostra o lançamento de uma exceção do tipo InvalidUserException na linha 5. Um método pode lançar uma exceção ao encontrar uma situação a qual não possa lidar, ou seja, o método propaga a exceção até achar um tratador adequado para a exceção lançada. Para isso o método deve informar o tipo de exceção ao qual deseja propagar. Na linha 1 do exemplo abaixo, a exceção do tipo InvalidUserException é repassada para o método que fez a chamada a requestUserInfo. 1- public void requestUserInfo() throws InvalidUserException{ 2if (user.activeUser()) { 3user.showInfo(); 4else { 5throw new InvalidUserException(); 6} 7- }. Exceções podem ser levantadas em qualquer ponto de um programa e, se não forem capturadas, podem ser propagandas de forma transparente ao ponto de entrada do programa, fazendo com que a o programa encerre a sua execução de forma inesperada.. 2.4 Teste de Software A construção de um sistema computacional pode ser uma tarefa bastante complexa, dependendo das suas características e dimensões [46]. Devido a este fator, um sistema computacional está sujeito a diversos tipos de problemas tornando-o diferente do que foi originalmente projetado. Diversos problemas podem estar relacionados, o mais comum é o fator humano [46]. As atividades de engenharia de software dependem muito das habilidades e conhecimento técnico dos engenheiros de software bem como a interpretação da especificação, e por fim, a implementação gerada a partir do entendimento da especificação. Teste de software é um processo que consiste em executar um sistema com o objetivo de encontrar defeitos [35]. Atividades de validação, verificação e testes de sistemas são utilizadas com o objetivo de obter um produto mais próximo ao que foi especificado.. 12.

(32) 2.4. TESTE DE SOFTWARE. Durante a construção, as suas partes assim como o sistema como um todo são testados com o objetivo de verificar a sua conformidade com a sua especificação. Se o sistema exibe algum tipo de divergência, torna-se necessária a realização de correções no sistema, no processo do desenvolvimento ou na sua especificação.. 2.4.1 Estratégia de teste Uma estratégia de teste deve lidar com testes de unidades visando verificar se uma pequena parte do código escrito foi desenvolvida de acordo como especificado, com testes que envolvem a integração de partes do sistema e com testes para o sistema como um todo, para validar os requisitos do cliente. As estratégias podem ser divididas em quatro fases distintas: teste de unidade, teste de componentes, teste de integração e teste de sistemas [7]. Teste de Unidade Teste de unidade verifica se uma porção do código fonte realiza adequadamente a funcionalidade proposta isoladamente do restante do sistema[46]. Devido a esta característica geralmente necessita de drivers e stubs. Um driver é um elemento que aplica os casos de teste. Ele é responsável por fornecer os dados de entrada, coletar os dados de saída e apresentá-los ao usuário. Já o stub serve para substituir os módulos necessários que não estejam disponíveis, com o objetivo de simular o seu comportamento, para a execução da unidade. Isso permite que o código relativo à unidade a ser testada possa ser verificado isoladamente. Teste de Componente Um componente é uma unidade de composição com interfaces bem definidas. Nesta fase o componente é testado de acordo com as especificações das funcionalidades e de sua estrutura [36]. Para esta técnica a utilização de drivers e stubs pode ser necessária. Teste de integração Uma vez testados os componentes individuais, estes devem ser integrados para criar sistemas parciais ou completos. Este processo de integração envolve construir o sistema e testá-lo quando a problemas relacionado a sua integração. Nesta fase são realizados testes de integração a fim de testar erros decorrentes deste cenário. Estes visam descobrir erros arquiteturais relacionados às interfaces dos componentes[46]. As três abordagens. 13.

(33) 2.4. TESTE DE SOFTWARE. principais de testes de integração são: big bang, top-down e botton-up. No big bang, todos os componentes são integrados de uma só vez não sendo necessário o uso de drivers e stubs. Porém nesta abordagem torna-se difícil a localização das falhas. Na abordagem top-down os componentes são integrados a partir do bloco principal do programa, não sendo necessários os drivers, porém stubs podem ser necessários. Na abordagem bottom-up, os componentes são integrados a partir dos componentes independentes, dispensando o uso de stubs. Neste caso novos drivers devem ser criados a cada integração. Teste de Sistemas Teste do sistema é o processo com o objetivo de verificar se o programa, como um todo, não atende aos seus objetivos. Tem utilidade limita se não existe um conjunto de objetivos mensuráveis para o produto[36]. Os testes de sistemas se baseiam nos requisitos funcionais e não funcionais do sistema.. 2.4.2 Teste estrutural A técnica estrutural estabelece os requisitos de teste com base em uma dada implementação, requerendo a execução de partes ou de componentes elementares do programa [36]. Esta técnica baseia-se na estrutura do programa e permite que seja examinada a sua estrutura interna. Nessa técnica os aspectos de implementação são fundamentais na escolha dos casos de teste. Em geral, a maioria dos critérios da técnica estrutural utiliza uma representação de Grafo de fluxo de controle CFG [36]. Um grafo de fluxo de controle G = (N,E,s) é um grafo dirigido que consiste de um conjunto N de nós, um conjunto E de arestas dirigidas e um nó de entrada s. Os nós representam comandos ou uma coleção de comandos sequenciais e as linhas ou arestas representam o fluxo de controle. O grafo de fluxo possui nós de entrada, nos quais a computação começa, e nós de saída cuja, terminando a computação. Os critérios pertencentes a esta técnica são classificados com base na complexidade, no fluxo de controle e no fluxo de dados [46]. Os Critérios baseados no fluxo de controle utilizam informações do grafo de fluxo de controle para derivar os requisitos de testes. Os critérios baseados em fluxo de controle mais conhecidos são Todos-Nos, Todas-Arestas e Todos-Caminhos. O critério baseados em fluxo de dados utiliza informações do fluxo de dados pra derivar os requisitos de teste. Para isso é necessário adicionarão grafo de fluxo de controle informações a respeito do fluxo de dados, caracterizando o Grafo Def-Uso [67] . Os principais critérios baseados em fluxo de dados. 14.

(34) 2.4. TESTE DE SOFTWARE. são [67]: Todas-Definições, Todos-C-Usos, Todos-P-Usos, Todos-Uso, Todos-C-Usos, Todos Caminhos-DU, Todos-Caminhos-DU, Todos-Potenciais-Uso.. 2.4.3 Teste Funcional Esta técnina checa se um programa está de acordo com a sua especificação, independentemente do código fonte. Teste funcional é também conhecido como teste caixa-preta ou teste comportamental. Ao se testar um sistema computacional (S) são escolhidos alguns pontos específicos do domínio do sistema D(S) para a execução de (S) [46]. Idealmente, os testes devem ser realizados para todos os elementos do domínio do sistema. Porém esta ação torna-se bastante custosa. Devido a esta limitação, faz-se necessária a adoção de critérios de seleção dos elementos do D(S) com o objetivo de obter um conjunto reduzido com alta probabilidade de revelar uma falha. Estes critérios visam estabelecer condições que devem ser satisfeitas no decorrer dos testes. Os critérios de teste funcionais são utilizados para se projetar casos de testes os quais o programa ou sistema é considerado caixa preta [46]. Os detalhes internos não são considerados na execução dos casos de teste. Para testar o sistema, são fornecidas entradas e avaliadas as saídas geradas para verificar se estão em conformidade com a especificação. As fontes utilizadas pelos testes funcionais são as especificações de requisitos e de projeto. As abordagens mais conhecidas desta técnica são: Particionamento de equivalência, Análise do Valor Limite, Grafo Causa-Efeito e Error-Guessing. Particionamemnto de equivalência Técnica utilizada para a escolha de dados de entrada para testes[46]. O domínio de entrada é dividido em classes de equivalência, que representam um conjunto de valores válidos ou inválidos para as condições de entrada. Análise do Valor Limite Técnica utilizada para escolha de dados de entrada, combinada com a técnica de particionamento de equivalência. Como grande número de erros tende a ocorrer nos limites dos valores de entrada, a técnica de análise de valores limite determina que os dados de entrada escolhidos sejam valores limite de cada uma das classes de equivalência[46].. 15.

(35) 2.5. JUNIT. Grafo Causa-Efeito Esse critério de teste verifica o efeito combinado de dados de entrada. As causas, condições de entrada, e os efeitos, ações, são identificados e combinados em um grafo a partir do qual é montada uma tabela de decisão, e a partir desta, são derivados os casos de teste e as saídas. Esta técnica descreve o comportamento do sistema em forma de elementos e os relacionamentos entre eles[36]. Existem várias formas de representar o sistema como um grafo, por exemplo, modelo de fluxo de transações (do inglês Transaction flow model TFM) e máquina de estado finitos[7]. Por ser uma técnica para a geração de casos de teste, pode ser utilizada em conjunto com técnicas para a geração de dados de entrada. Error-Guessing Consiste em uma técnica ad-hoc na qual a pessoa pratica inconscientemente, uma técnica para projetar casos de testes, supondo por intuição ou experiência alguns tipos prováveis de erros e, a partir disso, definem-se casos de testes que poderiam detectá-los [36]. A ideia básica é enumerar uma lista de possíveis erros ou situações sujeitas a erros e, em seguida, escrever casos de teste com base nesta lista.. 2.5 JUnit Ferramentas e técnicas para a realização de testes automatizados de software contribuem para o controle da execução dos testes e auxilia na comparação dos resultados esperados em comparação aos resultados obtidos pela execução do programa testado. Através destes testes, é possível configurar as precondições e outras funções de controle e obter relatório dos testes. JUnit [18] rapidamente tornou-se o framework padrão para o desenvolvimento de testes de unidade em Java. Este framework foi criado por Eric Gamma e Kent Beck, com suporte à criação de testes automatizados na linguagem de programação Java. Esta seção se destina a apresentar parte das funcionalidades deste framework. Embora seja possível o uso de qualquer funcionalidade do JUnit na abordagem posposta, no restante deste tópico iremos abordar apenas as construções necessárias para o entendimento da extensão criada para dar suporte a testes do comportamento excepcional. Sendo assim maiores detalhes dobre o jUnit podem ser encontrados no site do projeto 1 bem como informações sobre o projeto e arquitetura2 . 1 http://www.junit.org 2 http://junit.sourceforge.net/doc/cookstour/cookstour.htm e. http://junit.sourceforge.net/doc/. 16.

(36) 2.5. JUNIT. Um caso de teste é responsável por especificar um conjunto de entradas de teste, condições de execução e resultados previstos, com a finalidade de fazer a avaliação de algum aspecto particular de um cenário a fim de verificar se o componente testado está funcionando de acordo com as suas especificações [36]. No JUnit 4, podemos construir um caso de testes definindo um ou mais testes. Para isso é usada a anotação @Test nos métodos responsáveis por testar partes do código em um sistema. O trecho de código abaixo mostra um teste em JUnit: public class MeuCasoDeTeste { @Test public void testMeuTeste() { Soma soma = new Soma(); assertEquals(30, Soma.somar(15,15), 0); } }. Neste caso de teste o método testMeuTeste() verifica se o retorno da soma ( método Soma.somar(int, int) ) é igual ao valor esperado. JUnit permite agrupar os casos de testes em suites de testes através da anotação @SuiteClasses. @RunWith(Suite.class) //Indica que está classe está associada a uma //suíte de teste (Suite.class) //Casos de testes que devem ser executados @SuiteClasses({ TC01.class, TC02.class, TC03.class}) public class AllTestsInjection02 {}. Esta Suite de testes agrupa os casos de testes TC01, TC02 e TC03. Todos os testes contidos nesses casos de testes serão executados. Através da anotação @Before é possível executar um ou mais blocos de código antes da execução do caso de teste. Pode-se também, após a execução deste, executar comandos através de métodos anotados por @After. A anotação @Before permite iniciar objetos e executar todos os pré-requisitos para que as condições iniciais do teste sejam atendidas. Já a anotação @After serve para liberar os recursos alocados. O teste anterior pode ser escrito novamente da seguinte maneira: public class MeuCasoDeTeste { Soma soma = null; @Before. 17.

(37) 2.5. JUNIT public void setUp() { soma = new Soma(); } @Test public void testMeuTeste() { Soma soma = new Soma(); assertEquals(30, Soma.somar(15,15), 0); } @After public void releaseResources() { soma = null; } }. Neste caso de teste, no método setUp é criado o objeto do tipo Soma necessário para o teste testMeuTeste. Por sua vez, no método releaseResources o atributo soma é desalocado. Os resultados dos testes são obtidos através da comparação entre os resultados especificados e os resultados verificados no processamento de um determinado dado. Em JUnit esta comparação é realizada utilizando-se os métodos da classe Assert. O método assertTrue verifica se uma condição é verdadeira, assertFalse verifica se uma condição é falsa, assertEquals verifica se dois objetos são iguais, assertNotNul verifica se um objeto não é nulo, assertNull verifica se um objeto é nulo, assertSame verifica se dois objetos possuem a mesma referência, fail serve para falhar um caso de teste . Para todos estes, caso a condição não seja atendida, uma exceção do tipo AssertionFailedError é lançada. JUnit também permite verificar se uma determinada exceção esperada de fato foi lançada na execução de um caso de teste, como pode ser observado no exemplo abaixo. @Test(expected=IOException.class) public void testMeuTeste() { Classe.metodo(); }. Este teste verifica se há ocorrência de uma exceção do tipo IOException na execução do teste. Se a exceção ocorrer o teste passa, caso contrário o teste falha.. 18.

(38) 2.6. TEST-DRIVEN DEVELOPMENT. 2.6 Test-Driven Development Test-Driven Development (TDD) [38] é uma técnica de desenvolvimento de software que vem ganhando atenção com a popularidade das metodologias ágeis de desenvolvimento de software. É uma das técnicas mais utilizadas em Extreming programming(XP) e outras metodologias de desenvolvimento ágil. TDD consiste em ciclos rápidos de testes, codificação e refatoração. Ao adicionar uma funcionalidade, vários destes ciclos são executados com pequenas tarefas objetivando implementar e aperfeiçoar o sistema de software até que não haja mais nada a acrescentar e mais nada a tirar [37]. Pesquisas apontam que esta prática reduz a incidência de defeitos [17]. Quando usada corretamente, esta técnica também ajuda a melhorar o projeto do sistema, documenta as interfaces públicas e protege, através dos testes automatizados, contra erros futuros [17]. TDD exige que os testes automatizados sejam escritos antes do código funcional.. 2.6.1 Etapas do TDD Passo 1: Pensar TDD utiliza testes pequenos para forçar o desenvolvedor a escrever seu código funcional. É recomendado que ele escreva somente o código necessário para que o teste passe. De acordo com os conceitos de XP, não devemos escrever nenhum código de produção a menos que um teste falhe. O primeiro passo consiste em imaginar o comportamento que o código deverá apresentar sempre quebrando em atividades bastante pequenas. Após esta atividade pensa-se em um teste pequeno que irá falhar a menos que o comportamento esteja presente. Este teste irá forçar a criação do código funcional referente ao comportamento desejado. Como exemplo, vamos pensar em um sistema que necessite lidar com números de CPF. Neste caso é necessário a criação de uma classe que represente um CPF. O número do CPF deve ser passado como parâmetro do construtor. Caso este seja inválido, uma exceção do tipo IllegalArgumentException deverá ser lançada. Este é primeiro passo de imaginar o comportamento desejado. Passo 2: Barra vermelha Neste passo deve ser escrito o código de teste, o mínimo necessário. Janzen et al [17] recomendam que os testes não passem de cinco linhas, caso possível. Inicialmente codifique em termos das classes e suas interfaces públicas, não levando em conta a implementação interna desta classe. Os primeiros testes serão escritos com o objetivo de. 19.

(39) 2.6. TEST-DRIVEN DEVELOPMENT. usar nome de classes e métodos que não existem ainda, forçando o programa a projetar a interface da classe da perspectiva do usuário da classe e não do seu comportamento interno. Após o teste ser codificado, deve ser executada a suíte de testes. Se o teste não falhar, ou se ele falhar de uma maneira diferente da esperada, algo está errado. Esta etapa é chamada de barra vermelha, pois na maioria das ferramentas, os testes que não passam resultam em uma barra vermelha. Exemplo: @Test(expected= IllegalArgumentException.class) public void testVerifyCpf() { Cpf cpf = new Cpf(00000000000); }. O código não compila devido ao teste preceder a implementação da entidadeCpf. Tendo em vista isto, devemos criar esta classe. public class Cpf { public Cpf(int cpfNumber) {} }. Agora o teste compila mas o teste ainda não passa como esperado, já que a lógica do código funcional não está completa. Passo 3: Barra verde O próximo passo consiste em escrever o código funcional, apenas o suficiente para o teste passar. Neste momento não é necessário a preocupação com a elegância do código. Após a escrita do código, os testes devem ser executados novamente. Neste momento todos os testes devem passar, sinalizando aderência à especificação dos testes. Se o teste falhar, o código deverá ser corrigido ou reescrito dependendo de sua complexidade. Exemplo: Para que o teste passe, é necessário adicionar o cálculo de verificação do CPF e caso este não seja válido, uma exceção deverá ser lançada. public class Cpf { int number; public Cpf(int cpfNumber) { if (!isValid()) { trows new IllegalArgumentException(); } else { this.number = cpfNumber; }. 20.

Referências

Documentos relacionados

Sempre que as entidades adjudicantes recorrerem à possibilidade prevista no n.º 3, alínea a), de formular especificações técnicas em termos de desempenho ou de

O Secretário Geral da OTM-CS fez este pronunciamento durante a cerimónia de abertura da IV Sessão Ordinária do Conselho Nacional do SNEB, realizada em finais de

O LAVI vem sendo montado gradativamente, com recursos provenientes do FDA (Fundo de Desenvolvimento Acadêmico) e LABGRAD (Programa de Apoio aos Laboratórios de

A jurisprudência do Supremo Tribunal Federal entende que, quando há deliberação de PEC que seja contrária a uma das chamadas “cláusulas pétreas” da Constituição Federal

Convencionam as partes que, exclusivamente para os empregados que mantêm contrato de trabalho com a mesma empresa ou, empresa do mesmo grupo econômico há mais de 10 (dez) anos e

Assim, a casa favorece as relações e a convivência entre (1) gerações de uma mesma família, entre (2) pessoas de famílias diferentes e que são afins na casa em que escolheram

78 Figura 3.27 Padrão de difração de pós obtido para o complexo ácido nalidíxico:Zn através (a) de síntese por solução, em comparação com os difractogramas

Ele certamente tem um histórico de pesquisa maior que o seu (por isso que ele é orientador), tem uma experiência na área para emitir opinião sobre o que pode ser interessante como