• Nenhum resultado encontrado

Seleção e Geração Automática de Casos de Teste a partir de Diagramas de Máquina de Estados Comportamentais da UML 2

N/A
N/A
Protected

Academic year: 2021

Share "Seleção e Geração Automática de Casos de Teste a partir de Diagramas de Máquina de Estados Comportamentais da UML 2"

Copied!
8
0
0

Texto

(1)

Seleção e Geração Automática de Casos de Teste a partir

de Diagramas de Máquina de Estados Comportamentais da

UML 2

Helton Souza Lima1, Everton Leandro G. Alves1, Franklin Ramalho1 1Grupo de Métodos Formais – Universidade Federal de Campina Grande (UFCG)

Campina Grande – PB – Brasil

{helton, everton, franklin}@dsc.ufcg.edu.br

Resumo. Neste trabalho foi investigada e implementada uma estratégia para a

seleção e geração automática de casos de teste a partir de diagramas de estados comportamentais da UML 2. Foi utilizado o algoritmo "Chinese Postman" para fazer a seleção dos casos de teste e o código gerado está em conformidade com o framework JUnit.

Abstract. In this work a strategy for automatic selection and generation of test

cases from UML 2 behavioral state machine diagrams was investigated and implemented. The “Chinese Postman” algorithm was used to perform test case selection and the generated code is in conformity to the JUnit framework.

1. Introdução

Testes baseados em modelos consistem na derivação de casos de teste a partir de documentos que especificam os requisitos do software e são considerados mais apropriados em detrimento de testes baseados em código, pois mostram conformidade (ou não) entre o produto final e a especificação inicial documentada [Gross 2003]. Além da conformidade com a especificação, testes baseados em modelos têm a vantagem de poderem ser gerados desde fases iniciais do processo de desenvolvimento e guiarem todo o processo de desenvolvimento. A automação dessa derivação é altamente desejável pois diminui o esforço manual empregado, aumentando a produtividade e a confiabilidade nos testes e diminuindo os custos.

No entanto, o método automático pode vir a gerar um grande número de casos de teste, incluindo redundância [Binder 1999]. Portanto, torna-se crucial o desenvolvimento de estratégias para a seleção dos casos de teste mais importantes para um dado contexto. Dentre os possíveis casos de teste a serem gerados, faz-se necessário avaliar propriedades específicas e minimizar redundância.

Neste artigo apresentamos uma solução automática para a seleção de casos de teste gerados a partir de máquinas de estados, mais especificamente para os diagramas de máquinas de estados comportamentais da UML 2. Além do algoritmo de seleção, foi desenvolvida a geração de casos de teste em conformidade com um framework bastante usado entre os desenvolvedores Java, o framework JUnit [Gamma and Beck 2007]. Para utilizar nossa solução, é suficiente criar um diagrama de máquina de estados comportamental em alguma ferramenta CASE para a UML versão 2.0 e exportá-lo para

(2)

O artigo está estruturado da seguinte forma. A Seção 2 apresenta os diversos elementos existentes em um diagrama de máquina de estados comportamental da UML na versão 2.0. Na Seção 3 são apresentadas, em linhas gerais, as técnicas de seleção e de geração dos casos de teste utilizadas no trabalho. Na Seção 4, um estudo de caso ilustra a utilização da solução proposta. Na Seção 5, é feita uma análise crítica em relação aos trabalhos relacionados. Por fim, na Seção 6, são discorridas as considerações finais.

2. Diagramas de Máquina de Estados Comportamentais da UML 2

Na especificação da UML versão 2.0, as máquinas de estados estão representadas pelos diagramas de máquinas de estados comportamentais [OMG 2007]. Os elementos de um diagrama de máquina de estados comportamental da UML 2 são:

Estados. Representam uma situação em que: (i) uma condição (geralmente implícita) está sendo satisfeita: (ii) uma atividade está sendo executada; (iii) um sistema esperando por um evento a ser disparado; (iii) um sistema está na espera por um intervalo de tempo. Um estado pode ser de quatro tipos: (i) Simples: quando o estado não tem sub-estados; (ii) Composto: quando possui sub-estados, podendo possuir uma região ou mais; (iii) Sub-estado: quando o estado é parte de um estado composto; (iv) Estado Final: quando a região que contém esse estado é dada como terminada.

