Atenção: esse artigo tem um vídeo complementar. Clique e assista!

Artigo no estilo: Curso

De que se trata o artigo:

Apresentaremos nesta série de artigos uma técnica baseada em templates de testes de design para a verificação de artefatos de diagramas de classes UML contra código Java. Nesta segunda parte de nosso artigo, apresentaremos uma abordagem de apoio à verificação de diagramas de classes da UML. Essa matéria foi escrita tendo como base a dissertação de mestrado intitulada Verificação de Artefatos de Diagramas de Classe UML através da Aplicação Testes de Design, do Programa de Pós-Graduação em Ciência da Computação da Universidade Federal de Campina Grande [1].

Para que serve:

Uma das principais contribuições em se aplicar teste de design é diminuir os custos do software. Custos com a manutenção do software podem chegar até 90% do custo total do ciclo de vida do software. Dentre esses custos destacamos o custo com a revisão de código.

Em que situação o tema útil:

Verificação de conformidade com o design é especialmente relevante em processos de desenvolvimento que promovem uma clara distinção entre artefatos de design e de implementação, como por exemplo, o RUP. E, especialmente, se equipes diferentes desenvolverem os artefatos de design e os de implementação.

Autores: Waldemar Pires Ferreira Neto, Franklin de Souza Ramalho e Dalton Serey Guerrero

Dado o problema da verificação dos artefatos do diagrama de classes UML apresentado na primeira parte deste artigo publicado na edição 35 da Engenharia de Software Magazine, a solução que apresentaremos neste artigo é a verificação desses artefatos através da criação de testes de design baseados em templates de código. Utilizamos templates, pois identificamos que os testes de design para a verificação dos artefatos do diagrama de classes seguem um padrão, e esse padrão consegue ser especificado através de templates de teste.

O uso de templates para geração de testes é utilizado há algum tempo para a geração de diversos tipos de testes. Na abordagem que apresentaremos, definiremos um template de teste para cada tipo de artefato no diagrama de classe.

Sendo assim, neste artigo mostraremos a forma como foram adotados os templates de teste. Inicialmente, apresentaremos como adotamos templates para a verificação das classes do diagrama de classe. Em seguida, apontaremos os demais tipos dos artefatos do diagrama de classe e suas características que são cobertas pelo nosso trabalho. Mostraremos ainda alguns artefatos que não podem ser verificados, e o porquê desse feito. Depois disso, ilustraremos a aplicação da abordagem para verificação das características referentes a um trecho do diagrama de classe de um sistema Web. Por fim, discutiremos como essa abordagem alcança todos os artefatos tratados, e como ela pode ser estendida para tratar outros artefatos.

Template do Teste de Design

A maneira como nós adotamos templates de testes para a verificação de artefatos dos diagramas de classe pode ser vista na Figura 1. Nessa figura podemos perceber que existem duas fases principais: a aplicação dos templates para diagrama de classe; e a execução dos testes pela aplicação dos templates.

Processo geral
para o uso de templates para a verificação de diagramas de Classe

Figura 1. Processo geral para o uso de templates para a verificação de diagramas de Classe.

Inicialmente, definimos um catálogo de templates genéricos capazes de identificar cada tipo de artefato tratado: classe, operação, atributo, pacote, interface e associação. Esses templates são métodos genéricos formados por trechos estáticos e algumas tags. Os trechos estáticos, como o próprio nome sugere, identificam a parte comum a qualquer teste de uma instância de um determinado artefato. As tags, sinalizadas com “<” e “>”, são os trechos variáveis desses testes, e devem ser substituídos pelas especificidades das instâncias de cada artefato no diagrama de classe. Em outras palavras, cada instância de um artefato no diagrama de classe gera um método que a testa, substituindo os tags do seu respectivo template pelas informações presentes no diagrama de classe.

Nas subseções a seguir, mostraremos os templates de testes de design para todos os artefatos tratados. Todos esses templates compartilham algumas propriedades:

· nome da entidade: várias tags dos templates são referentes ao nome completo das entidades. O nome completo de uma entidade é o seu nome, seguido da hierarquia de nomes das outras entidades onde esta entidade está contida. Todos esses nomes são separados por “.”. Por exemplo, a classe Classe1 está contida no pacote pacote2 que por sua vez está contido no pacote pacote1. Dessa forma, o nome completo da Classe1 deve ser pacote1.pacote2.Classe1;

· nome do teste: os métodos para cada artefato específico seguem um padrão que identifica o tipo de verificação. Todo método começa com o “test” e seguidos do nome do artefato a ser testado, identificando qual o artefato que está sendo testado. Logo após, vem um diferenciador (um contador, por exemplo) que garante uma assinatura distinta para qualquer método, identificado pela tag <dif>. Por fim, vem o nome completo da entidade a ser testada, substituindo o “.” por “_”, pois nomes de métodos não podem possuir “.”. Por exemplo, considere a classe mostrada no item anterior, Class1, o seu nome no método seria pacote1_pacote2_Classe1;

· templates de mensagens explicativas: as verificações realizadas através de uma assertiva (assertTrue, assertFalse, dentre outras.) possuem uma string template com uma mensagem que, caso a assertiva falhe, explica o porquê da falha do teste. Todas as mensagens estão em inglês somente por uma questão de implementação. E ainda, algumas dessas mensagens possuem a tag <not>, ela significa que de acordo com as informações do diagrama de classes, essas tags devem ou não ser substituídas pelo termo “not”. Por exemplo, se a verificação for realizada para saber se uma entidade não deve ser abstrata, então o tag <not> deve ser substituído. Caso contrário, ele não deve ser substituído por nada.

