• Nenhum resultado encontrado

O trabalho relatado por Krause e Wahls em [KW07] demonstra uma validação da tradução a partir de especificações JML para códigos binários utilizando jmle. Os autores utilizam testes exploratórios e encontram algumas falhas em relação à herança de objetos. Porém, eles se beneficiam por utilizarem testes de caixa branca para verificar o real motivo do problema, isto porque um dos autores é o criador do jmle. Estas falhas foram consertadas antes de nosso trabalho ser iniciado.

Bogdan e George [KK09] propõem uma estratégia para a utilização de testes de regressão para verificar a eficiência da priorização de testes baseados em modelos ao invés de priorizar a escrita do código fonte. Quando os autores utilizam a priorização dos métodos, eles podem detectar as falhas mais cedo no código desenvolvido. Neste trabalho foi realizada uma estra- tégia similar de priorização. Isto foi realizado quando, na configuração da geração dos casos de testes, foram utilizados os pesos das classes (onde os métodos da classe principal foram priorizados).

Como resultado, Bogdan e George concluíram que a priorização de testes baseados em modelos são menos custosas que a escrita do código fonte, mesmo que se possua um gasto inicial para a escrita dos modelos. O que está sendo proposto por este trabalho é exatamente a utilização inicial dos modelos para a criação dos códigos-fonte e também para criação de casos de testes, quando se possuir uma ferramenta confiável.

Farooq e Lam [FL09] utilizam testes baseados em modelos para reduzir o número de casos de testes redundantes. O estudo realizado pelos autores indica que a redundância nas suítes de testes gerada através de modelos pode ser detectada mais cedo e removido antes da sua execução. Porém, diferentemente deste trabalho, Farooq e Lam utilizam a especificação UML ao invés de JML. A solução proposta por eles é interessante, isto porque o Jartege, por exemplo, pode gerar uma grande quantidade de testes redundantes.

Para diminuir as redundâncias dos casos de teste, Farooq e Lam utilizaram um framework denominado de Evolutionary Computation (EC). Este framework utiliza técnicas meta-heurísticas e são utilizadas no processo de evolução natural. Mas, depois de algumas análises foram veri- ficadas que as classes do EC são ótimas para o processo de pesquisa. É através deste conjunto de classes que os autores fazem uma busca por casos de testes redundantes. O resultado fi- nal obtido, em comparação a outros dois algoritmos de pesquisa (Hill Climbing e Greedy) foi satisfatório e a quantidade de casos de testes redundantes excluídos ficou na faixa de 80%.

Pasareanu et al. [PSM+09] descrevem um framework para modelos baseados em análise e testes. O framework utiliza a combinação entre MathWorks e o modelo UML 2.0. O framework é baseado em uma representação intermediária comum para diferentes modelos de formalismos e os modelos também são estendidos para verificar e executar ferramentas de execução simbó-

CAPÍTULO 5 TRABALHOS RELACIONADOS 50

lica para analisar e gerar casos de teste, respectivamente.

Javed et. al. [JSW07] demonstram no trabalho uma estratégia diferente da apresentada neste trabalho. A estratégia utilizada pelos autores indica a utilização do MDA (Model-Driven

Architecture) para a verificação e validação do código gerado a partir de especificações UML,

que são representados por diagramas de sequência. Nesse trabalho, o MDA é utilizado para a criação dos casos de testes, porém a sequência de dados para exercitar os testes não são gerados automaticamente. Um problema do trabalho de Javed é que, para a geração de casos de testes a partir de diagramas de sequência, são necessárias muitas etapas para obter o resultado final, que são os casos de teste. Com isso a automação da geração é prejudicada.

A utilização de modelos para geração de código pela indústria pode ser observada no tra- balho de Rugina et. al. [RTOV08]. No trabalho, os autores utilizam modelos matemáticos para gerar códigos automaticamente. A criação dos modelos é realizada no MatLab-Simulink e Scilab-Scicos. O código gerado pela ferramenta proposta é para ser utilizado em sistemas embarcados de carros e aeronaves. Por serem sistemas críticos, é necessário que sejam execu- tadas verificações e validações no código produzido. Para realizar essas validações, os autores realizaram uma série de análises com o código produzido. Entre estas análises foi verificada a diferença de tamanho do código gerado automaticamente e um código escrito manualmente. Como resultado foi observado que os códigos eram semelhantes. Esta verificação do código gerado com o manual não foi realizada neste trabalho. Para isso a nossa estratégia utilizou testes baseados em modelos para analisar essa corretude.