Pseudo-Estados. Existem 9 pseudo-estados: Estado inicial, Terminal, Ligação, Bifurcação, Junção, Escolha, Ponto de entrada, Ponto de saída e Histórico. Os pseudo-estados são pseudo-estados especiais, que possuem, cada um, propriedades específicas, com semânticas diferentes de qualquer outro elemento.

Região. É uma parte de um estado composto que contém uma máquina de estados. O estado composto pode possuir mais de uma região, onde cada região tem um comportamento ortogonal à outra região.

Transição. É um relacionamento direto entre dois estados, os chamados estados fonte e estado destino. É pela transição que há a habilitação de mudança de estados. Cada transição pode possuir um Evento, um Guarda e uma Ação.

Evento. Os eventos podem ser sinais, chamadas de operações, passagem de tempo ou mudança de estado.

Guarda. Expressão booleana a ser satisfeita após o evento para poder habilitar o disparo da transição.

Ação. Acontece após o disparo de uma transição e pode estar associada a algum estado (na entrada do estado ou na sua saída ou durante a permanência no estado).

A diferença entre máquinas de estados estendidas e os diagramas de estados comportamentais da UML 2 é que estes últimos possuem, adicionalmente, pseudo-estados e regiões, além de serem definidos com base em uma semântica menos abstrata, pois modelam o comportamento de um objeto que deve estar inserido em um contexto de uma classe.

(3)

3. Técnicas de Seleção e Geração de Casos de Teste

3.1. Seleção de Casos de Teste

Um algoritmo de seleção de casos de teste para máquinas de estados deve percorrer os diversos caminhos possíveis existentes na máquina de estados, já que a mesma consiste em um grafo. Dessa forma, os caminhos selecionados são possíveis combinações do comportamento do sistema. Como cada transição possui um evento, é suficiente que o caso de teste exercite o sistema através dos eventos do caminho específico e verifique se o sistema está mudando de estado de acordo com o diagrama construído.

Dentre os algoritmos estudados para caminhamento em máquinas de estados com o propósito de extrair caminhos válidos que possam ser executados, implementamos o algoritmo do “Chinese Postman” (CP) [Black 2004], pois atende a dois critérios cruciais em um algoritmo de seleção de casos de teste: cobertura e escalabilidade. Para o primeiro critério, ele possui uma cobertura de todas as transições e estados. Para o segundo critério, ele se comporta muito bem em modelos de grande escala, pois tenta cobrir cada transição exatamente uma vez [Nam et al 2006].

O algoritmo “Chinese Postman” nasceu da idéia de resolver o problema do carteiro, que deve entregar cartas percorrendo as ruas de maneira otimizada, com a menor distância percorrida possível, entre a saída de um ponto, até sua volta ao mesmo ponto. No caso das máquinas de estados, há uma comparação simples: as ruas são as transições e as esquinas são os estados. Dessa forma, o algoritmo cobre todas as transições, de maneira mínima, e acaba também atingindo todos os estados.

Sendo assim, o módulo responsável por implementar e executar a seleção dos casos de teste faz uso das informações lidas a partir do arquivo XMI correspondente ao diagrama de máquina de estados. Este módulo é iniciado através da varredura do modelo em busca do conjunto de objetos que representam a máquina de estados especificada. Esse conjunto de objetos é então passado para o módulo responsável pela implementação do algoritmo de seleção de caminhos escolhida para nossa solução (o CP).

Antes do início da execução do algoritmo, existe uma rotina de adequação do modelo para atender as restrições do CP, pois este algoritmo é somente executado em grafos fortemente conectados (que são grafos onde existe, necessariamente, um caminho entre dois estados quaisquer), o que nem sempre é verdade nas máquinas de estado.Para contornar essa restrição, a rotina de adequação dos modelos cria uma transição imaginária para cada estado (que não seja pseudo-estado), que possui cada estado como estado-fonte e o estado inicial como estado-alvo. Essa rotina de adequação das máquinas de estados não afeta a semântica do funcionamento das mesmas, pois as transições que são criadas são tratadas como um reinício na simulação da máquina de estados, pois o estado inicial é atingido novamente. Além da vantagem de possibilitar a execução do algoritmo de seleção de casos de teste, essas transições acabam por definir novos casos de teste, pelo fato de acarretar o reinício da máquina de estados. Essa solução também não traz um excesso de informação para a execução do algoritmo de seleção, pois o número de transições criadas é diretamente proporcional ao número de estados presente na máquina de estados.

(4)

3.2. Geração de Código de Teste