Os templates que serão mostrados estão divididos para ressaltar cada característica verificada.

Classe

Inicialmente, ilustraremos a nossa técnica de criação de testes de design baseados em templates, mostrando como ela é usada para a verificação do artefato classe. O template para classe verifica as características de classe: nome, visibilidade, superClasse, escopo e interfaces realizadas. O template está organizado da seguinte forma:

· Assinatura do teste. A Listagem 1 exibe o trecho do método de teste que cria a assinatura do teste de design, identificando que se trata de um teste de design para a classe a qual o template está sendo aplicado.

Listagem 1. Trecho do Template do Teste de Design para Classe referente a assinatura do método de teste.


  1 public void testClass <dif><NomeDaClasse> ()
  2   throws IOException, InexistentEntityException {
  3 ...

· Existência da Classe. A Listagem 2 exibe o método de teste que substitui o tag <NomeDaClasse> pelo nome completo da classe. A verificação da existência da classe testada se dá com a invocação do método getClass da biblioteca DesignWizard. Esse método retorna uma representação da classe (um ClassNode) presente no código-fonte que possui o mesmo nome passado por parâmetro. Se não existir nenhuma classe com esse nome no código, a exceção InexistentEntityException será lançada, informando que a classe com o nome indicado não existe.

Listagem 2. Trecho do Template do Teste de Design para Classe referente a verificação da existência da classe.


  1 ...
  2   ClassNode aClass = dw.getClass("<NomeDaClasse>");
  3 ... 

· Classe Abstrata. Se a classe no diagrama de classe for abstrata, a Listagem 3 substitui a tag <TrueFalse> pelo termo “True”, caso contrário, deve substituir por “False”. Na mensagem explicativa a tag <NomeDaClasse> deve ser substituída pelo nome completo da classe testada;

Listagem 3. Trecho do Template do Teste de Design para Classe referente a verificação se a classe é abstrata.


  1 ...
  2   assert<TrueFalse>("The class <NomeDaClasse> must <not> be"
  3   +" abstract" ,
  4   aClass.isAbstract()) ;
  5 ... 

· Herança de Classe. A Listagem 4 exibe o trecho do método de teste que verifica se a classe testada deve herdar de outra classe do diagrama. Caso, no diagrama de classe, a classe testada não herde diretamente de nenhuma outra, essas linhas devem suprimidas do teste de design a ser criado. É fato que a UML permite herança múltipla entre classes. Contudo, consideramos que todos os diagramas de classe serão modelados de forma que somente existirão heranças simples. Isso se deve ao fato de somente consideramos que diagramas de classe modelam aplicações em Java, que não permite herança múltipla. As linhas 3-4 possuem uma string template para a formação de uma mensagem explicativa seguindo o padrão da mensagem do item anterior;

Listagem 4. Trecho do Template do Teste de Design para Classe referente a verificação da hierarquia de classes.


  1 ...
  2 ClassNode superClass = dw.getClass("<NomeDaSuperClasse>" );
  3 assertEquals("The class <NomeDaClasse> must extend the class "
  4 +"<NomeDaSuperClasse>", superClass,
  5 aClass.getSuperClass());
  6 ... 

· Visibilidade da Classe. A Listagem 5 exibe o trecho do método de teste que verifica se a classe no diagrama de classe possui a mesma visibilidade da classe mapeada no código. A linha 2 captura todos os modificadores da classe no código através do método getModifiers do DesignWizard. A linha 8 contem uma mensagem explicativa, formada da mesma forma que as dos itens anteriores. E as linhas 3-5 verificam se, dentre esses modificadores, está contido o modificador mapeado para a visibilidade da classe no diagrama;

Listagem 5. Trecho do Template do Teste de Design para Classe referente a verificação da visibilidade da classe.


  1 ...
  2 Collection<Modifier> modifs = aClass.getModifiers();
  3 assertTrue("The visibility of class <NomeDaClasse> must be"
  4 +" <visibility>",
  5 modifs.contains(Modifier.<visibility>));
  6 ... 

· Realização de Interfaces. Na Listagem 6, as linhas 2-3 instanciam um array de strings com os nomes completos de todas as interfaces que essa classe deve realizar, de acordo com o diagrama de classe. As linhas 4-11 executam um for que varre esse array de strings. No corpo desse for são realizadas as ações para a verificação: a linha 5 captura uma representação da interface no código (caso essa interface não exista, uma exceção será lançada); as linhas 6-7 capturam todas as interfaces que a classe testada realiza através do método getImplementedInterfaces da biblioteca DesignWizard. Por fim, as linhas 8-10 verificam se a interface capturada pela atual iteração do for está presente dentre as interfaces realizadas pela classe extraída do código. Caso não esteja presente, uma mensagem indicando o erro é criada.

Listagem 6. Trecho do Template do Teste de Design para Classe referente a verificação da realização de interfaces.


  1 ...
  2 String[] superInterfaces =
  3 {"<NomeDaInterface1\>", "<NomeDaInterface2>" , ...};
  4 for (String superInterface : superInterfaces) {
  5   ClassNode classnodeInterface =  dw.getClass(superInterface) ;
  6   Set<ClassNode> interfacesExtend =
  7     aClass.getImplementedInterfaces();
  8   assertTrue("The class <NomeDaClasse> must realize the"
  9     + " interface " + superInterface,
  10  interfacesExtend.contains(classnodeInterface));
  11 } ... 

Quer ler esse conteúdo completo? Tenha acesso completo