Como a indústria exige certificações que garantam a qualidade do software que está sendo utilizado, Conrad [Con09] realiza a validação do processo de tradução de especificações para códigos executáveis de acordo com a norma da certificação IEC 61508. Para a verificação e validação dos modelos, o autor criou um workflow para todo o processo de tradução dos modelos. Porém, segundo o autor, alguns questionamentos foram realizados antes da execução dos testes. Entre eles: se o que está especificado no modelo condiz com os requerimentos do sistema? O código produzido cumpriu o que estava descrito nas especificações?

Diferentemente do atual trabalho, no qual consideramos e demonstramos que a especifi- cação está de acordo com os requisitos no sistema, Conrad realiza a verificação da corretude das especificações através da revisão, análise estática e a compreensão das funções que serão realizadas pelo modelo. Estas etapas de verificação são exigidas pela IEC 61508. Já para a verificação do código produzido, Conrad realizou testes sistemáticos (teste de equivalência) para demonstrar que a execução semântica do modelo está sendo preservada durante a geração e compilação. Todo o estudo de caso foi realizado na linguagem de programação C.

Já o trabalho realizado por Galler et. al. [GPW08] se aproxima do que foi realizado neste trabalho. Os autores apresentam um comparativo de diferentes alternativas para geração de ca- sos de teste aleatoriamente através de programas baseados em contrato, mais especificadamente

ModernJass [Rie07]. No artigo, foi realizada uma extensão de uma ferramenta, JET [CCLC08],

que utiliza JML para a geração de casos de testes. Para a validação dos casos de testes gera- dos pela ferramenta criada, Galler utilizou três estratégias para a criação dos dados que foram executados durante os testes: utilização de testes randômicos, utilização do Z3 SMT Solver e inserção de dados manuais.

CAPÍTULO 5 TRABALHOS RELACIONADOS 51

de geração de dados, verificar qual é a melhor estratégia para geração de casos de testes mais exatos. Além disso, o autor demonstrou que apesar de ter utilizado testes mais sofisticados com o SMT Solver, o aumento da cobertura do código não aumenta da maneira esperada. Para melhorar o problema de cobertura de código, o autor decidiu realizar intervenções manuais. Galler também cita a utilização da mesma ferramenta para geração de casos de testes utilizadas neste trabalho, o Jartege. Porém, para ele, a utilização de SMT Solvers pode melhorar nos exercícios de teste.

Em Hierons et. al. [HBB+09] é demonstrado como as especificações formais podem auxi- liar na geração de testes. Os autores ainda demonstram que a indústria tem começado a utilizar as especificações formais para criação de casos de testes. Eles ainda demonstram os ganhos de qualidade do software no final do processo de testes. A utilização de especificações formais, como a deste trabalho, também demonstra que, se possuirmos ferramentas confiáveis, não só o processo de testes pode ter sua qualidade garantida, mas também o processo de desenvolvi- mento, através de geradores automáticos de código.

C

APÍTULO

6

Conclusão

No presente trabalho foi apresentada uma simples estratégia para verificar a corretude de ge- radores de código baseados em contratos, utilizando testes baseados em modelos. Usamos um gerador de casos de testes que, além de criar os scripts de teste (esqueletos de código), também criam os dados necessários para executar e avaliar os testes. A principal contribuição deste tra- balho é propor uma estratégia que demonstra a utilização de ferramentas baseadas em modelos para geração de códigos fontes e casos de teste e como a segunda pode ser usada para atestar a confiabilidade da primeira.

Para apresentar a aplicação desta estratégia, foi utilizada a especificação da API JavaCard como estudo de caso, o gerador de código jmle e a ferramenta de testes baseadas em modelos Jartege. Ao se realizar experimentos utilizando este estudo de caso, foi possível demonstrar que o jmle não é livre de falhas e uma destas falhas encontra-se na manipulação de arrays. Além disso, como foi utilizado um código disponibilizado pela própria Sun, pôde-se reutilizar nossa própria estratégia neste código, onde não conseguimos encontrar qualquer discrepância da especificação JML. Apesar de não podermos afirmar que o código da Sun é correto, isto nos permite dizer que o código produzido pela Sun Microsystem é de alta qualidade.