Após a seleção dos casos de teste, faz-se necessário gerar código de teste em alguma linguagem de programação para que os testes possam ser executados. Para isso, foi criado um módulo de geração de casos de teste, responsável por transformar os caminhos selecionados pelo módulo de seleção em código de teste. Foi escolhido gerar código para o framework JUnit, que automatiza os casos de teste e é bastante conhecido na comunidade Java. Esse módulo é o responsável para determinar a semântica necessária para o mapeamento dos diversos elementos dos diagramas de máquinas de estados comportamentais em código que simule a execução da máquina de estados especificada. Além disso, esse módulo cria um código que, durante essa simulação, verifica se a classe sob teste se comporta da maneira esperada. Para a criação dessa simulação é necessária a criação de uma semântica própria para cada elemento existente nos diagramas de estados comportamentais da UML 2.0. A seguir, é apresentada a forma como cada elemento encontrado no diagrama de máquina de estados comportamental é transformado em código Java.

Transições e Eventos: a ocorrência de um evento é mapeada para uma chamada de um método da classe sob teste. Os eventos das transições que tem como estado-fonte o estado inicial, são mapeados para chamadas do construtor padrão da classe sob teste, e um novo objeto desta classe é criado. As transições imaginárias criadas para adaptar o modelo são ignoradas nesse módulo. Auto-transições são também cobertas por este módulo. É através do mapeamento de eventos que é gerada a simulação do sistema modelado pela máquina de estados especificada.

Estados: criados os mapeamentos necessários para uma simulação básica da máquina de estados, resta agora criar os mapeamentos necessários para a verificação do comportamento esperado da classe sob teste. Desta forma, ao verificar-se que uma transição entre estados foi disparada, e houve mudança de estado, há a criação de código que verifica se a classe realmente está no estado para qual foi mudado. Esse código é criado utilizando-se uma rotina de verificação existente no framework JUnit, chamada

assertEquals. Para esta rotina são passados dois parâmetros: (i) o nome do estado

esperado da classe sob teste, e (ii) a chamada de um método desta classe que deve retornar o estado atual da mesma. A rotina assertEquals verifica se o nome do estado retornado pela classe e o nome do estado esperado são iguais. O resultado é observado na interface gráfica do JUnit.

Guardas: os guardas são mapeados para comandos condicionais (if-then-else), da linguagem Java, onde o parâmetro do comando consiste no corpo do guarda. Esse comando é inserido no código de teste logo após a chamada do método que corresponde à ocorrência do evento associado àquela transição que está sendo disparada. Em seguida, a rotina de verificação de mudança do estado é inserida dentro do corpo do comando condicional, assim como qualquer código de teste que venha a ser criado após a verificação da condição especificada pelo guarda.

Ações: ações não devem ser mapeadas diretamente para código de teste, pois elas devem ser executadas implicitamente assim que o evento seja lançado e o guarda eventualmente especificado seja satisfeito para uma dada transição. O código de teste não tem, assim, a responsabilidade de executar as ações, mas apenas de verificar se elas ocorreram da forma esperada. Essa verificação, para diagramas de estados, acontece

(5)

apenas nas asserções que envolvem o estado atual do objeto, o que já acontece mesmo sem a presença das ações.

4. Estudo de caso

Para ilustrar os resultados do trabalho, foi implementado um estudo de caso que descreve o ciclo de vida de um livro dentro do universo de uma biblioteca. Nesse contexto, um livro pode assumir diversos estados (Disponível, Reservado, Emprestado e

Atrasado) de acordo com a sua situação corrente.

O diagrama de máquina de estados comportamental da UML 2 que modela o comportamento da classe Livro é apresentado na Figura 1. Nesta, podem ser observadas as possíveis situações que um livro pode assumir (estados) e, como estas podem ser alcançadas (transições simples ou com guardas).

Aplicando a solução desenvolvida ao diagrama da Figura 1, um dos casos de teste gerado (de um total de seis possíveis) é apresentado na Figura 2. Através da análise do código gerado, pode-se acompanhar o caminhamento feito pelo algoritmo de seleção. Adicionalmente, a cada estado atingido, uma nova asserção é feita para verificação do estado atual da classe.

Na linha 2, o objeto livro é criado, o que significa que ele saiu do estado inicial, percorreu a transição e está em seu primeiro estado: Disponível. O código faz, então, uma asserção em relação a esse primeiro estado (linha 3). Na linha 4, a operação

emprestar é invocada, caracterizando o evento que vai disparar a mudança de estado. Na

linha 5, uma nova asserção é realizada a respeito da mudança para o novo estado:

Emprestado. Na linha 11, temos o código do comando if, onde a condição corresponde

ao guarda da transição que sai do estado Emprestado e chega no estado Reservado. Todo o código existente a partir da linha 12 está sujeito a essa condição. O restante do código segue a mesma linha de raciocínio.

(6)

Figura 2: Código de teste criado para o diagrama de estados da classe Livro

5. Trabalhos relacionados

Na última década, a UML tem se tornado o padrão de facto na indústria de software na modelagem de sistemas. Pesquisas em testes baseados em modelos UML têm sido realizadas desde o fim dos anos 90, especialmente trabalhos envolvendo teste de classes e diagramas de estados [Kim et al 1999]. Trabalhos envolvendo geração de testes e verificação para máquinas de estados finitas têm seu início ainda antes.

Algumas abordagens incluem o uso da UML para geração de testes no qual o modelo é compilado para um formato intermediário (Intermediate Format) [Crichton et al 2001]. Muitas abordagens para geração de código de teste baseado em diagramas de estados têm sido específicas para determinadas ferramentas [Offutt and Abdurazik, 1999], restringindo o seu uso. Muitos trabalhos não utilizam soluções que englobam diagramas de estados com estados compostos [Hartmann et al, 2000], outros utilizam técnicas de eliminação de estados compostos para trabalhar com algoritmos para máquinas de estados finitas comuns [Kim et al, 1999].

Quanto a ferramentas que implementam essas idéias de geração de código de teste baseado em diagramas de estados, temos a ferramenta ACUTE-J [Nam et al 2006], que está atualmente em fase terminal de implementação. Ela trabalha com diagramas de

(7)

estados UML e inclui a aplicação de algoritmos de seleção de casos de teste (como o “Chinese Postman”) para geração de código de teste em conformidade com o framework JUnit. Entretanto, esse trabalho foi descontinuado e suas publicações não oferecem um nível de detalhamento da cobertura dos elementos de um diagrama de estados. Além do mais, não explicam como se dá a utilização do algoritmo de seleção, já que para aplicá-lo é necessário modificar a máquina de estados, transformando-a em um grafo fortemente conectado. Por fim, essa ferramenta não dá suporte a diagramas que possuem transições com guardas.

Outros algoritmos de seleção de caminhos nas máquinas de estados são considerados. O método Wp, é um algoritmo que constrói uma árvore de alcance, e o segundo, chamado UIO (Unique Input Output) é baseado em seqüências únicas de entrada para cada estado. Entretanto, ambos os métodos são avaliados como não escaláveis [Burton 2002], pois podem gerar seqüências muito grandes. Sendo assim, são propostas abordagens híbridas (com combinações de vários algoritmos) para atingir a cobertura desejada com uma boa eficiência [Burton 2002] [Aho et al 1995].

6. Considerações Finais

Este artigo apresenta uma implementação de uma estratégia de seleção e geração automática de casos de teste (em JUnit) a partir de diagramas de estados comportamentais da UML2.

Durante o desenvolvimento desse trabalho foram identificados outros trabalhos envolvendo geração de testes baseados em máquinas de estados, o que mostra a importância desse tipo de modelagem dentro dos processos de desenvolvimento de software e hardware. Várias abordagens de seleção de casos de teste também têm sido empregadas através da análise da aplicação de diversos algoritmos. Entretanto, existem poucos trabalhos que utilizam a UML, linguagem que se tornou o padrão na indústria de software para modelagem de sistemas. Além disso, a UML continuamente vem sofrendo mudanças em sua especificação. A solução apresentada neste artigo: (i) é baseada na especificação 2.0 da UML; (ii) garante compatibilidade com as ferramentas de modelagem mais usadas.

Quanto à geração de código de teste, nossa solução dá suporte a diagramas de estados comportamentais simples, cobrindo modelos com estados, transições, eventos e guardas. O algoritmo escolhido para fazer a seleção dos casos de teste se comporta de maneira satisfatória, fazendo a cobertura de todas as transições, entretanto é necessária uma melhor avaliação do algoritmo usado, principalmente comparando sua eficácia em encontrar falhas em relação a outros algoritmos existentes.

Alguns dos elementos presentes nestes tipos de diagramas não possuem um mapeamento direto para código JUnit. Um exemplo é o mapeamento de guardas, que não foi coberto por nenhum outro trabalho até então. Em nossa solução, o código gerado permite fazer uma asserção sobre o estado destino (para qual o disparo da transição aponta) apenas se a condição do guarda for satisfeita. Caso contrário, todo o código gerado dentro do corpo do if é ignorado, o que é altamente indesejável. O ideal seria garantir que as condições dos guardas fossem satisfeitas, para que o caminho gerado do caso de teste, que contém transições com guardas, fosse completamente executado.

(8)

Como trabalhos futuros, desejamos (i) investigar e implementar soluções para os vários outros elementos presentes nos diagramas de estados comportamentais da UML 2; (ii) implementar e analisar outros algoritmos de seleção de casos de teste, incluindo abordagens híbridas como a proposta em [Aho et al 1995]. Isto permitiria uma melhor avaliação do método utilizado; (iii) considerar informações provenientes de outros diagramas da UML (p.e., diagramas estruturais).

Agradecimentos

Nós gostaríamos de agradecer a Patrícia Machado pelos preciosos comentários durante o desenvolvimento deste trabalho, que foi parcialmente financiado pelo CNPq.

Referências

Aho, Alfred V. and Dahbura, Anton T. and Lee, David and Uyar, M. Umit. (1995) “An optimization technique for protocol conformance test generation based on UIO sequences and rural Chinese postman tours” In Conformance testing methodologies and architectures

for OSI protocols, pages 427 – 438 IEEE Computer Society Press.

Binder, R. (1999) “Testing Object Oriented Systems: Models, Patterns and Tools”, Addison Wesley.

Beck, K. (2002) “Test-Driven Development: By Example”, Addison Wesley.

Black, P. E. (2004) “Chinese Postman Problem” in Dictionary of Algorithms and Data Structures, http://www.nist.gov/dads/HTML/chinesePostman.html , December.

Burton, S. (2002) “Automated Generation of High Integrity Test Suites from Graphical Specifications”. PhD Thesis. University of York, Departament of Computer Science, March 2002.

Crichton, C and Cavarra, A. and Davies, J (2001) “Using UML for Automatic Test Generation”, Automated Software Engineering.

Gamma, E. and Beck, K. (2007) “JUnit” http://junit.org , June.

Gross, H. (2003) “Testing and the UML – A perfect fit”, Technical Report, Fraunhofer IESE, Report 110.03E.

Hartmann, J. and Imoberdorf, C and Meisinger, M (2000) "UML-Based Integration Testing", International Symposium on Software Testing and Analysis 2000 (ISSTA 2000), Portland, USA.

Kim, Y. G. and Hong, H. S. and Cho, S. M. and Bae, D. H. and Cha, S. D. (1999) “Test Cases Generation from UML State Diagrams”, IEE Proceedings – Software, 146(4):187–192. Nam, H. D. and Mousset, E. C. and Levy, D. C. (2006) “Automating the Testing of Object

Behaviour: A Statechart-Driven Approach”, Transactions on Engineering, Computing and Technology.

Offutt, J. and Abdurazik, A. (1999)“Generating Tests from UML Specifications”, Second International Conference on the Unified Modeling Language (UML 99), Fort Collins, CO, pp. 416-429.

OMG – Object Management Group (2007) “Unified Modeling Language: Superstructure, Version 2.1”. http://www.omg.org/cgi-bin/doc?ptc/2006-04-02

Referências

Documentos relacionados

Podemos então utilizar critérios tais como área, arredondamento e alongamento para classificar formas aparentadas a dolinas; no processamento digital de imagem, esses critérios

Visando utilizar este fato como técnica de mapeamento geológico, foi feita a classificação de imagens Landsat baseada na resposta espectral dessas depressões cársticas.Como

Apesar da longa distância dos grandes centros urbanos do país, Bonito destaca- se, regionalmente, como uma área promissora dentro do Estado de Mato Grosso do Sul. Bonito,

• A Revolução Industrial corresponde ao processo de industrialização que teve início na segunda metade do.. século XVIII no

Embora os resultados demonstrem que os profissionais estudados apresentam boas condições emocionais (dedicação), a redução observada nas dimensões vigor, absorção e escore

Em todas as vezes, nossos olhos devem ser fixados, não em uma promessa apenas, mas sobre Ele, o único fundamento da nossa esperança, e em e através de quem sozinho todas as

• The definition of the concept of the project’s area of indirect influence should consider the area affected by changes in economic, social and environmental dynamics induced

Por sua vez, a complementação da geração utilizando madeira, apesar de requerer pequenas adaptações do sistema, baseia-se em um combustível cujas origens são mais diversifi