Com o presente estudo, ainda não podemos garantir que o jmle possui apenas falhas asso- ciadas à manipulação de arrays. A principal motivação sobre nossa conclusão parcial é que foram realizados testes aleatórios para exercitar os casos de teste. Algum trecho do código pro- duzido pelo jmle pode não ter sido executado e uma possível falha pode não ter sido detectada, especialmente aqueles associados a outros elementos suportados por JML, além de arrays.

Outro problema para a utilização do jmle é que, até a conclusão deste trabalho, algumas funcionalidades que podem ser utilizadas nos modelos JML não são traduzidas por jmle.

Como o jmle traduz as anotações em constraints, se for comparada a performance da exe- cução de um código criado manualmente com um código gerado pelo jmle, provavelmente o código manual terá uma melhor performance. Isto acontece porque durante a execução do jmle as constraints devem ser resolvidas.

A ferramenta utilizada para geração dos casos de teste (Jartege) também possui algumas limitações. Apesar de automatizar a criação de testes, o resultado final produzido nem sempre está de acordo com o que foi descrito no modelo; basicamente testes com pré-condições viola- das são gerados. Apesar disto não impactar sobre nossa estratégia, nos fez realizar vários casos de testes desnecessários, haja vista que ao violar a pré-condição, o veredicto do caso de teste é automaticamente verdadeiro, pois a especificação em geral não informa o que deve ocorrer em tais casos (exceto quando o contrato inclui exceções). Com isso, durante a utilização da estratégia, alguns ajustes manuais foram realizados. O grande problema desta geração foi a criação de pré-condições válidas. Em muitos casos a pré-condição do modelo JML era igno-

6.1 TRABALHOS FUTUROS 53

rada e os valores gerados eram incoerentes com seu modelo. Provavelmente esta falha já era prevista pelo criador da ferramenta visto que o Jartege permite que os valores primitivos para as pré-condições possam possuir uma faixa de valores válidos.

A vantagem da utilização do Jartege foi que a ferramenta é capaz de criar os dados e a estrutura para ser testada. Porém, a automação prevista pela utilização da metodologia MBT, em que apenas os modelos devem ser variados em casos de testes não são vistos no Jartege. Para a geração da suíte de teste, são necessárias muitas configurações nas propriedades da ferramenta. Muitas destas configurações não são intuitivas e, por exemplo, para a criação da faixa de valores para as pré-condições são necessários que sejam analisadas as especificações. Outro problema é que para a criação de cada classe de teste, é necessária a criação de uma classe para realizar o caso de teste.

Na experimentação realizada por este trabalho, verificou-se que, apesar da quantidade de testes realizados não ser tão grande (em uma situação ideal deveriam ser utilizados mais casos de testes já que foram usados testes aleatórios), a quantidade de falhas encontradas se estabili- zam depois de certa quantidade de testes. Para esta conclusão foram feitas análises estatísticas que indicaram:

• A alteração dos parâmetros de configuração do Jartege influenciam na quantidade de falhas encontradas;

• Na maioria das classes a quantidade de falhas eram lineares, esta análise indica que a quantidade de testes realizada foi suficiente;

• A utilização de diferentes seeds teve influência para o número de falhas encontradas.

6.1

Trabalhos Futuros

Existe um interessante trabalho relacionado para ser executado futuramente com os resultados obtidos através do experimento executado neste trabalho. Com o resultado final deste trabalho, percebeu-se que a mudança de alguns parâmetros de configuração do Jartege influencia o total de falhas encontradas. No entanto, o trabalho não explorou todas as configurações possíveis do Jartege, então não sabemos se os outros parâmetros também têm influência. Caso seja pla- nejado um experimento controlado baseado em um planejamento fatorial completo [BOX78], por exemplo, pode-se determinar estatisticamente quais parâmetros possuem reais influências.

Outro trabalho futuro é a intenção de melhorar a estratégia proposta por este trabalho atra- vés da utilização de resolvedores simbólicos, como os SMT Solvers, para indicar o conjunto de dados necessários para exercitar os casos de testes sem redundância e pesquisar todos os possíveis problemas no código no que diz respeito a sua especificação.

Outra direção corresponde à formalização das regras de redução do JML para restrições do JCK, e provando que estas regras sempre geram códigos corretos, assim como a fixação de qualquer problema encontrado.

A utilização de testes de mutação [FMR08] também podem auxiliar na avaliação do código gerado pelo jmle. Os testes de mutação podem ser utilizados para a alteração de fragmentos JML e usando jmle para verificar se o código resultante faz algum sentido.

Documentos relacionados