UNIVERSIDADE FEDERAL DO RIO GRANDE DO NORTE CENTRO DE CIÊNCIAS EXATAS E DA TERRA
DEPARTAMENTO DE INFORMÁTICA E MATEMÁTICA APLICADA PROGRAMA DE PÓS-GRADUAÇÃO EM SISTEMAS E COMPUTAÇÃO
HEITOR MARIANO DE AQUINO CÂMARA
UMA ABORDAGEM SISTEMÁTICA PARA IMPLEMENTAÇÃO, GERENCIAMENTO E CUSTOMIZAÇÃO DE TESTES DE LINHAS DE PRODUTO
DE SOFTWARE
NATAL 2011
HEITOR MARIANO DE AQUINO CÂMARA
UMA ABORDAGEM SISTEMÁTICA PARA IMPLEMENTAÇÃO, GERENCIAMENTO E CUSTOMIZAÇÃO DE TESTES DE LINHAS DE PRODUTO
DE SOFTWARE
Dissertação apresentada ao Programa de Pós-Graduação em Sistemas e Computação do Departamento de Informática e Matemática Aplicada da Universidade Federal do Rio Grande do Norte como requisito parcial para a obtenção do grau de Mestre em Sistemas e Computação.
Prof. Dr. Uirá Kulesza
Orientador
Profª. Drª. Roberta de Souza Coelho Co-orientadora
NATAL 2011
Seção de Informação e Referência
Catalogação da Publicação na Fonte. UFRN / Biblioteca Central Zila Mamede
Câmara, Heitor Mariano de Aquino.
Uma abordagem sistemática para implementação, gerenciamento e customização de testes de linhas de produto de software. / Heitor Mariano de Aquino Câmara. – Natal, RN, 2011.
128f. ; il. Orientador: Uirá Kulesza. Co-orientador: Roberta de Souza Coelho. Dissertação (Mestrado) – Universidade Federal do Rio Grande do Norte.
Centro de Ciências Exatas e da Terra. Programa de Pós-Graduação em Sistemas e Computação.
1. Testes de software. – Dissertação. 2. Linhas de produtos de software. – Dissertação. 3. Testes de linhas de produto de software. – Dissertação 4. Engenharia de software automatizada. – Dissertação. I. Kulesza, Uirá. II. Coelho, Roberta de Souza III. Universidade Federal do Rio Grande do Norte. IV. Título.
RN/UF/BCZM CDU 004.415.53
AGRADECIMENTOS
A Deus, por sempre me abençoar e concedido pelo seu infinito amor,
misericórdia e graça a conclusão deste trabalho.
Aos meus pais, por todo amor, paciência, compreensão e apoio dedicados.
Aos meus irmãos, pelo incentivo constante.
A minha namorada, pelas palavras de confiança, conselhos, orações e por se
fazer sempre presente mesmo nos momentos que não era possível estarmos juntos.
Ao meu orientador, por acreditar em mim e no desenvolvimento deste
trabalho, assim como pela dedicação, ajuda constante e todo conhecimento
adquirido.
Aos professores da UFRN que conheci durante o mestrado, pelas
contribuições ao meu aprendizado.
Resumo
Com o uso da abordagem de linhas de produto de software (LPSs), vários benefícios
são alcançados quando comparados aos processos de desenvolvimento
convencionais que se baseiam na criação de um único sistema por vez. O processo
de desenvolvimento de uma LPS se diferencia da construção tradicional de software,
uma vez que apresenta duas etapas essenciais: a engenharia de domínio - quando
elementos comuns e variáveis da LPS são definidos e implementados; e a
engenharia de aplicação – quando uma ou mais aplicações (produtos específicos)
são derivadas a partir do reuso dos artefatos criados na engenharia de domínio.
Durante a elaboração da LPS, assim como no desenvolvimento convencional de
sistemas, a atividade de teste é fundamental e tem como objetivo a detecção de
defeitos nos artefatos produzidos. Contudo, as características de uma LPS trazem
novos desafios a essa atividade e que precisam ser considerados. Diversas
abordagens foram propostas para o processo de teste de linhas de produto, mas
elas se mostram limitadas ou fornecem diretrizes muito gerais. Outro fator
preocupante é a escassez de ferramentas que auxiliem na implementação, aplicação
e acompanhamento dos testes, bem como na gerência e customização de tais
artefatos. Com base nesse contexto relacionado ao processo de teste de LPSs, esta
dissertação tem como objetivo propor uma abordagem sistemática para o teste de
linhas de produto de software. A abordagem oferece: (i) estratégias de testes
automatizados para LPSs tanto na engenharia de domínio quanto de aplicação; (ii)
diretrizes para a implementação e reuso de casos de teste automatizados nos níveis
de unidade, integração e sistema tanto para a engenharia de domínio quanto de
aplicação; e (iii) suporte ferramental para gerência e customização automática de
casos de teste usando técnicas de derivação automática de software. A abordagem
é avaliada através da sua aplicação em uma linha de produto para sistemas web. Os
resultados deste trabalho mostram que a abordagem proposta pode ajudar os
desenvolvedores a lidar com os desafios impostos pelas características das LPSs
durante o processo de testes.
Palavras-chave: Linhas de Produtos de Software; Testes de Software; Testes de
Linhas de Produto de Software; Engenharia de Software Automatizada.
Abstract
Through the adoption of the software product line (SPL) approach, several benefits
are achieved when compared to the conventional development processes that are
based on creating a single software system at a time. The process of developing a
SPL differs from traditional software construction, since it has two essential phases:
the domain engineering - when common and variables elements of the SPL are
defined and implemented; and the application engineering - when one or more
applications (specific products) are derived from the reuse of artifacts created in the
domain engineering. The test activity is also fundamental and aims to detect defects
in the artifacts produced in SPL development. However, the characteristics of an SPL
bring new challenges to this activity that must be considered. Several approaches
have been recently proposed for the testing process of product lines, but they have
been shown limited and have only provided general guidelines. In addition, there is
also a lack of tools to support the variability management and customization of
automated case tests for SPLs. In this context, this dissertation has the goal of
proposing a systematic approach to software product line testing. The approach
offers: (i) automated SPL test strategies to be applied in the domain and application
engineering, (ii) explicit guidelines to support the implementation and reuse of
automated test cases at the unit, integration and system levels in domain and
application engineering; and (iii) tooling support for automating the variability
management and customization of test cases. The approach is evaluated through its
application in a software product line for web systems. The results of this work have
shown that the proposed approach can help the developers to deal with the
challenges imposed by the characteristics of SPLs during the testing process.
Key Words: Software Product Lines, Software Testing, Testing of Software Product
Lines, Automated Software Engineering.
Sumário
1 Introdução ......................................................................................................... 13
1.1 Problema ........................................................................................................ 14
1.2 Limitações das Abordagens Atuais ................................................................ 15
1.3 Trabalho Proposto .......................................................................................... 15
1.4 Objetivos ......................................................................................................... 16
1.5 Organização do Texto .................................................................................... 17
2 Fundamentação Teórica .................................................................................. 18
2.1 Linhas de Produto de Software ...................................................................... 18
2.2 Desenvolvimento de Software Orientado a Aspectos ..................................... 22
2.2.1 Programação Orientada a Aspectos ........................................................... 22
2.2.2 Orientação a Aspectos em LPS .................................................................. 23
2.3 Testes de Software ......................................................................................... 24
2.3.1 Abordagens de Teste .................................................................................. 24
2.3.2 Estágios de Teste ....................................................................................... 25
2.3.3 Tipos de Teste de Sistema ......................................................................... 26
2.4 Testes de Linhas de Produto de Software ...................................................... 27
2.5 Ferramentas de Derivação ............................................................................. 29
2.5.1 Gears .......................................................................................................... 29
2.5.2 pure::variants .............................................................................................. 30
2.5.3 Ferramenta GenArch .................................................................................. 31
2.5.3.1 Visão Geral de Funcionamento ................................................................... 32
2.6 Sumário .......................................................................................................... 34
3 Uma Abordagem para Implementação, Gerência e Customização de Testes
de Linhas de Produto de Software ........................................................................ 36
3.1 Visão Geral da Abordagem ............................................................................ 36
3.1.1 Escolher Estratégias de Teste para a LPS ................................................. 39
3.1.2 Diretrizes para Implementação dos Testes ................................................. 43
3.1.2.1 Testes de Unidade do Núcleo ..................................................................... 43
3.1.2.2 Testes de Integração do Núcleo ................................................................. 46
3.1.2.3 Testes de Sistema do Núcleo ..................................................................... 47
3.1.2.4 Testes de Unidade e Integração de Produtos ............................................. 50
3.1.2.5 Testes de Sistema de Produtos .................................................................. 50
3.1.3 Gerência Automática de Variabilidades em Artefatos de Teste .................. 51
3.1.3.1 Anotar Artefatos de Teste ........................................................................... 51
3.1.3.2 Configurar Templates de Teste ................................................................... 52
3.1.3.3 Gerenciamento e Derivação Automática de Testes .................................... 53
3.2 Sumário .......................................................................................................... 54
4 Ferramenta para Derivação de Casos de Teste de LPS................................ 55
4.1 Adaptações na Ferramenta GenArch ............................................................. 55
4.2 Detalhamento das Adaptações ....................................................................... 55
4.3 Projeto Detalhado ........................................................................................... 59
4.4 Algoritmo de Derivação .................................................................................. 61
4.5 Sumário .......................................................................................................... 63
5 Abordagem em Ação ....................................................................................... 64
5.1 Estudo de Caso: LPS E-Commerce ............................................................... 64
5.1.1 Características Comuns e Variáveis ........................................................... 65
5.1.2 Arquitetura da LPS ...................................................................................... 66
5.1.3 Implementação de Variações ...................................................................... 67
5.2 Aplicação da abordagem de teste na LPS E-Commerce................................ 73
5.2.1 Passo 1: Escolha de Estratégias de Teste para a LPS ............................... 74
5.2.2 Passo 2: Implementação dos Testes .......................................................... 74
5.2.2.1 Testes de Unidade do Núcleo ..................................................................... 75
5.2.2.2 Testes de Unidade do Núcleo com Mock Objects ....................................... 80
5.2.2.3 Teste de Integração do Núcleo ................................................................... 85
5.2.2.4 Testes de Sistema do Núcleo ..................................................................... 89
5.2.2.5 Testes de Unidade e Integração de Produtos ............................................. 93
5.2.2.6 Testes de Sistema de Produtos .................................................................. 97
5.2.3 Passo 3: Anotar Artefatos de Teste ............................................................ 98
5.2.4 Passo 4: Geração dos Modelos do GenArch ............................................ 100
5.2.5 Passo 5: Derivação de Produtos da LPS .................................................. 104
5.3 Sumário ........................................................................................................ 111
6 Trabalhos Relacionados ................................................................................ 113
6.1 Abordagem de Teste de LPS Baseada em Riscos ....................................... 113
6.2 Estratégias Genéricas de Teste para LPS .................................................... 114
6.3 Metodologia de Teste de LPS Baseada em Requisitos Expressos como Casos
de Uso ..................................................................................................................... 116
6.4 Processo de Teste para LPS ........................................................................ 117
7 Conclusão e Trabalhos Futuros ................................................................... 119
7.1 Contribuições ................................................................................................ 120
7.2 Trabalhos Futuros ........................................................................................ 121
Referências ............................................................................................................ 123
Lista de Figuras
Figura 1 - Atividades principais de uma linha de produto. Adaptado de (SEI, 2010). 20
Figura 2 - Processo de derivação simplificado de uma LPS. Adaptado de (Krueger,
2006). ........................................................................................................................ 21
Figura 3 - Modelo V para testes de software. ............................................................ 25
Figura 4 - Funcionamento do GenArch. Adaptado de (Cirilo et al. 2007). ................. 33
Figura 5 - Visão geral da abordagem. ....................................................................... 37
Figura 6 - Testes de unidade sem mocks. ................................................................ 44
Figura 7 - Testes de Unidade com mock. .................................................................. 45
Figura 8 - Testes de integração do núcleo. ............................................................... 47
Figura 9 - Uso de Template de teste com código comum. ........................................ 48
Figura 10 - Uso de template de teste com código comum e variável. ....................... 49
Figura 11 - Arquitetura do GenArch. Adaptado de (Cirilo, 2008). .............................. 57
Figura 12 - Meta-modelo do modelo de arquitetura. ................................................. 58
Figura 13 - Meta-modelo do modelo de configuração. .............................................. 59
Figura 14 - Classes principais na geração do modelo de Arquitetura. ...................... 60
Figura 15 - Classes principais na geração do modelo de Configuração. .................. 61
Figura 16 - Modelo de Característica da LPS E-Commerce. .................................... 65
Figura 17 - Arquitetura MVC da LPS. ........................................................................ 66
Figura 18 - Modelo de Configuração do GenArch. .................................................... 69
Figura 19 - dynamicContent.jsp.xpt. .......................................................................... 69
Figura 20 - Fragmento WelcomeMessageFragment. ................................................ 70
Figura 21 - Característica Demographics. ................................................................. 70
Figura 22 - Classe Demografico.java. ....................................................................... 70
Figura 23 - Arquivo DemograficoIdade.aj. ................................................................. 71
Figura 24 - Características de Catalog. ..................................................................... 71
Figura 25 - Característica ContentApproval. ............................................................. 72
Figura 26 - Padrão Strategy na LPS. ........................................................................ 73
Figura 27 - Aspecto AutorizacaoNecessariaAspect. ................................................. 73
Figura 28 - Classes envolvidas nos testes de GenericDAOImpl. .............................. 75
Figura 29 - Classe GenericDAOImplTest. ................................................................. 76
Figura 30 - método setUp() de GenericDAOImplTest. .............................................. 77
Figura 31 - método tearDown() de GenericDAOImplTest. ........................................ 77
Figura 32 - método testFindByPrimaryKey(). ............................................................ 78
Figura 33 - método testFindAll_Class(). .................................................................... 78
Figura 34 - método testFindAllAtivos(). ..................................................................... 78
Figura 35 - método testSave(). .................................................................................. 79
Figura 36 - Classe DaoSuite. .................................................................................... 80
Figura 37 - Classes envolvidas nos testes de ContextProdutoSBean. ...................... 81
Figura 38 - Classe ContextProdutoSBeanTest.......................................................... 81
Figura 39 - setUp() e tearDown() de ContextProdutoBeanTest. ................................ 82
Figura 40 - método testCadastrar(). .......................................................................... 83
Figura 41 - método testAutorizar(). ............................................................................ 84
Figura 42 - método testCancelar(). ............................................................................ 84
Figura 43 - Classe TestSuiteSBeans. ....................................................................... 85
Figura 44 - Classes envolvidas nos testes de ProdutoMBean. ................................. 86
Figura 45 - Classe ProdutoMBeanTest. .................................................................... 87
Figura 46 - setUp() e tearDown() de ProdutoMBeanTest. ......................................... 87
Figura 47 - método testFinalizarCadastroProduto(). ................................................. 88
Figura 48 - Template TesteCadastroTipoProduto.xpt. .............................................. 90
Figura 49 - Template TesteCadastroProduto.xpt. ..................................................... 92
Figura 50 - (a) Template ProdutoMBeanProductTest.java.xpt. ................................. 94
Figura 51 - (b) Template ProdutoMBeanProductTest.java.xpt. ................................. 95
Figura 52 - (c) Template ProdutoMBeanProductTest.java.xpt................................... 96
Figura 53 - Script de teste de sistema para um produto da LPS. .............................. 97
Figura 54 - GenericDAOImplTest anotada. ............................................................... 98
Figura 55 - ContextProdutoSBeanTest anotada. ....................................................... 99
Figura 56 - ProdutoMBeanTest anotada. .................................................................. 99
Figura 57 - Operação Create Models do GenArch. ................................................. 101
Figura 58 - LPS E-Commerce com modelos do GenArch. ...................................... 102
Figura 59 - Modelo de arquitetura e propriedades de classe de teste. .................... 103
Figura 60 - Demonstração de relacionamento entre teste e característica. ............ 104
Figura 61 - Operação Derivate Core Tests da extensão do GenArch. .................... 105
Figura 62 - Assistente de derivação dos testes do núcleo. ..................................... 106
Figura 63 - Testes de unidade em projeto de produto. ............................................ 107
Figura 64 - Script de teste para o Selenium IDE. .................................................... 108
Figura 65 - Operação Derivate Product Tests da extensão do GenArch. ............... 109
Figura 66 - Assistente de derivação dos testes de um produto. .............................. 110
Figura 67 - Testes de integração em projeto de Produto. ....................................... 111
Lista de Tabelas
Tabela 1 – Estratégias concretas de teste para Linhas de Produto. ......................... 40
Tabela 2 - Anotação @Test e seus atributos. ........................................................... 52
Tabela 3 – Características variáveis e formas de tratamento. .................................. 68
13
1 Introdução
Linhas de Produto de Software (LPS) (Clements e Northrop, 2001), (Weiss e
Lai, 1999), (Pohl et al., 2005), (Parnas, 1976) podem ser vistas como famílias de
sistemas relacionados que compartilham um conjunto de características comuns
como também suas especificidades, e que são voltadas para um mercado ou missão
específica. A adoção de técnicas de linhas de produto no processo de
desenvolvimento possibilita a criação de artefatos reutilizáveis como componentes,
arquitetura, especificação de requisitos, casos de teste ou modelos, os quais são
genéricos o suficiente para garantir a criação de sistemas que façam parte da família
definida pela linha de produto. Dentro do contexto de abordagens de
desenvolvimento de LPSs, além das características comuns, são também
identificadas, modeladas e implementadas as características variáveis que podem
existir entre os membros da linha, ou seja, as características que distinguem um
produto do outro. Como conseqüência, uma série de benefícios podem ser obtidos,
tais como: redução no tempo total de desenvolvimento e entrega de aplicações,
maior controle de complexidade e aumento da qualidade dos produtos derivados da
linha de produto.
Assim como pode ser observado no desenvolvimento de sistemas
tradicionais, o uso de técnicas de teste de software numa linha de produto também
apresenta um papel fundamental, uma vez que busca melhorar a qualidade do
software produzido, através da busca de erros e detecção de inconsistências
(Kauppinen, 2003), (Pohl e Metzger, 2006), (Reuys et al., 2006). Com uma
abordagem eficaz de testes pode-se reduzir os esforços, aumentar a qualidade do
produto, alcançar os critérios de satisfação do cliente e diminuir os custos de
manutenção (Juristo e Moreno, 2006).
No contexto de linhas de produto de software (Clements e Northrop, 2001),
(Weiss e Lai, 1999), (Pohl et al., 2005), os testes podem ser aplicados tanto na
engenharia de domínio – etapa na qual os artefatos do núcleo (reusáveis) da
arquitetura de referência da LPS são implementados, bem como na engenharia de
aplicação – etapa na qual os produtos da linha são desenvolvidos através do reuso
de artefatos produzidos durante a engenharia de domínio. Devido às características
peculiares de LPSs, o processo de teste apresenta novos desafios que precisam ser
14
considerados como, por exemplo: (i) a escolha adequada dos artefatos que devem
ser testados na engenharia de domínio e os que precisam ser testados na
engenharia de aplicação; (ii) a definição apropriada das estratégias de teste que
serão utilizadas em cada fase da linha; e (iii) a melhor forma de lidar com as
variabilidades nos artefatos de teste da LPS.
Esta dissertação se insere no contexto de testes de linhas de produto de
software, buscando trazer mais qualidade para os artefatos desenvolvidos para uma
LPS. Ela busca oferecer mais sistemática para a implementação de estratégias de
teste tanto na engenharia de domínio como na de aplicação. As estratégias definem
claramente quais artefatos da linha podem ser testados e como testá-los durante o
processo de teste da LPS.
1.1 Problema
No processo de teste, muitos artefatos podem ser produzidos e requeridos
nas etapas de planejamento, projeto, implementação, monitoramento e execução
dos testes, tais como, cenários de teste, dados de teste e resultados de teste. O
gerenciamento desses artefatos não é uma tarefa simples e se não for realizada de
maneira adequada compromete os testes, deixando-os desatualizados ou mesmo
incompletos e inapropriados (Pressman, 2002), (Sommerville, 2003). No contexto de
testes de linhas de produto de software (Bertolino e Gnesi, 2003), (Kolb, 2003), (Pohl
e Metzger, 2006), (Pohl et al., 2005), (Tevanlinna et al., 2004), (Kolb e Muthig, 2006),
(Kishi e Noda, 2006), recentemente diversas estratégias para implementar testes de
software foram propostas. Tais estratégias apresentam diretrizes gerais para a
realização de testes, tais como, motivar o teste do núcleo da arquitetura da LPS ou
apenas dos produtos da LPS. Além disso, alguns trabalhos também ressaltam que
parte dos testes elaborados durante a engenharia de domínio podem também ser
reusados durante a engenharia de aplicação.
O uso de ferramentas que auxiliem o desenvolvimento, aplicação e
acompanhamento de resultados nos testes de uma linha, como também a gerência e
customização dos artefatos de teste por parte dos engenheiros da LPS se
caracteriza como outra questão de grande importância. Tais ferramentas são
fundamentais para permitir a seleção e configuração correta dos artefatos de teste
automatizados considerando uma dada estratégia. Contudo, ainda é escasso o
15
número de ferramentas que auxiliam em tal atividade, evidenciando a necessidade
de mais trabalhos que explorem concretamente meios de ajudar o processo de teste
de LPSs. No que se refere a ferramentas que ajudem na implementação e derivação
de artefatos de código para produtos de uma LPS, existem, por exemplo, o Gears
(Gears, 2010), pure::variants (pure::variants, 2010) e o GenArch (Cirilo, 2008).
Contudo, essas ferramentas, apesar de serem muito úteis no desenvolvimento de
linhas de produto, tais ferramentas não têm sido exploradas no contexto de suporte
ao gerenciamento e customização de testes.
1.2 Limitações das Abordagens Atuais
Diversos trabalhos de pesquisa têm sido propostos nos últimos anos visando
oferecer mais sistemática ao processo de teste de LPS. (Tevanlinna et al., 2004)
propõem o uso de estratégias genéricas de teste que podem ser aplicadas a
qualquer linha de produto, uma vez que independem do contexto específico de cada
LPS. (Kolb e Muthig, 2006) ressaltam a necessidade de projetar arquiteturas de LPS
visando testabilidade. (Bertolino e Gnesi, 2003) propõem uma metodologia para
ajudar no planejamento e gerência do processo de teste de LPS baseada em
requisitos expressos por casos de uso. (Kolb, 2003) propõe a melhoria das
atividades relacionadas a testes de LPSs com base na identificação e priorização de
riscos. (Kishi e Noda, 2006) apresentam um modelo de verificação que pode ser
usado durante o projeto da linha de produto. Apesar da importância e do avanço
proposto por tais trabalhos de pesquisa, existe uma forte carência na existência de
trabalhos que oferecem diretrizes explícitas e concretas para implementação de
estratégias de teste de LPS, assim como para o reuso, gerência e derivação de
artefatos de teste automatizado produzidos durante a engenharia de domínio ou
aplicação.
1.3 Trabalho Proposto
Este trabalho propõe uma abordagem para implementação, gerência e
derivação de testes automatizados para linhas de produto de software (Mariano et
al., 2011). A abordagem é formada por um conjunto de atividades que contemplam:
(i) estratégias de testes automatizados para LPSs; (ii) diretrizes para implementação
16
dos testes automatizados na engenharia de domínio para os testes do núcleo da
arquitetura e na engenharia de aplicação para testes dos produtos; e (iii) gerência e
derivação automática de variabilidades em artefatos de teste através do uso de uma
extensão de uma ferramenta de derivação de produtos que é usada também para
permitir que testes dos elementos de implementação sejam organizados e
automaticamente derivados, como também reaproveitar os testes aplicados no
núcleo da LPS nos testes dos produtos específicos. É necessário destacar que os
testes da LPS são implementados manualmente e que o processo de derivação
automática se refere a possibilidade de selecionar e customizar pequenos trechos de
tais testes por meio do suporte ferramental adotado no trabalho. No final desse
processo, existe também o código referente aos produtos da linha. Portanto, a
derivação no contexto da abordagem se caracteriza como a carga dos artefatos de
implementação específicos da LPS, assim como das classes e scripts de teste
automatizados que, por sua vez, são implementados previamente.
1.4 Objetivos
A dissertação tem como objetivo principal propor uma abordagem sistemática
para a implementação, gerência e derivação de testes automatizados de linhas de
produto de software. Além disso, o trabalho apresenta os seguintes objetivos
específicos:
Investigar trabalhos na área de teste de linhas de produto de software;
Propor diretrizes concretas para a implementação de estratégias de teste para
LPS tanto na engenharia de domínio quanto na engenharia de aplicação;
Propor mecanismos para a gerência e derivação automática de testes de
software e implementar tais mecanismos em uma ferramenta de derivação de
produtos;
Aplicar e avaliar a abordagem proposta através da sua aplicação para uma
LPS no domínio de sistemas web;
Realizar uma análise comparativa da abordagem proposta com outras
também voltadas para testes de linhas de produto.
17
1.5 Organização do Texto
Além deste capitulo introdutório, a dissertação apresenta mais seis capítulos.
O Capítulo 2 destaca: (i) conceitos da área de linhas de produto de software, os
benefícios da abordagem de LPS e suas respectivas etapas de desenvolvimento; (ii)
desenvolvimento de software orientado a aspectos (DSOA), programação orientada
a aspectos (POA) e o uso de orientação a aspectos no contexto de LPS; (iii)
conceitos básicos sobre testes de software; (iv) testes para linhas de produto de
software; e (v) ferramentas de derivação de LPS. No Capítulo 3 é apresentado a
abordagem de implementação, gerência e derivação de artefatos de teste de uma
LPS. No Capítulo 4 é detalhado as adaptações realizadas na ferramenta GenArch
para auxiliar a abordagem de teste de LPS proposta no trabalho. No Capítulo 5 é
detalhada a arquitetura, as características comuns e variáveis, e mecanismos de
implementação de variabilidades que foram adotados numa LPS de sistemas web no
domínio de Comércio Eletrônico (E-Commerce), assim como é ilustrada a aplicação
da abordagem em tal estudo de caso. No Capítulo 6 são apresentados alguns
trabalhos relacionados a abordagens de teste de LPS. Por fim, no Capítulo 7 são
encontradas as considerações finais, destacando as contribuições e trabalhos
futuros.
18
2 Fundamentação Teórica
Este capítulo apresenta uma visão geral da área de Linhas de Produto de
Software (LPS) que tem demonstrado ser uma estratégia de grande auxílio para
análise e gerência de características comuns e variáveis de famílias de sistemas,
bem como permitir a geração de produtos por meio do reuso de artefatos de
software (Seção 2.1). Em seguida, são também introduzidos conceitos e técnicas de
Desenvolvimento de Software Orientado a Aspectos (Seção 2.2), testes de software
(Seção 2.3) e testes no contexto de linhas de produto (Seção 2.4). Finalmente, o
capítulo é encerrado com a apresentação de ferramentas que lidam com o processo
de derivação de produtos (instâncias de uma LPS), tais como, Gears, pure::variants
e GenArch (Seção 2.5).
2.1 Linhas de Produto de Software
Linhas de Produto de Software (LPS) (Clements e Northrop, 2001), (Weiss e
Lai, 1999), (Pohl et al., 2005), (Parnas, 1976) podem ser vistas como famílias de
sistemas relacionados que compartilham um conjunto de características em comum,
mas também suas especificidades, e que são voltadas para um mercado ou missão
específica.
Com a adoção de linha de produto no processo de desenvolvimento é
possível a criação de artefatos reutilizáveis como componentes, arquitetura,
especificação de requisitos, casos de teste ou modelos, os quais são genéricos o
suficiente para garantir a criação de sistemas que façam parte da família definida
pela linha de produto. Além disso, é importante ressaltar que dentro do contexto de
abordagens de desenvolvimento de LPSs não são apenas identificadas, modeladas
e implementadas as características comuns, mas elas também permitem construir
artefatos ligados a características variáveis que possam existir entre os membros da
linha, ou seja, as características que distinguem um produto do outro.
Uma característica (feature) é uma propriedade ou funcionalidade relevante
de uma linha de produto de software (Czarnecki e Helsen, 2006) e que pode ser
classificada em três tipos: obrigatórias, alternativas e opcionais. As características
obrigatórias são aquelas que estão presentes em todos os produtos da linha. As
19
características alternativas são funcionalidades mutuamente exclusivas, ou seja,
existindo um grupo de características alternativas, apenas uma pode estar presente
no produto final. Por fim, as características opcionais são as funcionalidades que
podem ou não estar presentes num produto gerado a partir da LPS.
A abordagem de linhas de produto de software garante também alcançar
benefícios como (Pohl et al., 2005):
Redução nos custos envolvidos no desenvolvimento, pois existe a criação de
artefatos reutilizáveis, os quais podem ser usados em vários tipos de produtos
da LPS, ou seja, quando um produto necessita de uma funcionalidade e ela já
se encontra implementada por um artefato reusável como um componente,
basta apenas reaproveitá-lo, não precisando criar um novo componente.
Melhoria na qualidade, uma vez que são utilizados artefatos de software que
foram revisados e testados em vários produtos criados anteriormente pela
linha. Existe a preocupação de fazer a liberação desses artefatos para uso em
novos produtos somente quando apresentam um nível de qualidade
adequado, evitando que problemas sejam propagados para futuros produtos
gerados pela LPS;
Redução no tempo de comercialização de um produto de software. No início o
tempo é alto, pois é necessário desenvolver a base de elementos comuns
para a LPS a partir do zero. Contudo, depois que esses artefatos estão
prontos é preciso simplesmente reusá-los para gerar os membros da linha de
produto;
Redução no esforço de manutenção. Uma demonstração disso é vista quando
ocorre a mudança de um artefato núcleo da arquitetura da linha para, por
exemplo, corrigir problemas ou atender melhor os requisitos levantados na
LPS. Essas alterações também são propagadas para os demais produtos que
usam o mesmo artefato, facilitando a manutenção. Além disso, os
procedimentos de teste que inevitavelmente são usados quando mudanças
são aplicadas nos artefatos também podem ser reusados, sendo outra
maneira para diminuir os esforços de manutenção.
Ajuda a lidar com a evolução, pois mudanças realizadas nos artefatos núcleo
durante o desenvolvimento da linha são transferidas para todos os produtos
da família.
20
Melhora o gerenciamento da complexidade. Com uma linha de produto bem
projetada é possível saber com precisão quais artefatos poderão ser reusados
pelos produtos da família, bem como o local exato que esses artefatos podem
ser utilizados.
Com relação ao desenvolvimento de uma linha de produto de software,
normalmente existem três atividades principais (SEI, 2010), (Czarnecki, 1998):
Engenharia de Domínio, Engenharia de Aplicação e Gerenciamento da LPS. A
Figura 1 apresenta uma visão geral dessas atividades.
Figura 1 - Atividades principais de uma linha de produto. Adaptado de (SEI, 2010)
A engenharia de domínio, também conhecida como desenvolvimento da linha
de produto ou desenvolvimento de ativos núcleo (core assets), se caracteriza como
um processo que visa promover o reuso, ou seja, tem como objetivo a criação de
artefatos reusáveis para os produtos da linha como componentes, arquitetura,
linguagens específica de domínio, casos de teste, modelos de projeto e análise,
documentações, etc. Nessa fase, é encontrado o uso de atividades de análise,
projeto (design) e implementação. Na análise de domínio, é realizado o trabalho de
definição do escopo da LPS, bem como a identificação das características
obrigatórias, alternativas e opcionais ligadas aos membros da família. Na de projeto
de domínio, é criada a arquitetura comum para os membros da linha de produto, ou
seja, é desenvolvida uma arquitetura genérica que descreve a LPS e serve de base
para a construção dos produtos específicos da linha. Além disso, na atividade de
21
projeto é definida uma estratégia de como os produtos finais podem ser montados a
partir dos artefatos reusáveis. Por fim, a implementação de domínio, como o próprio
nome sugere, tem a finalidade de implementar os artefatos reusáveis como
componentes, arquitetura e casos de teste.
A engenharia de aplicação, também caracterizada como a fase de
desenvolvimento do produto, tem o foco na construção dos sistemas da família com
o reuso dos artefatos elaborados na engenharia de domínio. Durante a construção
de um produto, também conhecido como derivação (Sybren et al., 2005), o
engenheiro de aplicação é responsável por definir uma configuração base, ou seja,
selecionar as características para um determinado produto tendo como referência os
requisitos que esse produto precisará atender. A Figura 2 ilustra um processo de
derivação simplificado de uma LPS.
Figura 2 - Processo de derivação simplificado de uma LPS. Adaptado de (Krueger, 2006).
Como pode ser observado na Figura 2, no processo de derivação existe a
presença dos ativos núcleo, isto é, os artefatos reusáveis produzidos na LPS; a
definição de configurações que refletem as características que cada produto deverá
apresentar e, por fim, os produtos gerados, os quais são compostos pelos artefatos
que implementam as características especificadas nas configurações.
O gerenciamento da LPS (SEI, 2010) apresenta um papel fundamental para
colaborar no sucesso do desenvolvimento da linha e busca garantir que as
atividades realizadas na LPS estejam de acordo com o planejamento previamente
definido. Nessa fase é encontrada a aplicação de duas atividades: gerenciamento
organizacional e gerenciamento técnico. No gerenciamento organizacional, o
objetivo é garantir que os recursos necessários para o desenvolvimento da LPS
estão sendo produzidos de maneira adequada e na quantidade correta para as
22
unidades organizacionais. As atividades de nível técnico e as iterações durante o
ciclo de elaboração dos artefatos núcleo e dos produtos derivados também são
gerenciadas. No gerenciamento técnico, existe o trabalho de supervisionar o
desenvolvimento das pessoas responsáveis pelos ativos núcleo e dos produtos
específicos. Para isso, são coletadas informações que apontem se as atividades e
processos definidos estão seguindo padrões técnicos apropriados.
2.2 Desenvolvimento de Software Orientado a Aspectos
O Desenvolvimento de Software Orientado a Aspectos (DSOA) (Filman et al.,
2005) (Kiczales, 1997) é uma abordagem de engenharia de software que aplica a
Orientação a Aspectos (OA) ao processo de desenvolvimento de sistemas de
software e oferece mecanismos para a separação clara das funcionalidades básicas,
as quais podem ser tratadas com as abordagens tradicionais não orientadas a
aspectos, dos chamados conceitos ou interesses transversais (crosscutting
concerns). Os conceitos transversais se caracterizam por estarem espalhados e
entrelaçados no código da aplicação e que são difíceis de serem modularizados com
o uso de técnicas normalmente empregadas no desenvolvimento de software (tais
como, a orientação a objetos) como, por exemplo, logging, integridade de
transações, autenticação, segurança, desempenho, distribuição, persistência e
profiling.
2.2.1 Programação Orientada a Aspectos
A Programação Orientada a Aspectos (POA) (Kiczales, 1997) tem como
objetivo modularizar os programas através da separação dos conceitos relacionados
na construção dos sistemas de software em dois tipos de abstrações diferentes: os
componentes e os aspectos. Os componentes são elementos que encapsulam os
conceitos que podem ser perfeitamente modularizados em construções comuns de
linguagens de programação como objetos, métodos e procedimentos. Os aspectos,
por sua vez, são as entidades responsáveis por encapsular os conceitos
transversais existentes numa aplicação. Além disso, um conceito essencial no
contexto de POA é o de weaving que se refere ao processo de composição dos
componentes e os aspectos.
23
Existem várias implementações dos conceitos da orientação a aspectos,
assim como diversas terminologias e elementos associados a essa área. No
presente trabalho, é adotada a terminologia empregada pelo AspectJ (Kiczales et al.,
2001), por ser a linguagem que originou a POA e amplamente utilizada em soluções
de software. No conjunto de terminologias dessa linguagem, existe a definição de
aspectos como elementos que encapsulam os conceitos transversais e definem join
points, advices e pointcuts. Os join points especificam os pontos da implementação
do sistema que o aspecto pode atuar como, por exemplo, chamadas de funções,
leitura e escrita de variáveis, tratamento de exceções e entre outros. Os advices são
usados para indicar o comportamento (ação) que será introduzido quando os join
points são atingidos. Em cada advice é possível definir se o comportamento será
executado depois (cláusula after) ou antes (cláusula before) ao momento que o join
point é alcançado, bem como se a ação irá ser executada no lugar do join point
(cláusula around). Por fim, os pointcuts são elementos-chaves que expressam um
conjunto de join points e certas informações do contexto desses join points, como
também são elementos presentes na construção dos advices.
2.2.2 Orientação a Aspectos em LPS
A orientação a aspectos (OA) pode ser aplicada tanto nas fases de
implementação como nas etapas de arquitetura e projeto de um sistema, ou seja,
OA busca apresentar um caminho completo que direcione as atividades de todo o
ciclo de construção de um software. Nessa linha de uso de OA é possível apresentar
os seguintes exemplos: o trabalho de (Araújo et al., 2002) que demonstra a
separação de interesses transversais em nível de requisitos e o trabalho de (Garcia
et al., 2006) que mostra a aplicação das abstrações de aspectos como meio de
capturar decisões arquiteturais e permitir o desenvolvimento de arquiteturas de
software com maior modularidade.
A aplicação de OA não se restringe apenas ao processo de construção de
aplicações convencionais, mas também existem trabalhos elaborados recentemente
(Alves et al., 2005), (Apel e Batory, 2006), (Apel et al., 2006), (Kulesza et al., 2006),
(Lougran et al., 2004), (Mezini et al., 2004) que exploram o uso de técnicas de
orientação a aspectos durante o projeto e implementação de uma LPS. Nesses
trabalhos o conceito de aspecto é usado para prover uma melhor modularização de
24
características transversais identificadas no domínio de uma linha de produto. Dessa
forma, os aspectos servem para melhorar a separação e composição de
características opcionais e de integração de uma arquitetura de LPS. Como
resultado, os aspectos podem ser empregados para acoplar ou desacoplar essas
características da arquitetura de referência da LPS, simplificando o desenvolvimento
arquitetural da linha. Em outras palavras, a aplicação de aspectos em LPS pode ser
empregada para modularizar as características transversais, bem como permitir a
separação de um novo conjunto dessas características sem a necessidade de um
projeto inicial extenso, garantindo que a linha de produto seja desenvolvida de forma
incremental e a partir de ciclos iterativos, visando promover flexibilidade e
adaptabilidade dos seus produtos.
2.3 Testes de Software
No ano de 1972, Dijkstra afirmou que “os testes de programas podem ser
usados para mostrar a presença de falhas, mas nunca a sua ausência“ (Dijkstra,
1972). Dessa forma, fica claro que os testadores precisam ter em mente o
desenvolvimento de testes que evidenciem problemas associados à implementação
de um software. Além disso, com uma abordagem eficaz de teste pode-se reduzir os
esforços, aumentar a qualidade do sistema, alcançar os critérios de satisfação do
cliente e diminuição dos custos de manutenção (Juristo e Moreno, 2006).
Normalmente os testes são usados de duas formas para se alcançar os seus
benefícios (Beizer, 1990). Na primeira os testes são empregados para ajudar a
equipe de desenvolvimento a encontrar inconsistências nas aplicações durante a
fase de construção. Com esses problemas descobertos, medidas reparadoras são
implementadas e aplicadas no software. Na segunda, os testes são usados para
certificar se a aplicação realiza as suas funções de maneira adequada, ou seja, os
testes são uma alternativa para mostrar se o sistema opera de acordo com os
requisitos que deve atender.
2.3.1 Abordagens de Teste
Durante o processo de teste, diferentes estratégias podem ser adotadas de
acordo com os aspectos de qualidade que necessitam ser avaliados. Nesse
25
contexto, existem duas abordagens de teste principais: caixa preta e caixa branca.
Na primeira o sistema sob teste é visto como uma caixa preta. Os testes são
construídos desconsiderando o comportamento interno e estrutura da aplicação. O
objetivo dos testes está centrado em encontrar problemas relacionados ao
comportamento definido nas especificações do programa. Para isso, são
empregados dados de entrada e comparações entre os resultados alcançados nos
testes e os resultados esperados. Na segunda, os testadores precisam conhecer a
estrutura interna do programa, uma vez que são exercitados os caminhos lógicos da
aplicação (Myers, 2004).
2.3.2 Estágios de Teste
Os testes de uma aplicação precisam de um planejamento cuidadoso e de um
processo que determine com precisão as atividades necessárias para o
desenvolvimento adequado dos testes (McGregor, 2001a). Tradicionalmente os
testes de software são guiados através do modelo V de testes (Fewster e Graham,
1999), o qual é apresentado na Figura 3 a seguir.
Figura 3 - Modelo V para testes de software.
No modelo V da Figura 3 é visto no lado esquerdo a ordem de escrita dos
testes, ou seja, são pensados, projetados e construídos os testes dos artefatos
encontrados em cada fase de desenvolvimento da aplicação. No lado direito, por sua
vez, é visto a ordem de execução dos testes. Nessa fase existe o objetivo de
exercitar a aplicação através de testes de unidade, integração, sistema e aceitação.
26
Nos testes de unidade é visto se componentes individuas como classes e métodos
funcionam adequadamente. Nos testes de integração, os módulos do software são
reunidos e testados em grupo. Com o uso desses testes é possível encontrar
problemas ligados as interfaces dos módulos da aplicação. Nos de sistema é
avaliado o comportamento do software num ambiente semelhante ao de uso real,
verificando se a aplicação atende as características funcionais definidas na sua
especificação. Por fim, no teste de aceitação o sistema é analisado pelos usuários
finais, buscando saber se o software atende de maneira apropriada aos requisitos
apresentados por eles. A abordagem de teste de LPS proposta nesta dissertação
focaliza os estágios de teste de unidade, integração e sistema, conforme será
detalhado no Capítulo 3.
2.3.3 Tipos de Teste de Sistema
Como observado na Seção 2.3.2 anterior, os testes de sistema visam analisar
se o comportamento da aplicação está de acordo com as suas especificações. Além
desses testes com propósitos gerais, existem tipos de teste de sistema, os quais
apresentam objetivos específicos para verificar e validar as características de um
programa de software. No grupo dos tipos de teste, são destacados no presente
documento os testes de função, volume (conhecido também como teste de carga),
stress, usabilidade, segurança, desempenho e recuperação a falhas (Myers, 2004),
(Mcgregor e Sykes, 2001). A descrição dos tipos de teste é encontrada a seguir:
Testes funcionais (ou de função): usado para saber se as funções gerais
(regras de negócio) da aplicação seguem o comportamento esperado.
Durantes os testes, condições validadas e inválidas são empregadas para
obter os resultados. Esta dissertação de mestrado foca exclusivamente nos
testes funcionais por questão de escopo.
Teste de volume: nesse tipo de teste é analisado como a aplicação consegue
lidar com grandes quantidades de dados.
Teste de stress: o programa é submetido a condições anormais de utilização.
Nesses testes, podem ser levados em consideração simulações em que o
software é submetido a trabalhos extremos, a memória disponível do sistema
é insuficiente ou situações nas quais o hardware e os serviços são
inacessíveis.
27
Teste de usabilidade: os testes visam avaliar fatores como formas de
navegação, o nível de facilidade de uso e aprendizado da aplicação,
elementos de interface disponíveis e aderência a padrões de usabilidade.
Teste de segurança: tipo de teste que busca saber se os mecanismos de
acesso ao sistema e aos seus dados estão funcionando adequadamente.
Teste de desempenho: são verificados os critérios de desempenho e
eficiência do programa, tais como, tempo de resposta das operações e taxas
de transferência em determinadas condições de carga de trabalho e
configurações.
Teste de recuperação a falhas: os testes buscam saber a eficiência dos
procedimentos de recuperação em casos de falha. Esses casos podem se
manifestar quando existem, por exemplo, erros de programação, falhas de
hardware e problemas nos dados.
2.4 Testes de Linhas de Produto de Software
Assim como pode ser observado no desenvolvimento de sistemas
tradicionais, os testes de linhas de produto de software apresentam o objetivo de
detectar defeitos nos artefatos produzidos (Pohl e Metzger, 2006). Além disso,
técnicas e métodos de teste convencionais se mostram como alternativas válidas
para ajudar no processo de teste de LPS (Tevanlinna et al., 2004). Contudo, devido
às características peculiares inerentes a uma LPS, os testes de linhas de produto
apresentam diferenças, como também problemas e desafios específicos para serem
tratados.
Os testes de linhas de produto se manifestam tanto na engenharia de domínio
como na engenharia de aplicação (Pohl et al., 2005). Na engenharia de domínio não
existem, em geral, aplicações prontas para serem executadas. Dessa forma, os
testes são voltados basicamente para componentes individuais e pedaços da
arquitetura formada por elementos comuns. Por outro lado, também é possível
analisar como testar módulos da arquitetura que possuem variações. Para alcançar
esse objetivo, pode ser usada uma estratégia na qual é construída uma aplicação
exemplo e com base nela predefinir artefatos de teste que seriam usados durante os
testes da fase de aplicação. Além de testar os artefatos produzidos na engenharia
28
de domínio, nessa fase também ocorre o desenvolvimento de artefatos de teste
reusáveis como projetos de teste e dados de teste. Na engenharia de aplicação, por
sua vez, são realizados testes adicionais visando encontrar problemas em
configurações e garantir que as variações especificadas para um produto estão
realmente presentes. Nessa fase também é empregado os artefatos de teste
reusáveis que foram desenvolvidos na engenharia de domínio, reduzindo os
esforços nos testes das aplicações que serão derivadas. Contudo, devido à
presença de variabilidades e de arranjos específicos dessas variabilidades num
produto, a forma como os testes podem ser reaproveitados se caracteriza como uma
tarefa não trivial, pois para cada membro da LPS gerado, precisa existir a seleção de
artefatos de testes específicos para serem aplicados (Pohl e Metzger, 2006). Por fim,
os critérios de cobertura dos testes devem considerar tanto o reuso de elementos
comuns e variáveis como as partes específicas de produtos recém criadas.
Um quesito importante considerado no processo de teste de LPS é a gerência
de artefatos de teste. Para facilitar os testes é interessante, por exemplo, que as
diferenças entre os artefatos de teste para o núcleo de elementos e dos artefatos de
teste para os produtos derivados sejam conhecidas. A rastreabilidade também é
necessária e pode ajudar na seleção adequada de artefatos de teste no processo de
teste. Ainda com relação à gerência dos testes de uma LPS, repositórios de
artefatos de teste são empregados em muitos casos. Eles podem ser usados de
maneira que os artefatos de teste fiquem separados do código fonte das aplicações
ou de forma que os testes estejam integrados (McGregor, 2001b). Esse último caso
pode ser exemplificado quando extensões javadoc são usadas para integrar casos
de teste com resultados esperados no código Java de aplicações (Hoffman e Wilkin,
2002). Por fim, existe também a preocupação de usar ferramentas que possam
ajudar no processo de teste de uma LPS. Por exemplo, ferramentas que consigam
gerenciar artefatos de teste reusáveis e facilitem a execução e análise de resultados
de teste, como também integrem recursos como repositórios de artefatos de teste
com o ambiente de teste adotado na linha. No entanto, a quantidade de ferramentas
que suportem adequadamente o teste de linhas de produto é escassa (Tevanlinna et
al., 2004).
29
2.5 Ferramentas de Derivação
No processo de derivação (Sybren et al., 2005) é recomendado a aplicação
de ferramentas que promovam a seleção, agregação e configuração de artefatos
que compõem uma linha de produto. Gears (Gears, 2010) e pure::variants
(pure::variants, 2010) são exemplos de ferramentas que se inserem nesse contexto.
Essas ferramentas se apresentam como alternativas para promover a automatização
da geração de produtos durante a engenharia de aplicação com base em
configurações e artefatos produzidos durante a engenharia de domínio e que
refletem as características associadas a cada membro da LPS. As subseções
seguintes apresentam uma descrição geral das ferramentas mencionadas, bem
como do GenArch (Cirilo, 2008), ferramenta também desenvolvida para auxiliar a
construção de LPSs e derivação de produtos.
2.5.1 Gears
O Gears é uma ferramenta stand-alone formada por três elementos – infra-
estrutura, ambiente de desenvolvimento e configurador – os quais trabalhando em
conjunto permitem a derivação de produtos de uma LPS. A infra-estrutura representa
os arquivos e diretórios que foram adicionados aos artefatos de software (código
fonte, casos de teste, componentes) que tanto implementam a linha de produto
como podem ser reusados pelos membros da LPS. O ambiente de desenvolvimento
garante a elaboração, manutenção e organização dos artefatos que fazem parte da
linha. O configurador é encarregado pela geração dos produtos. O processo de
derivação implementada pela ferramenta é baseada em descrições de alto nível que
apresentam as características configuradas para um determinado produto.
No Gears, cada LPS é formada por um conjunto de artefatos e são
modeladas pelas suas características e pontos de variação. Na atividade de
configuração de um membro da LPS, é necessário que o usuário da ferramenta
atribua valores para os parâmetros existentes em cada característica que irá compor
o produto específico. O Gears permite também que as características que
implementam a linha sejam modularizadas. Além disso, como os módulos
apresentam definições próprias das características que os constituem, é possível a
derivação individualizada deles. A ferramenta usa outros dois conceitos importantes:
30
mixins e matrizes. Com os mixins é obtido o melhor gerenciamento de
características que se espalham em diversos módulos, uma vez que esse tipo de
característica pode ser definida num lugar central e usada pelos módulos que
dependem dela. As matrizes se apresentam como a alternativa que o Gears possui
para garantir a agregação de módulos que fazem parte de uma LPS. Com as
configurações, módulos, mixins e matrizes, o configurador da ferramenta é capaz de
derivar automaticamente os membros da linha de produto.
2.5.2 pure::variants
O pure::variants é uma ferramenta de derivação que usa modelos para
descrever os conceitos, características e abstrações que estão ligados ao domínio
da LPS em construção, elementos de implementação como arquitetura e
componentes e os membros que formam a linha de produto. A ferramenta foi
construída como um plug-in da plataforma Eclipse e apresenta também a
capacidade de prover o gerenciamento das características relacionadas à linha
durante todo o ciclo de desenvolvimento da LPS.
No processo de derivação de produtos suportado pelo pure::variants são
empregados dois tipos de modelos : modelo de características e modelo de família.
O modelo de característica descreve as características identificadas na LPS,
apresentando as propriedades, relacionamentos e restrições dessas características.
O modelo de família representa a estrutura interna dos componentes e a relação de
dependência deles com as características. Tal modelo é estruturado em diversos
níveis. O nível mais alto é constituído por componentes, os quais representam uma
ou mais características funcionais e compreende partes lógicas do software em
produção, tais como, classes, objetos, funções, variáveis. A parte física, por sua vez,
pode ser formada por arquivos já existentes ou que ainda serão desenvolvidos, bem
como por ações que serão aplicadas com base nos mapeamentos definidos entre
características e artefatos que implementam a linha de produto. Com as informações
contidas nos modelos do pure::variants, assim como pela definição de um grupo de
características para compor um produto específico (configuração) a partir do modelo
de características, o processo de geração dos membros da LPS pode ser realizado.
A ferramenta também possui um recurso de análise da corretude das configurações,
bem como busca resolver problemas nessas configurações e relatar os que não
31
puderam ser revertidos. Além disso, o pure::variants fornece uma linguagem
baseada em XML, denominada XMLTrans, para especificar as ações que devem ser
executadas durante a derivação dos produtos da LPS.
2.5.3 Ferramenta GenArch
O GenArch - Generative Architectures (Cirilo, 2008) é uma ferramenta
baseada em modelos que permite a derivação de membros de uma linha de produto
de software e que foi desenvolvida como um plug-in da plataforma Eclipse (Shavor
et al., 2003). Embora outras ferramentas de derivação de produtos como o Gears e o
pure::variants apresentem um conjunto de funcionalidades úteis para auxiliar na
construção e geração automática de linhas de produto de software, elas se mostram,
em geral, como ferramentas difíceis de serem empregadas pela comunidade
tradicional de desenvolvedores que possuem pouca familiaridade com vários dos
novos conceitos relacionados à área de LPS. Com base nesse contexto, o GenArch
foi construído com o objetivo de simplificar o processo de preparação de LPSs, bem
como ajudar na derivação de produtos de uma linha.
A ferramenta GenArch utiliza três modelos para representar os elementos que
compõe uma linha de produto, os quais são: modelo de arquitetura, modelo de
característica e modelo de configuração. O modelo de arquitetura permite a
representação visual das entidades que implementam a LPS como classes,
aspectos, templates ou arquivos de configuração. Com a sua criação é possível
relacionar os elementos de implementação da linha com as entidades do modelo de
característica. O modelo de característica, como o próprio nome insinua, é
empregado para representar as características obrigatórias, alternativas e opcionais
da linha de produto. A ferramenta usa como base o modelo de características
apresentado por (Czarnecki, 1998), o qual permite definir o relacionamento,
restrições, dependência e atributos associados às características identificadas na
LPS. Para implementar esse modelo no GenArch foi adotado o plug-in do Eclipse
chamado Feature Modelling Plugin (FMP) (Antkiewicz e Czarnecki, 2004). Por fim, o
modelo de configuração tem a função de definir o relacionamento entre as
características e os elementos de implementação. Dessa forma, uma vez definida
uma configuração para um produto a partir do modelo de característica, o GenArch
32
poderá automaticamente carregar os elementos de implementação desse produto
durante a derivação.
2.5.3.1 Visão Geral de Funcionamento
A ferramenta GenArch para suportar o processo de derivação de um produto
necessita da definição dos seus modelos base, ou seja, o modelo de arquitetura,
característica e configuração. Os modelos são produzidos através da varredura e
identificação de anotações Java especificas (próprias do GenArch) nos elementos de
implementação existentes no diretório de um projeto Java usado no desenvolvimento
da linha de produto.
A Figura 4 apresenta o funcionamento geral do GenArch. No início é preciso
anotar os elementos de implementação (passo 1). A ferramenta suporta dois tipos de
anotações: @Feature e @Variability. A primeira é para determinar a relação entre os
elementos de implementação com as características da LPS. Essa anotação
também permite especificar o nome da característica, o tipo (obrigatória, opcional ou
alternativa) e seu respectivo pai, caso exista. A segunda é para indicar os pontos de
extensão (hotspot) existentes. Em LPS, os pontos de extensão representam o que
pode variar na implementação de uma linha de produto e estão ligados a outro
conceito conhecido como variante (Pohl et al., 2005), (Pohl e Metzger, 2006). Esse
termo, por sua vez, especifica uma variação concreta que estará presente num
produto depois da derivação. Por exemplo, pode existir na linha um ponto de
extensão denominado “cor do carro” e atrelado a esse conceito as variantes de
nome “vermelho”, “azul” e “verde”.
33
Figura 4 - Funcionamento do GenArch. Adaptado de (Cirilo et al. 2007).
Em seguida, o módulo de importação do GenArch (passo 2) realiza uma
varredura nos elementos de implementação e recupera as anotações do tipo
@Feature para gerar a versão inicial do modelo de arquitetura, característica e
configuração, bem como identifica as anotações do tipo @Variability para criar os
templates, os quais são implementados através da linguagem XPand do plug-in
openArchitectureWare (oAW) que fornece uma completa infra-estrutura para o
desenvolvimento orientado a modelos (openArchitectureWare, 2010). Os templates
no Genarch são usados tanto para especificar o código que será usado por todos os
membros da LPS como código variável customizado de acordo com informações
obtidas do modelo de características ou pelo uso de elementos conhecidos como
fragmentos que encapsulam trechos de código ou texto, os quais são associados a
características da LPS e gerenciados por meio do modelo de configuração. Em
outras palavras, os templates auxiliam a determinar o conteúdo fixo e gerenciar a
inclusão ou não de código variável de elementos de implementação com base nas
34
características encontradas na configuração de dado produto da LPS criado após o
processo de derivação.
Depois da criação preliminar dos modelos, eles precisam ser melhorados
através de refinamentos e incrementos (passo 3). Nesse momento, existem
trabalhos que visam, por exemplo, incluir novas características no modelo de
característica, adição ou reestruturação dos elementos do modelo de arquitetura,
novas relações entre os elementos de implementação e as características no modelo
de configuração ou incremento dos templates com código que representem novas
possibilidades de variações concretas para um produto. Depois a ferramenta
GenArch através do módulo de derivação (passo 4) permite a geração dos produtos
da LPS. Para criar cada membro da linha, é preciso inicialmente definir uma
configuração com base no modelo de característica, ou seja, selecionar um conjunto
de característica que irá compor um produto específico. Com a configuração do
modelo de característica e com os modelos de arquitetura e configuração, o
GenArch é capaz de derivar os produtos. Por fim, para armazenar a implementação
referente a cada produto é necessário apenas a construção de projetos Java na
plataforma Eclipse (passo 5).
2.6 Sumário
Neste capítulo foi destacada a abordagem de linhas de produto de software
(LPS). Essa abordagem se diferencia do processo de desenvolvimento tradicional de
software, baseado na construção de um único sistema por vez. Ela apresenta duas
fases principais: (i) a engenharia de domínio - quando elementos comuns e variáveis
são definidos, modelados e implementados; e (ii) engenharia de aplicação - quando
uma ou mais aplicações são geradas a partir do reuso dos artefatos criados na
engenharia de domínio.
O capítulo também apresentou conceitos do desenvolvimento de software
orientado a aspectos (DSOA), ressaltando a importância dessa abordagem para a
modularização de interesses transversais (crosscutting concerns) de um dado
sistema. A programação orientada a aspectos (POA) e as terminologias de AspectJ
foram detalhadas, assim como evidenciado que a orientação a aspectos pode ser
usada tanto no desenvolvimento de aplicações convencionais como no contexto de
LPS.
35
Outro assunto abordado é o de testes de software, assim como o de
abordagens de teste e estágios de teste (unidade, integração, sistema e aceitação).
O processo de teste em linhas de produto foi também abordado. Os testes neste
contexto se aplicam aos artefatos produzidos na engenharia de domínio e aos
produtos específicos gerados na engenharia de aplicação, ou seja, os testes se
manifestam nas duas fases de uma LPS.
O capítulo foi concluído com a descrição de três ferramentas de
implementação de LPSs e derivação de produtos: Gears, pure::variants e GenArch.
As duas primeiras apresentam recursos úteis, mas por incorporarem vários dos
novos conceitos da área de LPS se tornam, em geral, complexas de serem
aplicadas pela comunidade tradicional de desenvolvedores. Com base nesse
contexto, o GenArch foi concebido para facilitar o processo de criação de uma LPS e
geração de produtos.
36
3 Uma Abordagem para Implementação, Gerência e
Customização de Testes de Linhas de Produto de Software
Este capítulo apresenta uma visão da abordagem proposta nesta dissertação,
destacando: (i) estratégias para implementação de teste para linhas de produto de
software; (ii) diretrizes para a implementação de estratégias de teste e reutilização
de artefatos de teste durante a engenharia de domínio e aplicação; e (iii)
mecanismos para garantir a gerência de variabilidades e customização de artefatos
de teste tanto na engenharia de domínio como na engenharia de aplicação de uma
LPS.
3.1 Visão Geral da Abordagem
A abordagem proposta nesta dissertação tem como objetivo principal oferecer
mais sistematização para o processo de implementação, gerência e customização
de testes automatizados para linhas de produto de software. No que se refere à
implementação, a abordagem oferece diretrizes para a implementação de
estratégias de teste tanto na engenharia de domínio quanto de aplicação. Com base
em tais diretrizes, é possível definir casos de teste automatizados para artefatos de
implementação da LPS. Uma vez implementados casos de teste para o núcleo da
linha e para as suas variabilidades, a abordagem oferece suporte para
automaticamente customizar tais artefatos de teste para contextos específicos, tais
como: (i) configurar o núcleo da LPS com seus respectivos casos de teste; ou (ii)
derivar um produto da LPS com os seus casos de teste específicos.
A Figura 5 apresenta uma visão geral da abordagem que se baseia na
extensão da ferramenta GenArch. A abordagem tem início durante a etapa de
implementação de domínio da engenharia de domínio, com a escolha de estratégias
de teste e implementação dos testes que consiste no desenvolvimento das classes
de teste, assim como a criação e preparação dos templates. Em seguida, as classes
de teste implementadas são anotadas manualmente. Com os testes anotados e os
templates prontos, os modelos da extensão do GenArch podem ser gerados. Com
esses modelos, é possível iniciar o processo de derivação dos produtos, permitindo,
dessa forma, o carregamento tanto do código dos membros da LPS como dos
37
testes. As subseções seguintes detalham cada passo da abordagem de teste de
LPS apresentada na Figura 5.
Figura 5 - Visão geral da abordagem.
A primeira atividade da abordagem de teste para linhas de produto está ligada
a escolha de estratégias de teste para a LPS que considera os artefatos de código
da LPS, documento de requisitos e modelos iniciais do GenArch gerados. As
estratégias servem para guiar os responsáveis pelos testes da linha e são também
uma forma de adquirir uma visão dos objetivos que precisam ser contemplados no
final dos testes, quais artefatos precisam ser testados e como poderão ser testados.
Contudo, na literatura de teste de LPS são vistas apenas estratégias gerais
38
(Bertolino e Gnesi, 2003), (Kolb, 2003), (Pohl e Metzger, 2006), (Pohl et al., 2005),
(Tevanlinna et al., 2004). O presente trabalho tem o intuito de destacar de forma
clara como os testes se manifestam nas fases de uma linha de produto. Para
alcançar essa finalidade são propostas estratégias efetivas de teste, as quais são: (i)
testes de unidade do núcleo, (ii) teste de integração do núcleo, (iii) teste de sistema
do núcleo, (iv) teste de unidade e integração de produtos e (v) teste de sistema de
produtos.
Uma vez definida as estratégias de teste, o passo seguinte é implementar os
testes da linha de produto. Nesse momento, os testes de unidade propostos para o
núcleo são implementados com o apoio de frameworks, tais como, o JUnit. Mock
Objects1 (Freeman et al., 2004), (Mackinnon et al., 2000) são empregados com o
objetivo de simular instâncias de objetos reais da LPS. Para a construção dos Mock
Objects é adotado o framework jMock (Freeman et al., 2004), (jMock, 2010). No
núcleo da LPS, testes de integração também são usados com o objetivo de avaliar a
interação e integração entre objetos do núcleo. Na elaboração de tais testes tanto o
JUnit como os Mock Objects são novamente usados. Para os testes de sistema do
núcleo são implementados templates, os quais servirão para criar scripts de teste de
sistema para uma ferramenta chamada Selenium IDE (Selenium, 2010). Para um
produto derivado, testes de unidade e integração aplicados ao núcleo são reusados,
mas sem a presença de Mock Objects. Para os testes de integração, são usados
templates para tratar a entrada ou não de código de teste para as partes variáveis
dos produtos. Os testes de unidade, por sua vez, também podem ser criados,
visando testar especificamente as classes referentes às variantes da LPS. Além
disso, testes de sistema são empregados nos membros da LPS por meio de scripts
gerados com base nos templates.
Na nossa abordagem, conforme descrito anteriormente, são adotados
frameworks que permitem a automação de casos de teste, bem como a aplicação de
templates para ajudar na definição de casos ou scripts de teste que poderão ser
customizados. Embora esses recursos auxiliem nos testes automatizados da LPS, é
importante ressaltar que a atividade de implementação é realizada de forma manual,
ou seja, requer a codificação de classes de teste e criação do código referente aos
templates.
1 Termo apresentado em maiores detalhes na seção 3.1.2.1.
39
Com os artefatos de teste implementados, o próximo passo é anotar os testes
da LPS. No caso específico da nossa abordagem, é usada a ferramenta GenArch
com tal propósito. A anotação @Feature da ferramenta é usada para relacionar
features a testes e como trabalho futuro usar @Variability para indicar classes e
interfaces que necessitam usar Mock Objects. Além dessas anotações existentes no
GenArch, é proposto o uso de uma nova anotação @Test para a ferramenta. Essa
anotação, por sua vez, indica se o artefato de teste é para o núcleo ou para um
produto derivado, o tipo e o estágio de teste.
Em seguida, quando as classes de teste se encontram implementadas e
devidamente anotadas, assim como os templates prontos, é iniciada a geração de
modelos da extensão do GenArch. Depois dessa geração, além das informações
típicas dos modelos da ferramenta, os artefatos de teste são representados no
modelo de arquitetura e no modelo de configuração. Por fim, é colocada em prática a
derivação dos membros da LPS. Nessa etapa, os modelos são processados e os
produtos, bem como seus testes automatizados são instanciados e customizados
automaticamente. A extensão do GenArch proposta neste trabalho é responsável
pela customização dos scripts e casos de teste automatizados. Essa extensão
também garante a possibilidade de escolha dos testes que serão derivados, ou seja,
definir se serão configurados, por exemplo, apenas os testes de unidade para um
produto ou se também os testes de integração e sistema serão carregados para
esse membro da LPS.
3.1.1 Escolher Estratégias de Teste para a LPS
A atividade de escolha das estratégias de teste para a linha de produto tem
como principal objetivo selecionar estratégias efetivas para a realização dos testes
da linha de produto (passo 1 da Figura 5). Na abordagem proposta, a escolha das
estratégias considera o documento de requisitos da LPS, informações dos modelos
preliminares do GenArch que possam ter sido criados antes do processo de teste e
as implementações (código) da linha de produto, bem como envolve: (i) decisões de
que estratégias gerais serão utilizadas, tais como, teste apenas do núcleo da LPS,
teste apenas dos produtos, ou teste de ambos; assim como (ii) a seleção de que
tipos e estágios (níveis) de teste podem ser aplicados dada uma estratégia de teste
de LPS escolhida. Diversos fatores podem influenciar nessa escolha, tais como: (i) a
40
tecnologia de implementação das variabilidades; (ii) o tipo e domínio do software
envolvido na LPS; (iii) o grau de amadurecimento da equipe com automação de
testes; (iv) os custos para sua implementação, etc. A escolha da estratégia de teste
é essencial, uma vez que determina que casos de teste deverão ser, de fato,
elaborados e possivelmente automatizados para garantir a qualidade da linha de
produto de software.
Nossa abordagem explicita e detalha estratégias concretas de teste de linhas
de produto, ressaltando as vantagens de cada uma delas. O foco principal do
trabalho é nos testes relacionados às funcionalidades da linha de produto, testes
não-funcionais serão alvos de trabalhos futuros. A escolha dos testes do tipo
funcional foi, sobretudo, devido a sua importância no contexto de teste de sistemas e
por serem fundamentais na garantia de qualidade do funcionamento de aplicações.
A Tabela 1 apresenta diferentes tipos e estágios de teste que podem ser aplicados
as estratégias gerais de teste escolhidas.
Tabela 1 - Estratégias concretas de teste para Linhas de Produto.
Estratégia Objetivo Consequências
Teste de Unidade do Núcleo Exercitar e avaliar a
funcionalidade implementada
por classes do núcleo da LPS,
de forma a verificar o seu
funcionamento.
Problemas ligados a classes
do núcleo são identificados e
não são transferidos para os
membros da LPS.
Teste de Unidade do Núcleo
com Mocks
Verificar o funcionamento
adequado de classes do
núcleo com outras classes do
núcleo que apresentam um
comportamento complexo ou
são difíceis de serem
inicializados.
As classes do núcleo (difíceis
de serem usadas nos testes),
as quais interagem com
outras classes do núcleo, mas
que representam elementos
que estarão sob teste, podem
ser simuladas por Mock
Objects. Dessa forma, as
classes do núcleo podem ser
testadas sem a necessidade
de usar instâncias reais das
outras classes do núcleo que
possam depender.
41
Teste de Integração do
Núcleo
Verificar o funcionamento e
colaboração adequada de
classes do núcleo.
A viabilidade de integração
dos componentes é
comprovada. Componentes
envolvidos nos testes e de
qualidade atestada podem ser
usados para um produto
derivado.
Teste de Sistema do Núcleo Verificar que os componentes
comuns existentes na
arquitetura da LPS estão
funcionando adequadamente.
Casos de testes são aplicados
exclusivamente para artefatos
do núcleo da arquitetura da
LPS, permitindo saber se
classes anteriormente
testadas continuam
funcionando da forma
esperada, bem como podem
verificar o comportamento da
aplicação com os
componentes do núcleo.
Teste de Unidade e
Integração de um Produto
Analisar se unidades como
classes da parte comum e
variável de um produto
funcionam de forma
adequada, como também
saber se a colaboração entre
essas classes também está
de acordo com o esperado.
Componentes do núcleo e
variações são retestados
quando presentes em um
produto derivado. Além disso,
testes são usados para
verificar novamente que a
colaboração entre os
elementos de implementação
está adequada.
Teste de Sistema de um
Produto
Verificar se os componentes
comuns e variáveis de um
produto funcionam
corretamente.
A qualidade do
comportamento funcional do
produto é comprovada.
As estratégias apresentadas na Tabela 1 concretizam duas abordagens
gerais de teste de LPS encontradas na literatura que são: (i) divisão de
responsabilidades (Tevanlinna et al., 2004) que motiva a aplicação de teste tanto na
engenharia de domínio como na engenharia de aplicação; e (ii) reuso de artefatos de
teste (Pohl e Metzger, 2006), (McGregor, 2001b), (Tevanlinna et al., 2004) que
42
destaca a elaboração de testes durante a engenharia de domínio de forma a
promover o reuso de tais artefatos durante a engenharia de aplicação.
A primeira abordagem geral – divisão de responsabilidades – é concretizada
pela definição explícita de estratégias que se manifestam na engenharia de domínio
e aplicação de uma LPS. O trabalho apresenta diretrizes de como testes de unidade,
integração e sistema são aplicados para os artefatos que implementam o núcleo da
LPS como para os diversos produtos (configurações) gerados.
A segunda abordagem geral – reuso de artefatos de teste – por sua vez, é
implementada neste trabalho através da reutilização de testes de unidade e
integração na engenharia de aplicação e que foram definidos para o teste do núcleo
durante a engenharia de domínio, assim como pela definição de templates de
geração de código de teste. Os templates são implementados para os seguintes
cenários: (i) geração de testes de sistema para o núcleo; (ii) geração de testes de
integração para os produtos; e (iii) geração de testes de sistema para os membros
(produtos) da LPS. No primeiro cenário, os templates são implementados ainda na
fase de domínio e possuem código de teste para páginas comuns a todos os
produtos da linha. Em outras palavras, são voltados para páginas mandatórias e que
apresentam código fixo. Os testes para tais páginas (gerados a partir dos templates)
estarão sempre presentes, pois foram projetados para testar páginas que serão
carregadas em todos os membros da LPS. A técnica de template é usada neste
cenário apenas para customizar informações específicas do projeto da LPS ou
mesmo diferentes dados de teste. Dessa forma, a medida que novos produtos são
derivados, os testes podem ser reaproveitados. No segundo cenário de uso dos
templates, o código de teste desses artefatos são criados com base nos testes de
integração do núcleo. Os templates apresentam uma parte comum e outra variável
que é gerada de acordo com a presença de variabilidades para determinado
produto. O código comum é sempre reutilizado e a parte variável é passível de
reuso, uma vez que pode existir um subconjunto entre todos os produtos da LPS
que compartilhem uma mesma variabilidade. Dessa forma, o trecho de teste usado
para testá-la estará presente no arquivo de teste de integração de cada membro do
subconjunto. Por fim, no terceiro cenário, os templates são usados para permitir a
geração de código de teste de sistema que possa exercitar páginas que apresentam
conteúdo fixo e variável que depende da escolha de variabilidade para ser inserido.
Os templates são implementados, de forma que possam testar a parte comum e
43
garantir também que trechos de código de teste para a parte variável também sejam
gerados caso certa variabilidade seja selecionada. Assim como observado no uso
dos templates para teste de integração, o reuso é alcançados devido a existência de
trechos comuns nos casos de testes criados. Os trechos variáveis também podem
ser reaproveitados, pois pode existir um grupo de produtos que apresentam a
mesma variabilidade.
As seções seguintes apresentam as diretrizes para implementar cada
estratégia concreta de teste proposta neste trabalho, permitindo compreender
melhor como tais estratégias implementam as abordagens gerais de teste de LPS
destacadas anteriormente. Além disso, é encontrada a forma como é usada a
ferramenta de derivação GenArch para gerenciar e customizar os artefatos de teste
automatizado elaborados durante a aplicação das estratégias.
3.1.2 Diretrizes para Implementação dos Testes
Está seção apresenta como as estratégias de teste definidas no trabalho se
manifestam nas fases de uma linha de produto, destacando a forma de
implementação dos testes, os artefatos testados e os objetivos que precisam ser
alcançados em cada estratégia (passo 2 da Figura 5). Dessa forma, os responsáveis
pelos testes podem encontrar um direcionamento concreto de como conduzir o
trabalho de teste na engenharia de domínio e aplicação de uma LPS. Além disso, é
importante destacar que as estratégias de teste para LPS se baseiam em
tecnologias disponíveis para a linguagem Java e especificamente para o domínio de
sistemas web. A realização das estratégias e suas diretrizes é detalhada no Capítulo
5, através de exemplos de testes automatizados elaborados para uma LPS do
domínio de aplicações web.
3.1.2.1 Testes de Unidade do Núcleo
Durante a etapa da engenharia de domínio, a abordagem motiva o uso de
testes de unidade sobre o núcleo (core) da linha de produto. Esses testes podem ser
automatizados seguindo técnicas e práticas adotadas no desenvolvimento de
sistemas de software (Myers, 2004). Nesse contexto, para cada classe relevante ou
crítica do núcleo da LPS deve ser elaborada uma classe de teste de unidade. A
44
abordagem também propõe o uso de Mock Objects (Freeman et al., 2004),
(Mackinnon et al., 2000) no contexto de testes de classes do núcleo que dependem
de outras classes também do núcleo. Os Mock Objects ou simplesmente mocks são
usados para simular objetos reais que apresentam um comportamento complexo ou
ainda bastante impreciso, difíceis de serem inicializados por dependerem de
informações de uma base de dados ou por simplesmente ainda não existirem. Além
disso, com o uso de mocks é possível definir expectativas na execução de métodos
e meios para verificar se essas expectativas foram alcançadas.
Na abordagem existem dois diferentes cenários de teste de unidade do
núcleo: (i) teste de unidade sem mocks; (ii) teste de unidade com mocks. No primeiro
caso, os testes usam apenas classes reais do núcleo. No segundo, os mocks são
usados para substituir um grupo de classes do próprio núcleo da LPS. A seguir é
encontrada uma visão geral para cada cenário mencionado.
Figura 6 - Testes de unidade sem mocks.
A Figura 6 ilustra o cenário de teste de unidade sem mocks. Em geral, um
método de teste é implementado para cada cenário relevante do teste de unidade.
Neste cenário não é necessário o uso de mocks, pois as classes que estão sendo
testadas não dependem de outras classes do sistema.
45
Figura 7 - Testes de Unidade com mock.
A Figura 7 apresenta duas classes de teste. A primeira é definida como
Classe Teste Unidade C. Ela foi desenvolvida para testar a Classe C do
núcleo que, por sua vez, apresente uma dependência com uma interface do núcleo
chamada Interface X. Essa interface serve de base para a construção do mock
chamado Mock Interface X. O mock gerado implementa Interface X e pode
ser usado para simular essa interface nos testes. A segunda classe de teste é
Classe Teste Unidade D. Ela foi criada para testar a classe do núcleo Classe
D. Essa classe possui dependência com outra classe do núcleo chamada Classe Y
que, por sua vez, é empregada na criação do mock denominado Mock Classe Y.
Esse mock herda de Classe Y, podendo simular essa classe nos casos de teste da
linha de produto.
Para ajudar na elaboração dos testes de unidade são usados frameworks de
teste de unidade. No caso específico do estudo de caso apresentado nesta
dissertação, é explorado o uso do framework JUnit. O JUnit é usado para testes de
sistemas em Java e comumente usado para a criação de testes unitários. Na
abordagem, o framework pode ser usado para a implementação e execução dos
testes. Além disso, o JUnit oferece suporte para a visualização dos resultados
obtidos nos testes de maneira simples e intuitiva. Para a construção dos mocks, por
46
sua vez, foi adotado o jMock que oferece uma API expressiva e intuitiva, bem como
possibilita o acesso aos métodos de especificação e análise das expectativas nos
testes dos objetos simulados pelos Mock Objects.
3.1.2.2 Testes de Integração do Núcleo
Nos testes da fase de engenharia de domínio, nossa abordagem apresenta
também diretrizes para a implementação de testes de integração para analisar a
colaboração entre classes do núcleo e classes que representam pontos de variação
na arquitetura da LPS. Para a construção de tais testes também foi empregado o
JUnit. Apesar desse framework ser usado em muitos casos especificamente para
testes de unidade, o JUnit pode também ser aplicado em testes de integração de um
software.
Um diferencial incorporado nos testes de integração deste trabalho foi o uso
de Mock Objects, os quais são criados com o jMock. Os mocks são aplicados
normalmente em testes de unidade de um software. Contudo, na abordagem da
dissertação, os mocks serão empregados para simular uma parte do conjunto de
variações envolvidas nos testes. Dessa forma, o código de classes referente ao
núcleo pode ser testado sem que seja preciso usar todos os objetos concretos das
variáveis que elas dependem. A Figura 8 ilustra cenários de testes de integração
para o núcleo de uma LPS: (i) teste de integração de classes do núcleo sem a
presença de variabilidades; (ii) testes de integração de classes do núcleo e de
pontos de variação. No cenário (i), a classe de teste Classe Teste Integracao
A foi construída para testar uma classe do núcleo chamada Classe A que interage
com outras duas classes também do núcleo. O funcionamento e colaboração entre
essas classes são verificados. No cenário (ii) a classe de teste Classe Teste
Integracao B, por sua vez, tem como objetivo testar Classe D que depende de
uma classe do núcleo (Classe F) e uma classe que representa um ponto de
variação (Classe E). Devido à existência desse ponto de variação, é construído o
objeto mock denominado Mock Variação E para ser utilizado nos testes.
47
Figura 8 - Testes de integração do núcleo.
3.1.2.3 Testes de Sistema do Núcleo
Nosso trabalho também propõe o uso de testes funcionais no nível de sistema
para os artefatos do núcleo da LPS. Como na etapa de engenharia de domínio, em
geral, não existem aplicações prontas para serem executadas, nossa proposta é que
nessa etapa os testes do núcleo sejam parcialmente implementados na forma de
templates de geração de código para serem usados futuramente. Com relação à
implementação de tais templates, existem dois cenários possíveis. No primeiro, os
templates são implementados para testar apenas a parte comum a todos os
membros da LPS, ou seja, não possuem código de teste para tratar as variabilidades
definidas para cada produto da linha. No segundo cenário, cada template de
geração de código contempla: (i) uma parte fixa que representa o código do teste
que se mantém o mesmo independente das variabilidades escolhidas para um dado
produto; e (ii) uma parte variável que contempla partes de código a serem geradas
de acordo com as variabilidades escolhidas para determinado produto.
Os templates podem ser usados para gerar código de testes funcionais no
nível de sistema. No caso específico deste trabalho, será ilustrado o uso de
templates para a geração de scripts de testes de sistema para a ferramenta
Selenium IDE (Selenium, 2010). Essa ferramenta se caracteriza por ser uma
48
extensão do navegador Mozila Firefox e permite a aplicação de testes de sistema a
partir da criação de scripts no formato HTML. Tais scripts podem ser gerados
automaticamente quando a aplicação alvo é exercitada. Além de serem executados,
os scripts podem ser editados ou transformados para outros formatos como código
de teste em Java, Groovy, C#, Perl, PHP, Python e Ruby. O recurso de geração
básica dos scripts de teste pode, em certas situações, ser usado para gerar a parte
comum dos testes.
A seguir, é apresentado como os templates de teste são usados na
abordagem proposta neste trabalho. Como destacado, existem dois cenários de
elaboração dos templates. A Figura 9 ilustra o primeiro cenário que se caracteriza
pela implementação de templates para a geração de scripts de teste voltados
apenas para a parte comum das aplicações web de uma LPS.
Figura 9 - Uso de Template de teste com código comum.
Como pode ser observado na Figura 9, um template foi construído com código
de teste comum aos produtos da linha (destacado de azul). Em seguida, após a
derivação, existem scripts para testar páginas JSP ou HTML obrigatórias, as quais
possuem código que não é alterado pela presença de variações, ou seja, é um
artefato que contém somente código comum. Dessa forma, como tais artefatos
49
estarão sempre presentes nos membros da LPS, o script de teste relacionado a eles
pode ser reusado à medida que novos produtos são criados. É interessante destacar
que o uso de templates poderia até ser desconsiderado se não fosse pela
necessidade de alterar no script de teste, para cada produto gerado, um trecho
específico de código que indica o nome do projeto da aplicação web alvo dos testes
de sistema. A maneira para alcançar esse objetivo é destacada de forma prática na
Seção 5.2.2.4 deste documento.
A Figura 10 apresenta o segundo cenário de teste com apoio de templates.
Nesse cenário, os templates são construídos com a parte comum (destacado de
azul) e variável (destacado de vermelho) dos testes. Depois do processo de
derivação, o código comum se mantém para testar o núcleo da linha e os trechos
variáveis são carregados com base nas variabilidades definidas para os produtos da
LPS. Por fim, com os scripts prontos, eles podem ser usados pelo Selenium IDE
para exercitar as páginas das aplicações web.
Figura 10 - Uso de template de teste com código comum e variável.
50
3.1.2.4 Testes de Unidade e Integração de Produtos
Na engenharia de aplicação, os testes de unidade e integração elaborados
para a engenharia de domínio podem ser reexecutados como teste de regressão.
Contudo, nos testes de integração, os objetos mock são retirados para dar lugar às
implementações reais de cada uma das variações que eles representam. Esse
cenário pode requerer a adaptação de classes de teste de integração elaboradas
originalmente apenas para o núcleo. No presente trabalho, é proposto o uso de
templates para permitir as customizações citadas nos testes de integração dos
produtos, ou seja, para garantir o controle da inclusão ou não de classes reais
devido as variações que essas classes implementam fazerem parte ou não de dado
produto. Testes de unidade, por sua vez, também podem ser criados para as classes
que representam variantes concretas dos pontos de variação da LPS. A decisão de
implementar tais classes de teste tem relação com o quanto é crítica a
funcionalidade implementada pelas variantes. A realização de testes que reusam ou
se baseiam nos testes implementados na engenharia de domínio servem como
forma de verificar se os resultados obtidos anteriormente continuam válidos ou
identificar novos defeitos quando um produto da LPS é derivado.
3.1.2.5 Testes de Sistema de Produtos
Com relação aos testes no nível de sistema para os produtos de uma LPS,
nossa proposta é que durante o processo de derivação dos membros da linha,
sejam gerados testes concretos a partir dos templates elaborados durante a
engenharia de domínio, e que são, durante a derivação, customizados de acordo
com as características definidas para o produto da LPS sendo considerado. Dessa
forma, existirão arquivos com conteúdo HTML para a ferramenta Selenium IDE
realizar os testes de sistema.
Na nossa abordagem, em particular, os testes de sistema para os produtos
são voltados para as páginas das aplicações web que apresentam partes comuns e
partes variáveis. Sabendo dessa informação, os templates de teste precisam garantir
a geração de scripts de teste compatíveis para o conteúdo dessas páginas. Por
exemplo, será detalhado um caso de teste de sistema para o cadastro dos produtos
das aplicações da LPS web adotada nesta dissertação. Parte do conteúdo desse
51
cadastro como as informações de garantia ou tamanho do produto são definidos
pela presença de variabilidades num membro da linha. O template de teste desse
cadastro também trata a presença de tais variabilidades, permitindo a geração de
trechos de código de teste específicos para os pontos variáveis das páginas de
cadastro dos produtos.
3.1.3 Gerência Automática de Variabilidades em Artefatos de Teste
Uma vez implementados os artefatos de teste automatizados para uma linha
de produto, nossa abordagem provê suporte para gerenciar e derivar
automaticamente os artefatos de teste considerando o contexto de uma estratégia
de teste, tais como, teste do núcleo da LPS ou teste dos produtos da LPS. Esta
seção descreve os passos da abordagem para garantir tal gerência e derivação
automática de testes.
3.1.3.1 Anotar Artefatos de Teste
Na abordagem proposta, um dos primeiros passos para garantir a gerência
dos testes, é anotar os artefatos de teste (passo 3 da Figura 5) com anotações que
explicitam que tipos e estágios de teste são endereçados por esses artefatos. Isso
permite que, posteriormente, tais anotações sejam lidas e processadas por uma
ferramenta de derivação e que seja assim decidido que artefatos de teste devem ser
carregados para realizar o teste de unidade, integração ou sistema do núcleo ou de
um dos produtos da LPS.
Duas anotações já presentes na ferramenta GenArch são usadas pela nossa
abordagem de teste, são elas: (i) @Feature – que atualmente é usada na ferramenta
para explicitar que artefatos de implementação da arquitetura de uma LPS estão
relacionados a determinadas características, esta anotação será usada na
abordagem para indicar que artefatos de teste estão relacionados a que features; e
(ii) @Variability – esta anotação indica que artefatos de implementação representam
pontos de variação na implementação de uma arquitetura de LPS. Nesta
dissertação, é objeto de trabalhos futuros o uso dessa anotação de forma a indicar
classes ou interfaces que necessitam ter classes Mock Objects criadas.
52
Além de tais anotações, foi criada também uma nova anotação @Test para
indicar a estratégia de teste, isto é, definir se os testes são para o núcleo ou para os
produtos (configurações) da LPS, o estágio (unidade, integração, sistema), e o tipo
(funcional) de teste a ser realizado. A Tabela 2 apresenta a anotação @Test e seus
atributos.
Tabela 2 - Anotação @Test e seus atributos.
@Test
Atributos
Strategy core, product
Stage unit, integration, system
Type functional
A anotação @Test é processada pela ferramenta GenArch para permitir a
caracterização dos artefatos de teste e, posteriormente, a carga de determinados
artefatos de teste de acordo com a estratégia em um dado instante. A funcionalidade
básica do GenArch foi estendida para permitir o suporte à carga de artefatos de teste
relacionados a determinadas estratégias. O Capítulo 4 detalha as adaptações
realizadas na ferramenta GenArch para contemplar tais funcionalidades.
3.1.3.2 Configurar Templates de Teste
Outro aspecto fundamental na nossa abordagem diz respeito à correta
configuração dos templates de teste funcional elaborados para uma dada LPS. Na
abordagem, são adotados templates que lidam ou não com as variabilidades da
linha de produto. Os templates que não precisam considerar as variações existentes
em determinado produto, são aqueles usados nos testes de sistema para as páginas
de aplicações que possuem apenas código comum e fixo (Seção 3.1.2.3). Nesse
cenário, a configuração necessária é a definição do método da extensão do
GenArch, responsável por inserir o nome do projeto do produto no script de teste
criado a partir do template. Com relação aos templates que lidam com variações da
LPS, podem ter a sua parte variável customizada seguindo duas técnicas: (i) código
customizável que utiliza informações (parâmetros) provenientes do modelo de
característica da LPS; e (ii) uso de fragmentos que representam trechos de código
ou texto que estão associados a um determinado feature, o qual uma vez escolhido
53
durante a derivação ocasiona a inclusão do fragmento de texto dentro do template
durante a sua customização. Os templates da nossa abordagem que podem usar
essas duas técnicas de configuração são aqueles construídos para testar páginas
dos produtos que apresentam uma parte fixa e outra variável (Seção 3.1.2.3) ou os
que são direcionados para os testes de integração dos membros derivados de uma
LPS (Seção 3.1.2.4).
Este passo da abordagem envolve a configuração e preparação dos
templates para serem customizados automaticamente durante a derivação de
determinado produto na engenharia de aplicação. Vale ressaltar que a adequada
configuração dos templates não necessariamente implica em geração completa de
código de teste, pois isso depende da complexidade de artefatos de teste a serem
produzidos, assim como do detalhamento da análise do domínio sendo considerado.
3.1.3.3 Gerenciamento e Derivação Automática de Testes
A extensão do GenArch permite a organização dos artefatos de
implementação e teste de uma linha de produto, de forma que é possível gerenciá-
los a partir do uso de anotações. A presença de tais anotações permite que a
ferramenta GenArch possa automaticamente gerar seus modelos de derivação
(passo 4 da Figura 5), para que, posteriormente, possa derivar versões específicas
dos artefatos relacionados aos produtos da LPS de maneira a promover a execução
de diferentes estratégias de teste. Usando a extensão do GenArch é possível,
portanto, derivar automaticamente as classes e interfaces que implementam
determinado membro da LPS, assim como seus respectivos testes (passo 5 da
Figura 5).
A derivação automática dos artefatos de teste foi implementada de forma
idêntica a derivação para os artefatos de implementação, ou seja, artefatos de teste
que foram anotados são automaticamente carregados em um projeto Java
dependendo da estratégia de teste escolhida pelo engenheiro em questão. Além de
permitir a carga das classes de teste de unidade ou integração, a ferramenta pode
também customizar templates relacionados aos testes de sistema escritos em
ferramentas, tais como, o Selenium IDE para aplicações web.
54
3.2 Sumário
Este capítulo apresentou a abordagem de teste para LPSs proposta neste
trabalho. Tal abordagem possui cinco estratégias concretas de teste que são: (i)
testes de unidade do núcleo, (ii) teste de integração do núcleo, (iii) teste de sistema
do núcleo, (iv) teste de unidade e integração de produtos e (v) teste de sistema de
produtos.
O capítulo também descreveu o uso do framework JUnit para auxiliar a
implementação dos testes de unidade e integração do núcleo da LPS na engenharia
de domínio, como também o uso de Mock Objects para simular determinadas
classes em tais testes. Os testes de sistema do núcleo, elaborados também durante
engenharia de domínio, são formados por templates que servem para a criação de
scripts de teste para a ferramenta Selenium IDE. Com relação aos testes dos
produtos derivados, os testes de unidade e integração do núcleo são reaproveitados
ou adaptados. No caso específico dos de integração, são gerados casos de teste a
partir de templates criados na fase de domínio, os quais tratam a entrada ou não de
trechos de código variável quando dada variabilidade está presente ou não num
membro da LPS. Por fim, os testes de sistema dos produtos são constituídos pelos
scripts definidos com base nos templates desenvolvidos na engenharia de domínio.
Por fim, O capítulo destacou o uso de anotações @Feature para relacionar
artefatos de teste com características da LPS, assim como propôs como trabalho
futuro empregar @Variability para especificar as classes e interfaces que precisam
ter Mock Objects criados. Além disso, foi apresentada a nova anotação @Test da
extensão do GenArch para indicar a estratégia, o estágio e o tipo que o teste se
enquadra. Com o processamento de @Test e @Feature nas classes de teste,
representações de tais artefatos são encontradas nos modelos de arquitetura e
configuração da extensão do GenArch. Com os modelos prontos, o processo de
derivação dos produtos e seus respectivos testes pode ser realizado.
55
4 Ferramenta para Derivação de Casos de Teste de LPS
Este capítulo apresenta a extensão proposta para o GenArch, destacando as
mudanças realizadas na ferramenta para permitir a derivação de testes para linhas
de produto de software. Nas seções seguintes é encontrado uma visão geral das
adaptações do GenArch (Seção 4.1), a arquitetura da ferramenta e extensões
realizadas na sua implementação (Seção 4.2), o projeto detalhado das adaptações
(Seção 4.3), e as modificações elaboradas para o algoritmo de derivação do
GenArch (Seção 4.4).
4.1 Adaptações na Ferramenta GenArch
Para permitir o gerenciamento e derivação dos testes de uma LPS foi
necessário a definição da nova anotação @Test para a ferramenta GenArch (Seção
3.1.3.1). Dessa forma, os responsáveis pelos testes conseguem indicar nas classes
de teste: a estratégia adotada, o estágio relacionado ao caso de teste e o tipo de
teste. Para alcançar esse objetivo foi necessário implementar modificações no
sistema de varredura de anotações da ferramenta para permitir a identificação e
processamento das informações presentes na nova anotação. O mecanismo de
derivação de produtos também precisou de adaptações, pois tanto o código da linha
de produto precisa ser carregado como os artefatos de teste específicos para cada
membro da LPS.
Os modelos de arquitetura e configuração do GenArch foram também
alterados. Os dois modelos na versão estendida da ferramenta permitem a
representação dos elementos de teste através do processamento das anotações
@Test. Essas mudanças foram introduzidas com o objetivo de auxiliar o processo de
derivação de produtos e dos testes relacionados, bem como facilitar a análise das
classes de teste e de suas propriedades no nível de modelo pelos responsáveis em
desenvolver a linha de produto de software.
4.2 Detalhamento das Adaptações
Como destacado na Seção 2.5.3 a ferramenta GenArch é um plug-in da
plataforma Eclipse (Shavor et al., 2003). O Eclipse, por sua vez, se caracteriza por
56
prover um ambiente de desenvolvimento de aplicações de software e que
disponibiliza uma plataforma extensível e uma vasta quantidade de recursos que
auxiliam no desenvolvimento de plug-ins. Na plataforma Eclipse é encontrado um
motor de execução responsável por instanciar toda a plataforma. As outras funções
são estruturadas por um grupo de subsistemas implementados por um ou mais plug-
ins. O núcleo da plataforma Eclipse apresenta uma arquitetura que garante de forma
dinâmica a localização, carregamento e execução de plug-ins. Os plug-ins permitem
que novas funções possam ser conectadas (“plugadas”) à plataforma pela realização
de pontos de extensão presentes na mesma. Um plug-in também pode ser estendido
pela exposição de pontos de extensão.
Para a elaboração do GenArch foram usados quatro plug-ins extensíveis da
plataforma Eclipse, os quais foram essenciais para permitir: (i) a definição de
wizards, (ii) a navegação na árvore de diretórios de determinado projeto e
funcionalidades para manipulação de arquivos e diretórios; (iii) a manipulação dos
modelos; e (iv) a geração de código.
A Figura 11 apresenta uma visão geral da arquitetura da ferramenta GenArch.
Para a manipulação de código-fonte Java foi empregado o plug-in Java
Development Toolkit (JDT) (Shavor et al., 2003) e para manipular as
implementações em AspectJ foi adotado o AspectJ Development Toolkit (AJDT)
(Colyer, 2004). Esses plug-ins oferecem um conjunto de ferramentas para o
gerenciamento da área de trabalho, visões, editores, compiladores e manipuladores
de código-fonte. A API de árvore de sintaxe abstrata (ou do inglês Abstract Syntax
Tree - AST) presente nesses plug-ins foi usada na manipulação (escrita, leitura e
remoção) das anotações do GenArch e a recuperação da estrutura de elementos
como classes, interfaces ou aspectos. Como mencionado anteriormente, é através
do processamento das anotações que são criados os modelos da ferramenta
GenArch. Para a extensão do Genarch, a AST gerada pelo JDT pode ser usada para
ajudar a tratar as anotações @Test e recuperar as informações relacionadas à
estratégia, ao estágio e ao tipo dos testes da linha de produto.
57
Figura 11 - Arquitetura do GenArch. Adaptado de (Cirilo, 2008).
Para a implementação da infra-estrutura de manipulação dos modelos
suportados pelo GenArch foi utilizado o Eclipse Modeling Framework (EMF)
(Budinsky et al., 2003). O EMF possui como objetivo principal fornecer recursos para
facilitar a especificação e desenvolvimento de modelos usados como referência para
a construção de aplicativos. Além disso, o EMF é um framework Java que oferece
para a construção de ferramentas dirigidas a modelos: (i) um conjunto de classes
que representam um meta-modelo e que possibilitam acessá-lo em tempo de
execução; (ii) um grupo de classes adaptadoras que permitem que os modelos
sejam visualizados e editados; e (iii) um editor visual básico para os modelos. Todos
esses elementos citados são gerados automaticamente com base na especificação
de um meta-modelo eCore. Esses meta-modelos foram empregados na elaboração
dos modelos de arquitetura e configuração do GenArch.
Na extensão do GenArch foram acrescentados novos elementos nos meta-
modelos do modelo de arquitetura e configuração para permitir, por exemplo, a
manipulação de representações específicas relacionadas às classes de teste. As
Figuras 12 e 13 ilustram os meta-modelos adaptados dos modelos de arquitetura e
configuração.
58
Figura 12 - Meta-modelo do modelo de arquitetura.
A Figura 12 mostra o novo elemento “ArchitectureTestClass” (destacado na
figura) com os atributos referentes à estratégia, ao estágio e ao tipo de teste. Com a
definição desse elemento no meta-modelo é possível a geração das classes de
apoio ao processo de criação dos modelos de arquitetura. Dessa forma, caso sejam
encontradas anotações @Test, os artefatos de teste anotados possuem uma
representação no modelo de arquitetura. Além disso, é possível incluir, editar ou
remover elementos que representam classes de teste no modelo de arquitetura do
GenArch.
A Figura 13 apresenta o meta-modelo do modelo de configuração. Nesse
meta-modelo foi criado um novo elemento denominado “ConfigurationTestClass”
(destacado na figura). Com o meta-modelo adaptado é possível, após o
processamento das anotações @Test e @Feature definidas nos testes, a geração
de modelos de configuração capazes de também representar tais artefatos de teste
e indicar as relações deles com características da LPS.
59
Figura 13 - Meta-modelo do modelo de configuração.
Para o desenvolvimento do modelo de características do GenArch, por sua
vez, foi empregado o Feature Model Plugin (FMP). A infra-estrutura de modelagem
de características do FMP é também implementada com base no EMF. Os templates
suportados pela ferramenta, são implementados através da linguagem XPand do
plug-in openArchitectureWare (oAW) (openArchitectureWare, 2010). Assim como o
FMP, o oAW é baseado no framework EMF.
4.3 Projeto Detalhado
Com as adaptações realizadas nos meta-modelos dos modelos de arquitetura e
configuração, após o processo de geração desses modelos, é possível encontrar
representações específicas para os elementos de teste da linha de produto. Nesta
seção apresentamos uma visão, em nível de classes, das mudanças aplicadas na
criação dos modelos de arquitetura e configuração do GenArch.
60
Figura 14 - Classes principais na geração do modelo de Arquitetura.
A Figura 14 ilustra as classes principais usadas no processo de geração do
modelo de arquitetura do GenArch, bem como métodos relevantes de cada uma.
Quando o usuário da ferramenta inicia a operação de geração dos modelos, a classe
inicialmente usada é CreateModelsAction. Em seguida, no algoritmo dessa
classe, é empregada uma instância da classe CreateModelsOperation que
realiza, entre outras operações, a instanciação das classes responsáveis por
percorrer os arquivos e diretórios do projeto da LPS e, dessa forma, ajudar na
definição do conteúdo dos modelos do GenArch. No caso específico do modelo de
arquitetura, é criada uma instância da classe
ArchitectureModelResourceVisitor. Na extensão da ferramenta, essa classe
depende de JavaAnnotationUtil que apresenta um novo método, denominado
testAnnotations()responsável por recuperar as informações da anotação
@Test (a estratégia, o estágio e o tipo dos testes) definidas para as classes de teste.
Com a existência de classes de teste anotadas,
ArchitectureModelResourceVisitor usa o método addTestClass()de
ArchitectureModelContent para permitir a inclusão de classes de teste no
modelo de arquitetura. Esse método não faz parte da implementação original do
GenArch, existindo apenas na extensão da ferramenta apresentada neste trabalho.
A Figura 15 apresenta as classes principais para a geração do modelo de
configuração do GenArch. Quando é solicitada a criação do modelo, a classe
CreateModelsAction é chamada inicialmente. Em seguida,
CreateModelsAction emprega um objeto da classe CreateModelsOperation
que usa ConfigurationModelResourceVisitor para realizar a varredura dos
arquivos e diretórios, e ajudar na definição dos elementos do modelo de
61
configuração. A classe ConfigurationModelResourceVisitor, por sua vez,
utiliza métodos das classes JavaAnnotationUtil e
ConfigurationModelContent. Em JavaAnnotationUtil é usado o método
featureAnnotations() para recuperar as informações da anotação @Feature
(nome, tipo e característica-pai de uma característica) definidas, por exemplo, numa
classe ou aspecto. Dessa forma, é possível relacionar as características com
determinado elemento de implementação da LPS. Como na abordagem as classes
de teste também são anotadas, a associação de tais elementos às características
que elas testam pode também ser feita. Além de featureAnnotations(), o
método testAnnotations() é usado. Esse método faz parte da extensão do
GenArch e serve para obter os dados dos atributos da anotação @Test. Com
relação à classe ConfigurationModelContent, é usado, entre outros métodos,
addTestClass() para inserir no modelo uma classe de teste contendo a
associação com a(s) característica(s) especificada(s) para ela. Esse método também
é novo e está presente exclusivamente na extensão do GenArch.
Figura 15 - Classes principais na geração do modelo de Configuração.
4.4 Algoritmo de Derivação
A abordagem deste trabalho permite a implementação, gerência e derivação
de testes de uma linha de produto de software. Para o processo de derivação, em
particular, um passo essencial que precisa ser realizado antes é a anotação dos
elementos de teste com @Test, pois através dessa anotação é possível identificar
os artefatos de teste e recuperar informações que apontem se o teste é para o
núcleo ou produto da LPS, o estágio (unidade, integração ou sistema) e o tipo que,
62
no momento, pode ser apenas funcional. Além disso, o processamento dessas
anotações ajuda na definição dos elementos de teste no modelo de arquitetura e
configuração da extensão do GenArch. Quando os modelos do GenArch se
encontram prontos, a derivação do código de implementação de um produto e de
seus testes pode ser realizada. A extensão do GenArch propõe duas formas de
derivação que são: (i) geração de código de teste para o núcleo, durante a
engenharia de domínio; (ii) geração de código de teste para produtos, durante a
engenharia de aplicação.
A funcionalidade de derivação de teste referente ao núcleo da LPS quando
iniciada requisita para o usuário da ferramenta definir: (i) o nome do projeto para a
derivação; e (ii) selecionar um ou mais estágios que devem ser considerados, ou
seja, indicar se serão carregados testes de unidade, integração ou sistema para o
núcleo. Quando a derivação é finalizada, o projeto Java de destino recebe todos os
elementos de implementação da LPS que não foram anotados ou que não estão
presentes no modelo de configuração. Geralmente, como esse modelo apresenta
elementos relacionados com variabilidades da linha e como a derivação é para
artefatos do núcleo, é feito o carregamento de elementos que não façam parte do
conteúdo do modelo de configuração, ou seja, artefatos de implementação
obrigatórios. Contudo, caso aconteça de especificamente uma classe ou aspecto
relacionada a alguma característica mandatória esteja nesse modelo, o algoritmo de
derivação abre uma exceção e verifica se o elemento é realmente do núcleo. Com
relação aos elementos de testes, são carregados aqueles que possuem as
informações que indicam que os testes são apenas para o núcleo e ligados aos
estágios definidos. Caso existam testes representados no modelo de configuração,
eles também são analisados para saber se a característica associada se trata, de
fato, de uma característica mandatória.
A derivação dos testes para produtos específicos, por sua vez, é semelhante
a derivação do código de teste para o núcleo, mas a diferença é que uma
configuração do modelo de características é definida. Dessa forma, é possível saber
as características comuns e variáveis que compõem um produto, e com as
associações definidas em tais características com os elementos de implementação,
o algoritmo de derivação pode selecionar os artefatos específicos para o membro da
LPS. Os testes para um produto são carregados de acordo com a configuração do
63
produto e dos estágios de teste selecionados, ou seja, se determinada característica
foi definida, os artefatos de implementação e teste relacionados a ela são derivados.
4.5 Sumário
Este capítulo apresentou a arquitetura do GenArch e as tecnologias adotadas
na implementação da ferramenta. A plataforma Eclipse, por se caracterizar como um
ambiente de desenvolvimento extensível forneceu diversas facilidades ao processo
de construção da ferramenta. Com o uso dos plug-ins JDT e AJDT no GenArch foi
possível manipular código-fonte Java e AspectJ, e ao empregar a API AST presente
em tais plug-ins, pode ser realizada a escrita, a leitura e remoção das anotações do
GenArch, assim como a recuperação da estrutura de elementos como classes,
interfaces e aspectos. Além disso, os plug-ins EMF, FMP e oAW, também utilizados
no GenArch, possibilitaram a manipulação dos modelos e templates.
O capítulo também destacou que o sistema de varredura do GenArch sofreu
alterações para poder identificar e processar a nova anotação @Test. Além disso, a
capacidade de representação de elementos de teste nos modelos de arquitetura e
configuração na extensão do GenArch é encontrada. Para alcançar esse objetivo,
em específico, um novo elemento precisou ser incluído no meta-modelo de cada
modelo adaptado. Em seguida, foram exploradas as classes de implementação
envolvidas na geração dos modelos estendidos e a forma de colaboração entre tais
classes para garantir a representação de testes. As duas formas de derivação (carga
de testes para o núcleo ou para os produtos) também foram descritas. Nesse
momento, foram apresentadas as adaptações no algoritmo de derivação para
permitir o carregamento tanto do código de dado produto, bem como dos artefatos
de teste relacionados a esse membro que pertençam à determinada estratégia,
estágio e tipo de teste.
64
5 Abordagem em Ação
Este capítulo apresenta uma linha de produto para aplicações web no domínio
de comércio eletrônico (E-Commerce), destacando as características comuns e
variáveis, projeto detalhado e as tecnologias empregadas para implementar as
variações identificadas nessa LPS. Esta LPS é usada como estudo de caso de
aplicação e avaliação da abordagem de teste proposta nesta dissertação. Assim, o
capítulo também ilustra como as diretrizes da abordagem são usadas para
desenvolver testes para a LPS de E-Commerce.
5.1 Estudo de Caso: LPS E-Commerce
As aplicações web apresentam atualmente um nível de complexidade
elevado, uma vez que apresentam conteúdos diversificados, necessidade de
gerenciar várias operações, oferecer segurança e confiabilidade de informações,
entre outros fatores. No contexto desses sistemas, existem aqueles ligados ao
domínio de Comércio Eletrônico (E-Commerce), os quais permitem as empresas
realizarem seus negócios pela Internet (Lau, 2006). Essas aplicações suportam
diversos visitantes e transações, bem como coordenam inúmeras entregas de
produtos ou serviços para os clientes. Além disso, as aplicações E-Commerce
apresentam três padrões de transação, os quais são: Business-to-Consumer (B2C),
Business-to-Business (B2B) e Consumer-to-Consumer (C2C) (Rajput, 2000). B2C se
refere às transações de venda dos produtos ou serviços da companhia para os
clientes. O B2B abrange as transações de negócio dos produtos, serviços ou
informações entre companhias. O C2C, por sua vez, corresponde às transações de
venda e compra entre consumidores.
Com a finalidade de avaliar a abordagem apresentada neste trabalho é
empregado como estudo de caso uma linha de produto de sistemas web no domínio
de Comércio Eletrônico (E-Commerce). Grande parte da análise de domínio foi
fornecida pelo trabalho elaborado por (Lau, 2006). Nesse trabalho são destacados
modelos de características para lojas virtuais que contemplam requisitos do domínio
desses sistemas. As características são divididas em dois grupos principais: Store
Front e Business Management. Store Front reúne características referentes às
65
interfaces de interação dos clientes com a loja virtual. Muitas dessas características
são visíveis pelos próprios clientes e influenciam nas suas experiências de utilização
com a loja web. Business Management apresenta características relacionadas com
as operações de negócio da loja virtual como gerenciamento de produtos e pedidos
dos clientes, marketing, entre outras operações que colaboram no funcionamento da
loja.
5.1.1 Características Comuns e Variáveis
Nos modelos de características apresentados no trabalho de (Lau, 2006) são
encontradas em torno de duzentas e trinta características. Na LPS E-Commerce, em
particular, foram definidas quase oitenta características, as quais se encontram
também agrupadas em Store Front e Business Management. A Figura 16 apresenta
uma visão geral de algumas características da linha de produto.
Figura 16 - Modelo de Característica da LPS E-Commerce.
Como pode ser observado na Figura 16, existem no lado esquerdo as
características ligadas a Store Front e no lado direito as relacionadas a Business
Management. Com o uso do plug-in FMP do Eclipse foi possível definir os
relacionamentos, dependências, atributos e restrições das características referentes
66
ao escopo da LPS E-Commerce. Informações adicionais sobre tal LPS são
apresentadas em (Lau, 2006) e (Torres, 2011).
5.1.2 Arquitetura da LPS
Para o desenvolvimento da linha de produto E-Commerce foi empregado o
padrão arquitetural MVC (Model - View - Controller). Com o uso desse padrão foi
possível realizar a separação da lógica responsável pela: (i) apresentação e
interação com os usuários (camada View); (ii) manipulação dos dados e lógica de
negócio (camada Model); e (iii) da parte encarregada de capturar as ações dos
usuários e prover o mapeamento delas em chamadas das funcionalidades presentes
no Model (camada Controller). A Figura 17 apresenta uma visão da arquitetura MVC
adotada com a presença de alguns elementos de implementação da própria LPS.
Figura 17 - Arquitetura MVC da LPS.
67
Como pode ser observado na Figura 17, estão presentes na arquitetura: (i)
módulo Model - apresenta os Session Beans, que possuem a implementação do
negócio, as classes de domínio da arquitetura da LPS e as classes de acesso a
dados (DAOs); (ii) módulo View – possui as páginas web implementadas na
tecnologia Java Server Pages (JSP) que com o auxílio do framework Java Server
Faces (JSF) renderizam os dados de visualização; (iii) módulo Controller – contém
os Managed Beans, entidades que funcionam como controladores e interfaces de
comunicação entre as camadas View e Model.
Além do uso de páginas JSP e do framework JSF, a LPS E-Commerce
utilizou tecnologias como: (i) RichFaces para definição de componentes visuais e a
fácil integração com recursos AJAX; (ii) Spring que é o framework usado para
auxiliar na injeção de dependência; (iii) SpringAOP que faz parte do Spring e oferece
suporte para programação orientada a aspectos; (iv) AspectJ para ajudar também na
implementação dos aspectos; e (vi) Hibernate foi o framework para o mapeamento
dos elementos do domínio da LPS em entidades de base de dados.
5.1.3 Implementação de Variações
Uma das atividades essenciais no desenvolvimento de uma LPS é a escolha
dos mecanismos de implementação para cada uma de suas variabilidades (Chen et
al., 2009). No caso da LPS E-Commerce foi adotado um conjunto de técnicas e
tecnologias. A Tabela 3 apresenta um resumo das técnicas de modularização
adotadas para cada uma das variabilidades da LPS.
O primeiro grupo de características gerenciado é referente à característica
HomePage. Ela possui duas subcaracterísticas mutuamente exclusivas: StaticContent
e DynamicContent. A primeira habilita que o produto derivado tenha páginas JSP com
informações estáticas e no caso de mudanças do conteúdo delas ocorre a
substituição da página anterior pela página atualizada. A segunda possui duas
características alternativas: (i) WelcomeMessage que permite a exibição de uma
mensagem de boas vidas, geralmente de maneira textual, na página principal de um
produto; e (ii) SpecialOffers que permite um produto apresentar ofertas promocionais
para os clientes como produtos com desconto.
68
Tabela 3 - Características variáveis e formas de tratamento.
Características Subcaracterísticas Tipo Formas de tratamento
HomePage StaticContent e DynamicContent
Mutuamente exclusiva
Modelo de configuração
DynamicContent WelcomeMessage e
SpecialOffers Alternativa
Modelo de configuração; Fragmentos
Demographics Age e Income Alternativa Modelo de
configuração; Aspectos
ProductInformation DetailedDescription, WarrantyInformation,
Size,Weight Opcional
Modelo de configuração; Templates e Fragmentos
Searching BasicSearch e
AdvancedSearch Alternativa
Modelo de configuração
Browsing CategoryPage Opcional Modelo de
configuração
EletronicGoodsFulfilment
FileRepository Opcional Modelo de
configuração
ServicesFulfilment AppointmentScheduling
e ResourcePlanning Alternativa
Modelo de configuração
ContentManagement ContentApproval Opcional
Modelo de configuração; Orientação a
Objetos; Aspectos
Com a definição de características para um produto ocorre a seleção de
arquivos para compor esse membro da linha após a derivação. Para exemplificar, ao
escolher a característica StaticContent é feito o carregamento do arquivo
StaticContent.jsp; a seleção de DynamicContent implica no uso de
dynamicContent.jsp; ao especificar a característica WelcomeMessage os arquivos
welcomeMessage.jsp, MensagemMBean.java e mensagem.jsp são carregados; e ao
selecionar SpecialOffers implica no uso de ofertasespeciais.jsp. A Figura 18
apresenta uma visão parcial do modelo de configuração do GenArch usado na LPS,
apresentando a relação de alguns arquivos com características.
69
Figura 18 - Modelo de Configuração do GenArch.
Para gerenciar as variações de alguns arquivos JSP foram adotadas diretivas
do tipo include de JSP e templates do GenArch. A Figura 19 apresenta o template
dynamicContent.jsp.xpt usado para a geração adequada do arquivo
dynamicContent.jsp.
Figura 19 - dynamicContent.jsp.xpt.
Como pode ser observado na Figura 19, é definido um fragmento para extrair
o trecho de código referente ao include do arquivo wellcomeMessage.jsp (linha 6),
bem como o ponto de inclusão do conteúdo desse fragmento (linha 7). Um
fragmento representa um trecho de código ou texto num arquivo que se deseja
inserir em um template durante a sua customização. Além disso, é encontrada a
diretiva relacionada à inclusão da página ofertasespeciais.jsp que ainda não foi
encapsulada em fragmento (linha 9). O fragmento da Figura 20 é encontrado no
modelo de configuração do GenArch e esse fragmento só é adicionado no template
se a característica WelcomeMessage for selecionada para um produto da LPS.
70
Figura 20 - Fragmento WelcomeMessageFragment.
.
O outro grupo de variações implementadas está relacionado ao registro de
usuários das aplicações E-Commerce. A Figura 21 apresenta uma visão das
características desse grupo.
Figura 21 - Característica Demographics.
Como observado, Demographics é uma característica opcional e apresenta Age
(idade) e Income (renda) como subcaracterísticas. Com a definição de Demographics,
a classe Demografico.java é carregada para um produto após o processo de
derivação. Tal classe é ilustrada na Figura 22.
Figura 22 - Classe Demografico.java.
A classe original Demografico.java não possui, por exemplo, os atributos
idade e renda. Para incluir tais variações foram usados aspectos implementados em
AspectJ. A Figura 23 apresenta o arquivo DemograficoIdade.aj que exerce o papel
71
de incluir a idade e os métodos de atribuição e recuperação para esse atributo. Para
tratar a característica variável renda é usado, por sua vez, o arquivo intitulado
DemograficoRenda.aj.
Figura 23 - Arquivo DemograficoIdade.aj.
As características variáveis ligadas ao catálogo da loja também foram
tratadas. Esse catálogo possui informações dos produtos como o tipo, dados
básicos, descrição detalhada, informações de garantia, tamanho, peso e
disponibilidade. Na Figura 24 a seguir são vistas as características referentes ao
catálogo no modelo de características da LPS.
Figura 24 - Características de Catalog.
A solução adotada para gerenciar as variações referentes às informações dos
produtos foi a criação de um template relacionado à entidade Produto e fragmentos
para determinar o código variável que será inserido no template dependendo das
características selecionadas. Dessa forma, depois da derivação existirá uma classe
Produto.java com conteúdo específico de acordo com as variações definidas.
72
O conjunto de características formado por BasicSearch e AdvancedSearch;
ProductPage e CategoryPage; ShoppingCart, Checkout e OrderConfiguration;
PhysicalGoodsManagement, FileRepository, AppointmentScheduling e ResourcePlaning
são também gerenciadas, mas as formas de tratamento não são detalhadas no
presente trabalho por possuírem uma complexidade baixa ou equivalente a
característica WelcomeMessage.
A última característica variável gerenciada e descrita nesta dissertação foi
ContentApproval que está relacionada à parte de gerência de conteúdo, uma das
funções administrativas mapeadas na LPS. A Figura 25 destaca ContentApproval no
modelo de características.
Figura 25 - Característica ContentApproval.
Com a seleção de ContentApproval para um membro da linha é preciso usar
uma lógica de negócio em que cada produto cadastrado necessite de aprovação do
supervisor para estar disponível na loja virtual. Caso ContentApproval não seja
escolhido, a aprovação não precisa ser realizada. Para tratar as duas possibilidades,
o padrão Strategy (Gamma et al., 1994) foi empregado para determinar a
implementação adequada em cada situação. A Figura 26 apresenta o uso desse
padrão na LPS.
73
Figura 26 - Padrão Strategy na LPS.
Para gerenciar a característica ContentApproval também foi usado aspectos.
Na Figura 27 a seguir é encontrado um comportamento inserido no método da
classe ProdutoDAO (elemento de acesso a dados) que retorna uma lista de
produtos. O comportamento do aspecto, por sua vez, retira da lista os produtos que
ainda não foram autorizados.
Figura 27 - Aspecto AutorizacaoNecessariaAspect.
5.2 Aplicação da abordagem de teste na LPS E-Commerce
Esta seção ilustra a aplicação das atividades (passos) da abordagem (ver
Figura 5) proposta nesta dissertação à LPS E-Commerce. É dado foco principal as
diretrizes para implementação dos artefatos de teste da LPS, assim como a gerência
e derivação automática dos artefatos de teste.
74
5.2.1 Passo 1: Escolha de Estratégias de Teste para a LPS
Diferentes estratégias de teste podem ser usadas para testar a linha de
produto E-Commerce. Nessa LPS, em particular, foram adotadas todas as cinco
estratégias concretas de teste propostas (Seção 3.1.1), com o objetivo de comprovar
a viabilidade de uso real de tais estratégias. Dessa forma, este trabalho apresenta
diretrizes para implementação de estratégias de teste tanto para os artefatos do
núcleo produzidos durante a engenharia de domínio quanto para os testes dos
produtos gerados na engenharia de aplicação da LPS web adotada. Em especial, é
também ilustrado como testes para o núcleo podem ser automaticamente reusados
para testes dos membros específicos derivados. Por fim, as atividades de teste
também buscaram verificar problemas nos artefatos comuns ou mesmo variáveis já
testados anteriormente nos produtos recém criados e que ainda não tinham passado
por testes.
Uma questão importante relacionada à nossa abordagem e que precisa ser
reforçada é a inexistência de determinações que obriguem o uso de todas as
estratégias de teste propostas. Dependendo do domínio específico ou das
características da LPS, a experiência da equipe com automação de testes, os custos
envolvidos nas atividades de teste, os objetivos pretendidos durante os testes e
entre outros fatores, podem existir situações em que seja preciso selecionar apenas
um subconjunto das estratégias. Esses casos são perfeitamente possíveis, uma vez
que a escolha das estratégias deste trabalho, seja em sua totalidade ou em parte, é
influenciada pelas situações que os envolvidos no processo de teste de uma LPS se
deparam.
5.2.2 Passo 2: Implementação dos Testes
A abordagem de teste proposta nesta dissertação aborda os testes da
engenharia de domínio e de aplicação. Na engenharia de domínio os testes são
aplicados para garantir a qualidade das classes do núcleo por meio de testes de
unidade com ou sem o uso de Mock Objects. Além disso, testes de integração com
mocks substituindo as variações e testes de sistema de funcionalidades completas e
obrigatórias são também usados. Na engenharia de aplicação, por sua vez, testes
de unidade, integração e sistema são empregados para os produtos derivados.
75
5.2.2.1 Testes de Unidade do Núcleo
Testes de unidade foram aplicados na linha de produto E-Commerce. Nessa
LPS existe na parte de persistência uma classe denominada GenericDAOImpl que
faz parte do núcleo e que é herdada pelas classes de acesso a dados (objetos
DAO). A classe GenericDAOImpl por pertencer a todos os membros da LPS foi
escolhida para ser testada. Além dos testes para GenericDAOImpl, foram
elaborados testes para outra classe do core denominada ProdutoDAO. A forma de
implementação e o nível de complexidade dos testes para essa classe são
compatíveis aos casos de teste de GenericDAOImpl. Dessa forma, no presente
trabalho, foram detalhados especificamente os testes de GenericDAOImpl.
Para a construção dos testes foi usado o framework JUnit. Na Figura 28 é
encontrado um diagrama que ilustra a classe de teste GenericDAOImplTest para
a execução dos testes para GenericDAOImpl. A classe de teste depende das
classes Mensagem e GenericDAOImpl, as quais estão também representadas no
diagrama.
Figura 28 - Classes envolvidas nos testes de GenericDAOImpl.
76
Na Figura 28 é observado métodos de teste da classe
GenericDAOImplTest. Além disso, é possível perceber que a classe de teste
herda da classe abstrata TestCase que pertence ao framework JUnit. A Figura 28
também apresenta métodos da classe Mensagem e que ela herda da classe abstrata
CadastroDB da LPS E-Commerce. A classe GenericDAOImpl, alvo dos testes,
também é encontrada, bem como alguns de seus métodos. Essa classe implementa
a interface GenericDAO.
Na Figura 29 é encontrado, em nível de código, a declaração da classe de
teste GenericDAOImplTest para testar os métodos de GenericDAOImpl. Pode
ser observado que a classe agrega atributos do tipo Mensagem que representam as
mensagens de boas vindas das aplicações E-Commerce. Além disso, é definido o
construtor e o método suite() para retornar a coleção de testes implementados na
classe GenericDAOImplTest.
Figura 29 - Classe GenericDAOImplTest.
A Figura 30 apresenta um trecho de código do método setUp(). Pode ser
observado que esse método instancia a classe GenericDAOImpl, cria um objeto do
tipo Mensagem, com a definição de valores para seus atributos. Além disso, é
encontrado o uso do método save() para armazenar na base de dados o objeto
Mensagem. Não é apresentado na figura, mas nesse método também é instanciado
e definido valores para outro objeto mensagem, assim como é realizada a sua
persistência.
77
Figura 30 - método setUp() de GenericDAOImplTest.
No método tearDown(), ilustrado na Figura 31, são retirados do banco as
entidades que representam as mensagens de boas vindas e que são usadas na
classe de teste.
Figura 31 - método tearDown() de GenericDAOImplTest.
Com relação à implementação dos métodos de teste, alguns são destacados
nesta seção. A Figura 32 apresenta o método de teste
testFindByPrimaryKey(). O método findByPrimaryKey() é usado no
método de teste e recebe dois parâmetros. O primeiro argumento define a chave
primária do objeto consultado e no segundo é especificado que deve ser retornado
um objeto do tipo Mensagem. Por fim, é encontrada uma assertiva do JUnit usada
para verificar se o objeto Mensagem recuperado apresenta o mesmo identificador de
“mensagem1”.
78
Figura 32 - método testFindByPrimaryKey().
A Figura 33 ilustra outro método de teste implementado,
testFindAll_Class(). Tal método de teste usa o método findAll() de
GenericDAOImpl que retorna uma lista com base no tipo de objeto repassado
como parâmetro. Em testFindAll_Class(), em particular, findAll() é
empregado para retornar uma lista de objetos do tipo Mensagem. Em seguida, é
analisado com a ajuda de uma assertiva do JUnit se o tamanho da lista é igual a
dois, uma vez que foram salvos no banco duas mensagens de boas vindas.
Figura 33 - método testFindAll_Class().
A Figura 34 ilustra um método de teste encarregado de verificar se todos os
objetos retornados pelo método findAllAtivos() estão ativos realmente.
Figura 34 - método testFindAllAtivos().
79
A Figura 35 apresenta um método encarregado de testar o método save()
de GenericDAOImpl. No método de teste, é realizada a instanciação de um objeto
Mensagem de nome “mensagem3”, bem como são definidos valores de seus
atributos. Em seguida, esse objeto é salvo na base de dados pelo método save().
O método findByPrimaryKey() é usado para retornar o objeto Mensagem
recentemente armazenado e por meio de uma assertiva do JUnit é verificado se foi
retornado um objeto não nulo. Por fim, o objeto retornado é excluído do banco.
Figura 35 - método testSave().
Neste documento são descritos apenas uma parte dos métodos usados para
testar a classe GenericDAOImpl e os que não são apresentados por possuírem um
nível de complexidade semelhante foram: (i) testUpdate() – para avaliar a função
de atualização; (ii) testDelete() – para analisar a exclusão; (iii)
testFindAll_Class_Order() – para testar um método que retorna uma lista de
objetos ordenada; e (iv) testFindByExactField() – para testar um método que
recupera objetos a partir de parâmetros específicos. Para executar o conjunto de
testes para GenericDAOImpl foi construído uma classe denominada DaoSuite
que pode ser vista na Figura 36. Pode ser observado que a classe DaoSuite herda
de TestCase do JUnit, como também é definido o construtor e um método suite()
para recuperar a coleção de teste de GenericDAOImpl e adicioná-las na suite de
testes de DaoSuite. É visto também que o conjunto de testes da classe
ProdutoDAOTest são obtidos e inseridos na mesma suite de testes.
80
Figura 36 - Classe DaoSuite.
5.2.2.2 Testes de Unidade do Núcleo com Mock Objects
Nossa abordagem propõe o uso de Mock Objects nos testes unitários das
classes do núcleo da LPS. Para demonstrar a aplicabilidade de tais diretrizes na
implementação de testes para o núcleo de LPS, foram definidos testes para classes
do núcleo da camada de negócio das aplicações E-Commerce como
ProdutoSBean, RegistroSBean, SBeanAlteracao, SBeanInativacao,
SBeanRemocao e ContextProdutoSBean. No presente documento serão
detalhados os testes dessa última classe (ContextProdutoSBean) que faz parte
da implementação do padrão Strategy adotado para gerenciar a característica
variável ContentApproval (Seção 5.1.3). Os testes das outras classes de negócio não
são descritas neste documento por serem bastante similares aos definidos para os
testes de ContextProdutoSBean, tendo complexidade de criação equivalente ou
inferior.
Na Figura 37 é encontrado um diagrama que representa a classe de teste
ContextProdutoSBeanTest que herda da classe abstrata
MockObjectTestCase (classe do framework jMock), como também a classe
ContextProdutoSBean analisada por meio de testes elaborados em
ContextProdutoSBeanTest, a interface IProdutoSBean e um mock que
implementa essa interface.
81
Figura 37 - Classes envolvidas nos testes de ContextProdutoSBean.
A Figura 38 apresenta o código da classe ContextProdutoSBeanTest.
Como pode ser observado, além de outras definições, existe nessa classe o uso de
um atributo do tipo Mockery (linha 30) para a construção dos mocks, bem como é
empregado um atributo do tipo Produto (linha 32). Como para os testes é
necessário usar esse objeto, foi necessário derivar um membro da LPS contento a
classe Produto.
Figura 38 - Classe ContextProdutoSBeanTest.
82
A Figura 39 apresenta a instanciação dos objetos necessários no setUp() e
o método tearDown() da classe ContextProdutoSBeanTest. Como pode ser
visto, são criados: (i) um objeto Produto e definido os valores de seus atributos
(linhas 47 a 56); (ii) a criação do mock “strategy” a partir da interface
IProdutoSBean (linhas 58 e 59), permitindo, dessa forma, testar os métodos
definidos nessa interface sem que seja preciso empregar as instâncias concretas de
IProdutoSBean (ProdutoSBeanComAutorizacao ou
ProdutoSBeanSemAutorizacao) que podem estar presentes somente na
engenharia de aplicação da LPS; e (iii) um objeto ContextProdutoSBean,
repassando para o construtor dessa classe o mock da interface IProdutoSBean
(linha 61).
Figura 39 - setUp() e tearDown() de ContextProdutoBeanTest.
A Figura 40 apresenta o método testCadastrar() da classe de teste
ContextProdutoSBeanTest. Esse método de teste verifica se o método
cadastrar() da interface IProdutoSBean é chamado apenas uma vez e se
recebe como parâmetro um objeto do tipo CadastroDB quando o método
cadastrar() da classe ContextProdutoSBean é executado. Essa análise é
realizada pelas expectativas definidas por meio do mock de nome “strategy” (linhas
83
73 a 75). Como esse mock implementa a interface IProdutoSBean é possível
acessar o método cadastrar() dessa interface e usá-lo nas expectativas do
método de teste. Em testCadastrar(), é observado também o uso de
cadastrar() da classe ContextProdutoSBean, recebendo um objeto do tipo
Produto criado no setUp() da classe de teste (linha 76). Por fim, é encontrada no
método de teste, a verificação das expectativas definidas (linha 81). Nesse
momento, caso as expectativas sejam atendidas, significa que ao empregar o
método cadastrar() de ContextProdutoSBean foi usado o método
cadastrar() de IProdutoSBean uma única vez e recebeu como parâmetro um
objeto CadastroDB.
Figura 40 - método testCadastrar().
A Figura 41 apresenta o método testAutorizar()que possui uma lógica
semelhante ao método de teste testCadastrar(). A diferença é que o método
analisado é autorizarProduto() da interface IProdutoSBean e que recebe
como parâmetro o identificador de um produto que precisa ser autorizado. O método
de teste verifica se autorizarProduto() de IProdutoSBean é usado apenas
uma vez e recebe um argumento do tipo inteiro quando o método
autorizarProduto() da classe ContextProdutoSBean é executado.
84
Figura 41 - método testAutorizar().
A Figura 42 ilustra testCancelar(), terceiro e último método de teste
implementado para a classe ContextProdutoSBeanTest. Esse método de teste
também apresenta uma lógica parecida com os dois métodos de teste descritos
anteriormente e se diferencia deles por analisar o método cancelarProduto()da
interface IProdutoSBean. Esse método, por sua vez, recebe como parâmetro um
identificador de determinado produto a ser cancelado. No método
testCancelar()é verificado se o método cancelarProduto() da interface
IProdutoSBean é utilizado uma única vez e recebe um valor do tipo inteiro quando
o método cancelarProduto() da classe ContextProdutoSBean é executado.
Figura 42 - método testCancelar().
85
Para executar os testes implementados na classe
ContextProdutoSBeanTest foi criada uma classe denominada
TestSuiteSBeans, ilustrada na Figura 43. A Figura 43 mostra também a forma
como a coleção de testes da classe ContextProdutoSBeanTest é recuperada e
adicionada na suite de TestSuiteSBeans (linha 19). É importante destacar que os
testes para as classes ProdutoSBean, RegistroSBean, SBeanAlteracao,
SBeanInativacao, SBeanRemocao, as quais fazem parte do núcleo da LPS, são
também obtidos e adicionados na suite de TestSuiteSBeans.
Figura 43 - Classe TestSuiteSBeans.
5.2.2.3 Teste de Integração do Núcleo
Os testes de integração do núcleo envolvem exercitar a execução conjunta de
objetos pertencentes a diferentes classes da LPS. Dessa forma, é possível verificar
como está a colaboração entre os elementos (classes) que implementam a
arquitetura base da linha de produto. Durante o desenvolvimento dos testes, é
necessária a definição de Mock Objects para representar (simular) as variações que
as classes do núcleo dependem. A Figura 44 ilustra um teste de integração que
emprega um objeto mock.
86
Figura 44 - Classes envolvidas nos testes de ProdutoMBean.
A Figura 44 apresenta a classe de teste ProdutoMBeanTest. Essa classe
depende de ProdutoMBean (alvo dos testes), elemento da camada de controle da
LPS E-Commerce e que participa de operações como o cadastro de produto e
adição de informações, bem como do processo de liberação de produtos. A classe
ProdutoMBean interage com a classe de negócio ContextProdutoSBean, a qual
utiliza a interface IProdutoSBean que faz parte da implementação do padrão
Strategy usado na LPS (Seção 5.1.3). Nesse padrão pode existir a presença de
classes reais que implementam IProdutoSBean e não estão representadas na
figura, as quais são: ProdutoSBeanComAutorizacao (classe variável) e
ProdutoSBeanSemAutorizacao (classe do núcleo). Contudo, para evitar o uso
das instâncias concretas de IProdutoSBean, que podem estar disponíveis apenas
na engenharia de aplicação, foi construído nos testes um mock com base na
interface IProdutoSBean. A Figura 45 apresenta o código dos testes para a classe
ProdutoMBean. Ela mostra no nível de código, a classe ProdutoMBeanTest.
Nessa classe de teste é encontrado um atributo do tipo ProdutoMBean (linha 28) e
outro atributo do tipo Mockery (linha 29). Além disso, é encontrado o construtor e o
método suite() da classe de teste.
87
Figura 45 - Classe ProdutoMBeanTest.
A Figura 46 ilustra a definição dos métodos setUp() e tearDown() da
classe ProdutoMBeanTest. No método setUp() é realizada a instanciação de
ProdutoMBean e sobrescrito os métodos addMensagem() e cancelar() usados
nessa classe, uma vez que os dois métodos citados acessam o contexto do
framework JSF quando existe uma aplicação real realizando operações como o
cadastro de produtos ou a liberação deles para estarem disponíveis na loja virtual.
Por fim, no método setUp(), também é criado o objeto mock usado nos testes
(linha 54).
Figura 46 - setUp() e tearDown() de ProdutoMBeanTest.
88
A Figura 47 apresenta o método de teste
testFinalizarCadastroProduto() da classe ProdutoMBeanTest. Esse
método é responsável por testar a colaboração entre a classe ProdutoMBean e
ContextProdutoSBean quando o método finalizarCadastroProduto() de
ProdutoMBean é requisitado. O método de teste foi elaborado sabendo que no
momento que é realizada a operação finalizarCadastroProduto() é usada
uma instância da classe ContextProdutoSBean e o seu método cadastrar().
Em seguida, nesse método é empregado o método cadastrar() definido na
interface IProdutoSBean. Dessa forma, caso nenhum problema ocorra durante a
interação entre as classes ProdutoMBean e ContextProdutoSBean que depende
de IProdutoSBean, o teste é realizado com sucesso.
Figura 47 - método testFinalizarCadastroProduto().
Como pode ser observado no método de teste, é criado um mock de nome
“strategy” a partir da interface IProdutoSBean (linha 64) e a definição de que será
possível criar mocks também com base em classes (linha 66). Com essa
especificação, foi possível construir um mock para a classe Produto (linha 67). Em
testFinalizarCadastroProduto(), é definido também um objeto do tipo
89
ContextProdutoSBean, repassando para o seu construtor o mock “strategy” no
instante que é instanciado (linha 69). Sem o uso desse mock, seria necessário o uso
de uma instância real de ProdutoSBeanComAutorizacao ou
ProdutoSBeanSemAutorizacao, dependendo da estratégia escolhida, ou seja, se
o produto precisa ou não de autorização após o seu cadastro. Na classe
ContextProdutoSBean é empregado um objeto que implemente a interface
IProdutoSBean para que, no momento do cadastro de um produto, possa ser
usado o método cadastrar() definido nessa interface. No caso do método de
teste analisado, é usado em ContextProdutoSBean o mock “strategy” que
implementa IProdutoSBean. Para analisar o método cadastrar() dessa
interface são definidas expectativas. No método de teste é informado que
cadastrar() deve ser executado uma vez e receber como parâmetro uma classe
CadastroDB (linhas 71 a 77). No caso dessas expectativas forem atendidas,
significa que no momento que o método finalizarCadastroProduto() é
requisitado, a classe ProdutoMBean conseguiu usar o método cadastrar() de
ContextProdutoSBean que, por sua vez, conseguiu empregar o método
cadastrar() da interface IProdutoSBean uma vez e pode receber como parâmetro
um objeto do tipo CadastroDB. Para implementar as expectativas é usado o mock
“strategy”, pois implementa a interface IProdutoSBean e, dessa forma, é possível
acessar o método cadastrar(). Além disso, o método
finalizarCadastroProduto() é chamado no método de teste (linha 77), assim
como são verificadas as expectativas especificadas (linha 79). Por fim, com a classe
ProdutoMBeanTest implementada, é possível executá-la de forma isolada ou em
conjunto com outros casos de teste através do uso de uma suite de testes.
5.2.2.4 Testes de Sistema do Núcleo
Os testes de sistema para o núcleo não são executados durante a engenharia
de domínio. Nessa fase existe apenas a construção dos testes, mas eles serão
aplicados concretamente num produto derivado da LPS. A abordagem propõe a
implementação dos testes de sistema através de templates que são usados para
definir scripts de teste para a ferramenta Selenium IDE. Além disso, ela define que
os templates podem: (i) conter código de teste que permanece inalterado para um
90
elemento (página de aplicação) mandatório ou (ii) podem apresentar uma parte fixa
e outra parte variável que é customizada com base nas variabilidades selecionadas
para um dado produto na engenharia de aplicação. A seguir, é encontrado um
exemplo que ilustra a primeira forma de uso dos templates.
Figura 48 - Template TesteCadastroTipoProduto.xpt.
A Figura 48 apresenta o template TesteCadastroTipoProduto.xpt que contém
o script de teste para um arquivo JSP chamado tipo_produto.jsp que é a página
responsável pelo cadastro dos tipos dos produtos. Essa página é comum aos
membros da LPS E-Commerce e não apresenta código variável. No template é
observado o uso do método projectName() (linha 11), método criado para a
91
extensão do GenArch e que permite a inclusão do nome do projeto que conterá
tanto o código referente à implementação de um produto (aplicação) como os seus
testes. O nome do projeto fica armazenado na variável name (linha11) e aplicado
num ponto específico do template (linha 12).
A Figura 49 apresenta um exemplo de template referente à segunda forma de
implementação proposta na dissertação, isto é, os templates de teste apresentam
trechos de código variável que são inseridos dependo das variabilidades escolhidas
para um dado produto da LPS. Parte do código comum do template foi omitido por
ser relativamente extenso, dificultando a visualização do script de teste. Na Figura
49 pode ser encontrado o uso do método projectName() para incluir o nome do
projeto de um produto relacionado à LPS.
92
Figura 49 - Template TesteCadastroProduto.xpt.
É também usado no template o método featureConfigurations() que
serve para recuperar as características relacionadas a uma característica. Esse
método é usado duas vezes no script de teste. Na primeira, são recuperadas as
características ligadas a ProductInformation (linha 17). No grupo de características
obtidas existem as seguintes variabilidades: DetailedDescription, WarrantyInformation,
Size, Weight e Availability. No método featureConfigurations() é analisado se
certa característica foi selecionada (linha 19) e caso tenha sido selecionada é
93
verificado se o nome da característica é igual a WarrantyInformation (linha 20). Caso
a condição seja verdadeira, é inserido no script final de uma aplicação derivada, o
trecho para testar a definição da informação de garantia de um produto que será
cadastrado (linhas 21 a 25). A verificação do nome da característica variável
selecionada também é realizada para Size e Weight e caso elas estejam presentes
num produto, são incluídos trechos de teste específicos referentes a cada uma delas
no template. Por fim, o método featureConfigurations() é usado pela
segunda vez (linha 31) para definir um trecho de código no script de teste caso a
característica variável DetailedDescription esteja presente num membro da LPS.
5.2.2.5 Testes de Unidade e Integração de Produtos
Na abordagem deste trabalho é proposto que os testes de integração
elaborados na engenharia de domínio da LPS sejam reexecutados como testes de
regressão na engenharia de aplicação da linha de produto. Esse cenário requer que
os casos de teste, originalmente voltados apenas para o núcleo, possam ser
adaptados de maneira a permitir a aplicação de testes nos diversos produtos
gerados na LPS, os quais são constituídos tanto por partes comuns como variáveis.
A adaptação dos testes se caracteriza essencialmente pela retirada dos objetos
mock empregados nos testes do núcleo pelas implementações reais das variações
que dependem. Os testes de unidade elaborados durante a engenharia de domínio
podem também ser reexecutados como testes de regressão. Caso seja necessário,
novos testes de unidade podem ser criados para as classes que representam
variantes concretas dos pontos de variação que possuem um papel crítico na LPS.
No que se refere à customização dos testes de integração, é apresentado na
abordagem o uso de templates. A Figura 50 ilustra a implementação de um template
baseado no teste de integração da classe ProdutoMBean do núcleo da LPS E-
Commerce (Seção 5.2.2.3). O template foi construído para atender a necessidade de
usar a implementação real referente à característica variável ContentApporval quando
ela é definida para um produto da LPS. Caso essa característica não seja
selecionada, o template gera uma classe de teste contendo, entre outras definições,
o mock que garante a realização dos testes sem a necessidade de usar a classe que
implementa a variação ContentApproval.
94
Figura 50 - (a) Template ProdutoMBeanProductTest.java.xpt.
A Figura 50 apresenta o template de teste
ProdutoMBeanProductTest.java.xpt. Nesse arquivo existe o uso do método
featureConfigurations() que é encontrado em várias partes do código e
empregado para recuperar as subcaracterísticas da característica
ContentManagement definidas para um produto. As subcaracterísticas possíveis são:
ProductDatabaseManagement e PresentationOptions que são obrigatórias, como
também ContentApproval que é opcional. No caso específico do template, a
subacaracterísitca que interessa é apenas ContentApproval. Como pode ser
observado, se essa característica variável for selecionada, a classe de teste herda
da classe abstrata TestCase do JUnit. Caso contrário, o teste herda de
MockObjectTestCase do jMock. Existem outros trechos que são definidos de
acordo com a escolha de ContentApproval. Nesses trechos, a presença dessa
variação num produto é analisada e se estiver presente é inserido, entre outras
95
definições, no código do método setUp(): (i) a instanciação de um objeto
GenericDAOImpl para acessar diretamente operações do banco; (ii) a criação de
um objeto Produto, assim como a definição de valores para seus atributos. Sem a
presença da característica ContentApproval, é incluído no teste apenas a criação de
um objeto do tipo Mockery para construção dos mocks, indicação de expectativas e
a verificação delas. Embora não seja apresentado na figura, mas o template também
garante a inclusão de pacotes específicos dependendo da presença ou não de
ContentApproval num membro da LPS. Trechos de código comum referente a certos
atributos e métodos como o suite() estão no template de teste.
Figura 51 - (b) Template ProdutoMBeanProductTest.java.xpt.
A Figura 51 ilustra outra parte importante relacionada ao template
ProdutoMBeanProductTest.java.xpt. Nela é encontrada a customização inicial do
método testFinalizarCadastroProduto(). Nessa parte do template é
analisado se a subcaracterística ContentApproval faz parte de um produto da linha.
Caso essa variação esteja presente é instanciado um objeto referente à classe
ProdutoSBeanComAutorizacao. No caso de ContentApproval não for selecionado
para um dado membro, é incluído o código referente à criação de um objeto mock a
partir da interface IProdutoSBean, podendo, dessa forma, ser usado para
substituir uma classe real que implemente essa interface como é o caso de
ProdutoSBeanComAutorizacao. Além da criação desse mock, é incluído no teste
a especificação que outros Mock Objects podem ser construídos a partir de classes,
como também a construção de um mock para simular a classe Produto.
96
Figura 52 - (c) Template ProdutoMBeanProductTest.java.xpt
A Figura 52 apresenta a continuação da customização do método
testFinalizarCadastroProduto(). O método featureConfigurations()
é usado novamente para recuperar as subcaracterísticas de ContentManagement,
sendo a que interessa no template é ContentApproval. No trecho de código existe a
verificação da presença da subcaraterística ContentApproval e se ela foi selecionada
na configuração de dado produto é incluído no método
testFinalizarCadastro() os trechos de código referente: (i) ao cadastro de um
produto da loja virtual pelo método finalizarCadastroProduto() de
ProdutoMBean; (ii) a recuperação do produto cadastrado; (iii) a verificação se o
produto foi realmente cadastrado na base de dados; e (iv) a exclusão do produto
presente no banco, pois as operações que necessitavam desse elemento foram
concluídas. Por outro lado, na situação em que ContentApproval não está na
configuração de um membro da LPS, é inserido no teste o código referente à
definição de expectativas através de um mock que torna possível os testes sem uma
instância da classe ProdutoSBeanComAutorizacao.
97
5.2.2.6 Testes de Sistema de Produtos
Nos testes de sistema da abordagem deste trabalho é aplicado o Selenium
IDE. Os arquivos de entrada para essa ferramenta são constituídos por scripts em
formato HTML, os quais são gerados com base em templates desenvolvidos com o
apoio dos recursos de criação e implementação de templates encontrados no
GenArch. É necessário frisar que os testes de sistema das aplicações (produtos) da
nossa abordagem, não precisam ser implementados manualmente, pois o conteúdo
final dos scripts é gerado com base em templates. O trabalho envolvido está apenas
na definição e preparação do conteúdo desses templates. A Figura 53 apresenta um
exemplo de um script de teste de sistema para um produto da LPS E-Commerce.
Figura 53 - Script de teste de sistema para um produto da LPS.
98
Na Figura 53 é encontrado um script de teste para o Selenium IDE que foi
criado a partir do template TesteCadastroProduto.xpt (Seção 5.2.2.4). Esse script
está presente no projeto TestProduct, informação inserida no seu próprio código de
teste (linha 8). Na configuração do produto derivado para o projeto TestProduct
foram definidas as características variáveis WarrantyInformation e Size para permitir,
no momento do cadastro de um produto, especificar as suas informações de
garantia e o seu tamanho. Com base na presença de tais características, são
inseridos trechos de código específicos no script de teste (destacado na figura).
5.2.3 Passo 3: Anotar Artefatos de Teste
Como descrito no Capítulo 3, os responsáveis pelos testes têm acesso a nova
anotação @Test para indicar as classes de teste implementadas que devem ser
consideradas, assim como por meio de tal anotação é possível definir a estratégia, o
estágio e o tipo que cada teste pertence. Além disso, a anotação @Feature é
empregada para especificar o relacionamento de artefatos de teste com
características da linha de produto de software.
Figura 54 - GenericDAOImplTest anotada.
A Figura 54, a seguir, ilustra a aplicação de @Test na classe
GenericDAOImplTest. Através dela é definido: (i) a estratégia como core para o
artefato de teste, pois esse teste é voltado para a classe GenericDAOImpl que
pertence a todos os membros da LPS, (ii) o estágio do teste como unit, (iii) o tipo do
teste é especificado como functional. A mesma anotação e valores dos atributos são
usados nas demais classes de teste de unidade referentes ao núcleo da LPS como,
99
por exemplo, ContextProdutoSBeanTest conforme pode ser observado na
Figura 55.
Figura 55 - ContextProdutoSBeanTest anotada.
A anotação @Test é também aplicada na classe de teste de integração
ProdutoMBeanTest. A Figura 56 apresenta o uso de @Test e a definição dos
atributos strategy, stage e type. A diferença básica encontrada nessa classe em
comparação com as outras classes de teste destacadas anteriormente é a definição
do atributo stage como integration.
Figura 56 - ProdutoMBeanTest anotada.
Na abordagem de teste deste trabalho é proposto também o uso da anotação
@Feature do GenArch para relacionar os testes com as características da LPS,
permitindo que ao selecionar certa característica para um determinado produto, o
100
teste para tal característica seja também carregado. Contudo, não foi preciso o uso
de @Feature no nosso estudo de caso, por conta da maioria das classes de teste
apresentados neste trabalho serem para o núcleo. Dessa forma, para carregar tais
testes é preciso apenas o uso de @Test. O núcleo da LPS, por sua vez, é sempre
carregado, podendo ser testado normalmente. Um cenário que a anotação
@Feature poderia ser usada, seria na anotação de classes de teste de unidade ou
integração de um dado produto. Nesse caso, a anotação @Feature indicaria uma
variabilidade da LPS que poderia ou não ser inserida na derivação de um produto.
Por fim, os testes descritos no documento que envolvem variações (teste de
integração e sistema de produtos) são implementados como templates de teste, não
existindo, nesse caso, a necessidade de empregar a anotação @Feature.
5.2.4 Passo 4: Geração dos Modelos do GenArch
Com as classes que implementam a linha e os testes devidamente anotados,
os modelos do GenArch podem ser gerados. Na nossa extensão da ferramenta, os
modelos de arquitetura e configuração permitem representar os elementos de teste,
como também é possível através desses modelos recuperar as informações relativas
a estratégia, o estágio e o tipo que se enquadra cada teste. O modelo de
características, por sua vez, não sofreu mudanças na extensão. Para a criação dos
modelos, é preciso usar a opção Create Models do GenArch conforme observado na
Figura 57.
101
Figura 57 - Operação Create Models do GenArch.
Com a operação de geração dos modelos concluída, é criado no projeto da
linha de produto um diretório models contendo os modelos de arquitetura,
configuração e características do GenArch. A Figura 58 apresenta o projeto da LPS
e a pasta models com cada um dos modelos da ferramenta, os quais são usados na
abordagem para auxiliar o processo de derivação dos membros da LPS, assim como
dos seus testes.
102
Figura 58 - LPS E-Commerce com modelos do GenArch.
Os modelos da extensão do GenArch preservam as propriedades conhecidas
dos modelos da versão original da ferramenta. Contudo, o modelo de arquitetura
permite que elementos de teste possam ser representados e o modelo de
configuração além de prover essa representação, garante a associação de classes
de teste com características existentes na LPS. Para isso, é preciso que tais testes
tenham sido anotados também com @Feature. A Figura 59 ilustra parte de um
modelo de arquitetura gerado pela extensão do GenArch. Como pode ser visto, o
modelo contém a representação do template ProdutoMBeanProductTest.java.xpt e
da classe de teste ProdutoMBeanTest. As classes de teste, em particular, são
identificadas no modelo através da presença do termo “Test Class” antes do nome
de cada teste. Além disso, na figura é observado as propriedades de
ProdutoMBeanTest que são: (i) o nome da classe de teste; (ii) a localização do
elemento de teste; e (iii) as informações referentes a estratégia, o estágio e o tipo de
teste que o elemento de teste pertence.
103
Figura 59 - Modelo de arquitetura e propriedades de classe de teste.
Com relação à representação de testes no modelo de configuração, será
destacado um exemplo hipotético. Isso se deve ao fato desse modelo possuir,
fundamentalmente, a relação de elementos de implementação de uma LPS com
características variáveis. Sabendo dessa particularidade e por conta do documento
não explorar classes de teste voltadas diretamente para variabilidades, não é
possível um exemplo real de relacionamento de um teste com uma característica
variável no modelo. A Figura 60 apresenta uma classe de teste fictícia, denominada
TesteVariacao, associada a uma característica chamada CaracteristicaVariavel.
Considerando que essa característica estivesse presente na configuração de um
produto da LPS, ao terminar o processo de derivação existiria a classe
TesteVariacao para testar CaracteristicaVariavel. Esse carregamento é possível
devido o relacionamento estabelecido entre o caso de teste e a característica
variável.
104
Figura 60 - Demonstração de relacionamento entre teste e característica.
5.2.5 Passo 5: Derivação de Produtos da LPS
Com a geração preliminar dos modelos do GenArch concluída, tais modelos
podem passar por incrementos e refinamentos, tais como, adição de novos
elementos nos modelos ou reestruturação do conteúdo deles e definição de novas
associações dos elementos de implementação da LPS com características no
modelo de configuração, e entre outras melhorias. Com os modelos prontos, a
derivação dos produtos com seus testes pode ser iniciada. A abordagem deste
trabalho propõe duas formas de derivação: (i) carregamento de testes do núcleo da
LPS e (ii) carregamento de testes para os produtos.
105
Figura 61 - Operação Derivate Core Tests da extensão do GenArch.
A Figura 61 apresenta a forma como a derivação dos testes do núcleo (core)
é iniciada na extensão do GenArch. Ela ilustra a operação Derivate Core Tests que
inicia o processo de derivação do núcleo da LPS e dos testes relacionados aos
elementos que compõem esse núcleo. Em seguida, o usuário da extensão do
GenArch precisa definir o projeto que receberá o código do núcleo e seus testes,
assim como escolher os estágios de teste que serão considerados.
106
Figura 62 - Assistente de derivação dos testes do núcleo.
A Figura 62 apresenta o assistente de derivação do testes do núcleo. A
extensão do GenArch seleciona os artefatos do núcleo, ou seja, os elementos que
estão representados no modelo de arquitetura e não apresentam relação com
características variáveis da LPS. Depois da derivação, o núcleo da LPS é carregado
juntamente com os testes desse núcleo pertencentes a cada possível estágio
definido. Por exemplo, se for especificado a derivação de testes de unidade para o
núcleo são carregados os testes anotados com @Test e com o atributo strategy
igual a core e o atributo stage com valor unit.
107
Figura 63 - Testes de unidade em projeto de produto.
A Figura 63 ilustra testes de unidade presentes num projeto Java após a
derivação. Podem ser visualizados em tal figura, os testes de unidade
GenericDAOImplTest e ProdutoDAOTest, assim como o suite de teste
DaoSuite. Além disso, é encontrado o teste ContextProdutoSBeanTest e
outras classes de teste para elementos da camada de serviço da LPS E-Commerce.
A Figura 64 apresenta o script de teste usado para testar a página de
cadastro do tipo de um produto e que foi criado a partir do template
TesteCadastroTipoProduto.xpt (Seção 5.2.2.4). O script da Figura 64 deve estar
presente no projeto caso a opção system test tenha sido definida. Contudo, é
importante ressaltar que o algoritmo atual da extensão do GenArch processa todos
os templates encontrados no modelo de arquitetura, ou seja, sejam eles para testes
ou não. Além disso, o script foi gerado normalmente pelo fato do template que serviu
de base para a sua criação não depender de características da LPS. A
funcionalidade de selecionar especificamente os templates de teste de sistema para
o núcleo na derivação é alvo de trabalhos futuros.
108
Figura 64 - Script de teste para o Selenium IDE.
No que se refere à derivação dos produtos e dos seus testes, é usado outra
operação da extensão do GenArch. Essa operação é Derivate Product Tests que
aciona o assistente de carregamento dos testes dos membros de uma LPS. A Figura
65 ilustra a escolha da opção Derivate Product Tests.
109
Figura 65 - Operação Derivate Product Tests da extensão do GenArch.
Depois de selecionar a opção Derivate Product Tests da extensão da
ferramenta GenArch, o assistente para carregamento da implementação de
determinado produto e dos seus testes é iniciado. Esse assistente é semelhante ao
assistente de derivação dos testes do núcleo. A diferença é que existe a
necessidade de especificar uma configuração do produto alvo dos testes. A Figura
66 apresenta o assistente de geração dos testes de dado produto.
110
Figura 66 - Assistente de derivação dos testes de um produto.
Com a conclusão da derivação pelo assistente da Figura 66, os artefatos de
implementação relacionados às características presentes na configuração do
produto são derivados, assim como as classes de teste do núcleo e os testes que
lidam com variabilidades da LPS. Os testes que devem ser considerados são os que
pertencem aos estágios selecionados pelo usuário da extensão do GenArch. É
importante destacar que a derivação atual da extensão, no que se refere
especificamente aos testes de integração e sistema de produtos, os quais são
implementados na forma de templates de teste, são processados
independentemente dos estágios escolhidos. Dessa forma, eles são sempre
identificados e customizados de acordo com as características presentes em dado
produto. A correta seleção dos templates devido à necessidade de derivar testes de
integração ou sistema é objeto de trabalhos futuros deste documento.
A Figura 67 apresenta testes que são carregados ao definir o estágio de
integração para a derivação (opção integration test). Nesse caso, somente os testes
111
de integração do núcleo são gerados e sabendo que todos os templates são
considerados, estarão presentes os artefatos de teste criados a partir dos templates
de teste de integração.
Figura 67 - Testes de integração em projeto de Produto.
A Figura 67 mostra a classe de teste de integração ProdutoMBeanTest.
Essa classe foi construída para testar ProdutoMBean, classe do núcleo dos
membros da LPS. Existe também a presença da classe de teste
ProdutoMBeanProductTest que foi criado a partir do template
ProdutoMBeanProductTest.java.xpt (Seção 5.2.2.5). O conteúdo final da classe de
teste é definido com base na presença ou ausência da característica variável
ContentApproval.
5.3 Sumário
Este capítulo apresentou uma linha de produto de sistemas web pertencente
ao contexto de Comércio Eletrônico (E-Commerce) que foi usada para avaliar a
abordagem proposta neste trabalho. As tecnologias de implementação usadas
nessa LPS, as principais características e os mecanismos para tratar as suas
variabilidades foram destacadas. Além disso, a arquitetura da LPS que se
caracteriza como uma arquitetura MVC (Model - View - Controller) foi também
estudada, bem como é encontrada uma visão de alguns dos elementos de
implementação de tal linha de produto web.
O capítulo também apresentou a aplicação das atividades (passos) da
abordagem proposta na LPS E-Commerce. Foram detalhadas as diretrizes de
implementação dos artefatos de teste, como também a gerência, customização e
derivação de testes. O capítulo destacou também os diagramas, código das classes
112
de teste de unidade e integração do núcleo, assim como a criação dos templates
para definir o conteúdo dos testes de integração dos produtos ou para gerar os
scripts de teste de sistema para o Selenium IDE. Além disso, a aplicação da
anotação @Test é evidenciado de forma prática, bem como é destacado, também
num contexto real de uso, como a extensão do GenArch permite: (i) a geração dos
modelos (arquitetura, característica e configuração); (ii) derivação dos testes para o
núcleo, ou seja, testes voltados exclusivamente para as partes comuns de um dado
produto; e (iii) derivação dos testes para as partes comuns e variáveis de um
membro específico da LPS, isto é, testes que envolvem tanto o núcleo como as
variabilidade dos produtos gerados.
.
113
6 Trabalhos Relacionados
Nesta seção são apresentados trabalhos de pesquisa no contexto de teste de
linhas de produto de software. As características de cada trabalho são destacadas,
bem como são realizadas comparações entre os trabalhos relacionados existentes e
a abordagem de teste de LPS proposta na dissertação.
6.1 Abordagem de Teste de LPS Baseada em Riscos
No trabalho desenvolvido por (Kolb, 2003) é apresentado uma abordagem de
teste de linhas de produto orientada pela identificação e priorização de riscos. O
autor relata alguns desafios ou problemas relacionados aos testes de uma LPS, tais
como: (i) a natureza genérica dos componentes usados pela linha, pois podem
apresentar diversos pontos de extensão e variantes, tornando a atividade de teste
para todas as possíveis combinações desses componentes impraticável; (ii) a
necessidade de saber previamente quais variabilidades dos componentes da LPS
devem ser testadas e em que ordem; (iii) a falta de alternativas que consigam lidar
com os testes de componentes que sofrem mudanças constantemente e que vários
produtos da linha dependem; (iv) a necessidade de mais técnicas compreensíveis
que demonstrem como testar de forma adequada e com o menor custo os
componentes genéricos, bem como a forma de se testar apropriadamente a LPS em
geral, considerando a natureza de cada linha de produto.
Com base nos desafios e problemas de se testar uma LPS, apresentados
anteriormente, como também por visar tornar os testes mais eficientes e eficazes,
(Kolb, 2003) propôs a abordagem de teste de linhas de produto dirigida a riscos.
Essa abordagem oferece suporte ao planejamento e preparação de testes de linhas
de produto e fornece técnicas específicas para desenvolver e gerenciar casos de
teste para componentes genéricos que os membros da LPS dependem. A
abordagem também oferece orientações para selecionar e como aplicar estratégias
adequadas para linhas de produto com base em requisitos, aspectos
organizacionais, riscos ou restrições de cronograma e recursos. A abordagem
defende que tanto o tempo como os recursos podem ser mais bem aproveitados
114
pela identificação e priorização dos riscos. Além disso, apresenta critérios de
cobertura específicos.
Apesar das contribuições de testes de linhas de produto de software
destacados no trabalho de (Kolb, 2003), não são encontradas informações que
mostrem em detalhes como alcançar os benefícios defendidos, bem como empregar
a abordagem orientada a riscos num contexto prático de desenvolvimento de testes
para uma LPS. Além disso, a gerência e o planejamento dos testes não são
explorados em profundidade, inexistindo também a especificação de como conduzir
o processo de criação e uso de artefatos de teste. Na abordagem proposta nesta
dissertação são oferecidas diretrizes para implementação e gerenciamento de
artefatos de testes considerando estratégias de teste específicas. Vale ressaltar que
as estratégias para identificação e priorização de riscos, bem como os critérios de
cobertura apresentados por (Kolb, 2003), podem ser usados para complementar a
abordagem proposta nesta dissertação.
6.2 Estratégias Genéricas de Teste para LPS
No trabalho desenvolvido por (Tevanlinna et al., 2004) são destacadas quatro
estratégias de teste genéricas que podem ser aplicadas a qualquer linha de produto
de software, uma vez que independem do contexto específico de cada LPS.
A primeira estratégia é definida como teste de produtos. Essa abordagem visa
testar os produtos individualmente, ou seja, à medida que produtos são gerados,
novos testes são desenvolvidos, procurando, dessa forma, assegurar a qualidade de
cada produto. Contudo, ela envolve altos custos e por não ser orientada a linhas de
produto, os benefícios alcançados pelo reuso de artefatos praticamente não são
encontrados.
A segunda estratégia é denominada testes incrementais de linhas de produto,
a qual tem como objetivo testar o primeiro produto gerado de forma individual e à
medida que novos produtos são criados, testes de regressão são aplicados. Nessa
abordagem, os testes de regressão possuem a função de garantir que os elementos
do núcleo da LPS testados anteriormente continuam funcionando depois de serem
integrados com artefatos específicos de cada novo produto gerado.
A terceira estratégia é conhecida como instanciação de artefatos reusáveis
que defende a criação de artefatos de testes o quanto antes possível na engenharia
115
de domínio. Na engenharia de aplicação esses artefatos podem ser reaproveitados
ou refinados para atender as necessidades de teste de um produto específico. Uma
alternativa para alcançar esse objetivo é o uso de artefatos de teste extensíveis,
buscando antecipar o teste de funcionalidades variáveis da LPS através de
templates e casos de teste abstratos (Hui Zeng e Rine, 2004).
A quarta e última estratégia é a divisão de responsabilidades. Nessa
abordagem os testes da linha são divididos entre a engenharia de domínio e
engenharia de aplicação. Essa divisão pode ser observada quando na engenharia
de domínio testes de unidade são empregados para verificar se componentes
individuais como classes e métodos que implementam o núcleo da linha estão
funcionando de forma adequada. Na engenharia de aplicação pode-se aplicar testes
de integração para os módulos que compõem um produto, buscando analisar a
comunicação entre esses módulos (Reis et al., 2007); testes de sistema para
analisar se os produtos gerados atendem as características requeridas, ou seja,
verificar se os sistemas da linha funcionam da maneira esperada (Nebut et al., 2006)
e testes de aceitação para comprovar que os produtos construídos se comportam da
forma deseja pelos seus interessados.
Na abordagem de teste para linhas de produto proposta neste trabalho foram
adotadas: (i) as estratégias de reuso de artefatos de testes, visando permitir que
testes como os de unidade e integração implementados na engenharia de domínio,
pudessem reaproveitar os testes usados nos elementos núcleo da linha; (ii) testes
incrementais, uma vez que na abordagem foi preciso assegurar através de técnicas
de regressão se o que funciona num produto continua funcionando quando presente
em novo membro da linha; e (iii) divisão de responsabilidades, pois na abordagem
foram apontadas atividades de teste para as fases de engenharia de domínio e
aplicação. O trabalho proposto nesta dissertação representa uma concretização das
idéias e diretrizes gerais apresentadas em (Tevanlinna et al., 2004), oferecendo
assim mais sistematização para o teste de LPS.
116
6.3 Metodologia de Teste de LPS Baseada em Requisitos
Expressos como Casos de Uso
No trabalho desenvolvido por (Bertolino e Gnesi, 2003) é destacada a
importância do planejamento adequado dos testes de linhas de produto de software,
bem como a necessidade de considerar nesse planejamento as variabilidades
existentes na LPS. Além disso, os autores defendem o planejamento antecipado dos
testes durante a especificação dos requisitos da engenharia de aplicação, momento
que a maioria das variações são introduzidas. Com base nesse contexto, foi criada a
metodologia PLUTO (do inglês Product Line Use Case Test Optimization) que
emprega requisitos expressos como casos de uso para ajudar a gerenciar o
processo de teste de uma LPS.
A abordagem PLUTO permite a derivação de cenários de uso de produtos
que podem ser gerados pela LPS e que precisam ser testados para saber se os
requisitos foram satisfeitos. Esses cenários são mencionados no trabalho como
“casos de teste”, mas também é deixado claro que eles não apresentam as
características de casos de teste reais como especificações precisas dos dados de
entrada, sequência de eventos e dados de saída esperados. A derivação dos “casos
de teste” (cenários de uso), em particular, é realizada a partir de requisitos descritos
em Casos de Uso de Linhas de Produto (do inglês Product Line Use Case - PLUC)
(Bertolino et al., 2002) que estendem os casos de uso tradicionais (Cockburn, 2001),
os quais usam linguagem natural de forma estruturada para serem construídos. Os
PLUCs, por sua vez, apresentam o diferencial de garantir a descrição de variações
através de tags que indicam as partes dos requisitos que podem ser instanciados
para personalizar um produto específico da LPS. Além disso, O PLUTO é baseado
no método conhecido como Partição de Categorias (Ostrand e Balcer, 1998). Nesse
método, os PLUCs são considerados unidades funcionais e os testadores são
responsáveis por definir as propriedades do sistema requeridas, parâmetros
relevantes para fins de teste (conhecidos também como categorias) e valores
significativos que podem ser assumidos por cada categoria. Por fim, são usados
Especificações de Teste pela metodologia PLUTO, os quais possuem valores
escolhidos para as categorias e possíveis restrições. Essas informações são
fundamentais para a derivação do conjunto de “casos de teste” para cada produto
pertencente à LPS.
117
Como evidenciado anteriormente, os “casos de teste” são, na verdade,
cenários de uso que são testados para comprovar se os requisitos identificados na
LPS são atendidos. Os “casos de teste” não se apresentam como testes de fato
executáveis, embora sejam passíveis de implementação, este aspecto não é
atendido pelo trabalho de (Bertolino e Gnesi, 2003). Além disso, não apresenta
diretrizes claras de como conduzir os testes com apoio da metodologia PLUTO,
assim como não é oferecido uma ferramenta para auxiliar o processo de teste. Na
abordagem de teste desta dissertação, por sua vez, existe a definição clara de
atividades de teste na engenharia de domínio e aplicação, como também suporte
ferramental por meio da extensão do GenArch proposta que permite gerenciar e
derivar casos de teste de unidade, integração e sistema necessários para atender os
objetivos de teste da LPS.
6.4 Processo de Teste para LPS
O trabalho de (Machado, 2010) apresenta o RiPLE-TE (do inglês RiSE
Product Line Engineering Testing) que se caracteriza como um processo de teste
para linhas de produto de software. Tal processo faz parte do RiPLE (RiSE Product
Line Engineering), uma espécie de framework para o desenvolvimento de LPSs que
reúne as seguintes disciplinas: escopo, requisitos, projeto, implementação,
gerenciamento de evolução e testes. É importante destacar também que o RiPLE é
um dos projetos relacionados ao RiSE Labs (Almeida et al., 2004).
O RiPLE-TE é um processo que se concentra em promover a redução de
esforço na condução de atividades de teste em LPSs pela reutilização sistemática de
artefatos de teste. Para alcançar tal finalidade, as similaridades presentes nos testes
são exploradas, bem como é realizado o gerenciamento das variabilidades dos
produtos da LPS. Além disso, o processo de teste se caracteriza por poder ser
aplicado tanto no momento em que os artefatos núcleo da LPS são desenvolvidos
(engenharia de domínio) como no instante em que os produtos específicos são
construídos (engenharia de aplicação). Na engenharia de domínio é proposto o uso
de testes de unidade e integração. Inicialmente, testes de unidade são empregados
para saber se classes e métodos que formam um componente reusável funcionam
corretamente. Depois, testes de integração são usados para verificar a interação
entre interfaces de componentes e integração dos módulos da LPS. Na engenharia
de aplicação, testes de integração são novamente usados, mas para analisar a
118
colaboração entre os diversos componentes que formam dado produto. Em seguida,
é destacado o uso de testes de sistema para avaliar o funcionamento geral de
determinado produto e, dessa forma, verificar se os requisitos definidos previamente
para esse membro da LPS estão, de fato, sendo atendidos. Por fim, testes de
aceitação são usados para saber se os produtos derivados funcionam de acordo
com os requisitos estabelecidos pelos interessados e usuários de tais membros da
linha.
Conforme descrito anteriormente, o RiPLE-TE abrange as duas fases
principais de uma linha de produto, bem como usa testes referentes aos estágios
(níveis) de unidade, integração, sistema e aceitação. Esse processo de teste
também apresenta um conjunto de tarefas, documentos de entrada, artefatos de
saída, papéis e diretrizes para o desenvolvimento e gerenciamento de artefatos de
teste de uma LPS. Contudo, apesar de ser um processo bem completo, capaz de
auxiliar os envolvidos nas atividades de teste de uma linha de produto, existe certa
carência em demonstrar de forma mais precisa como o processo RiPLE-TE pode ser
empregado concretamente em projetos de LPS. No trabalho de (Machado, 2010)
são encontrados estudos experimentais, mas o foco está voltado para a avaliação
do processo proposto e coleta de resultados que sirvam para melhorá-lo. Na
abordagem de teste de LPS desta dissertação, por sua vez, além de evidenciar
conceitualmente as características e forma de uso de tal abordagem, são
apresentadas diretrizes explícitas e detalhadas de como empregá-la de forma prática
durante a engenharia de domínio e aplicação de uma linha de produto. Além disso, o
nosso trabalho possui um diferencial fundamental que é a proposta de extensão da
ferramenta GenArch que oferece suporte a implementação, gerência e customização
de artefatos de teste, assim como a derivação automática dos produtos com os seus
respectivos testes automatizados.
119
7 Conclusão e Trabalhos Futuros
Esta dissertação de mestrado propõe uma abordagem sistemática para o
teste de linhas de produto de software. A abordagem fornece estratégias que
ajudam a direcionar os responsáveis pelo processo de teste (passo 1 da Figura 5),
como também oferece uma visão clara de como os testes se manifestam nas fases
de desenvolvimento de uma LPS. Foram propostas cinco estratégias efetivas de
teste funcional que são: (i) testes de unidade do núcleo, (ii) teste de integração do
núcleo, (iii) teste de sistema do núcleo, (iv) teste de unidade e integração de
produtos e (v) teste de sistema de produtos. Para cada estratégia foram oferecidas
diretrizes que apresentam concretamente como realizar a implementação dos testes
(passo 2 da Figura 5) dos artefatos produzidos tanto na engenharia de domínio
como na engenharia de aplicação de uma linha de produto.
A abordagem também permite a gerência e customização dos testes de uma
LPS. Para dar suporte a essas atividades, bem como a elaboração dos testes
referentes às estratégias citadas anteriormente, foi implementada uma extensão da
ferramenta GenArch. Com o uso de tal ferramenta, os artefatos de teste são
anotados para promover a gerência de tais artefatos (passo 3 da Figura 5).
Especificamente, foi criada a anotação @Test para indicar: (i) a estratégia dos
testes, ou seja, especificar se esses testes são exclusivamente para o núcleo ou
para produtos da LPS; (ii) o estágio (unidade, integração, sistema) que o teste está
relacionado; e (iii) o tipo (funcional) de teste que o artefato de teste pertence. Com o
processamento de tais anotações, é possível identificar os elementos de teste da
LPS, possibilitando a inclusão de elementos de teste nos modelos de arquitetura e
configuração após a geração dos modelos da ferramenta GenArch (passo 4 da
Figura 5), garantindo assim a possibilidade de carregar tais elementos de teste em
contextos específicos de teste da LPS ou de um produto em particular. Com relação
à customização dos testes, o trabalho descreve a utilização de templates para testes
de integração e sistema que podem ser implementados de forma a conter código de
teste que apresentam uma parte comum e partes variáveis a serem geradas de
acordo com as variabilidades definidas para um produto da LPS (integra passo 2 da
Figura 5).
120
Por fim, com os artefatos de teste devidamente anotados e com os modelos
gerados e prontos para uso, a abordagem garante por meio da extensão do
GenArch, a derivação de elementos de implementação que constituem determinado
produto da LPS e geração de seus respectivos testes, de acordo com a estratégia
(teste apenas do núcleo ou de produtos específicos da LPS) e estágio (unidade,
integração e sistema) definidos pelo engenheiro da LPS em questão (passo 5 da
Figura 5).
7.1 Contribuições
As contribuições referentes à abordagem de implementação, gerência e
customização de testes de linhas de produto de software (Mariano et al., 2011)
apresentada neste trabalho são:
Definição de estratégias de teste de LPS. No presente documento são
destacadas estratégias concretas de teste que conduzem os testes na fase de
engenharia de domínio e aplicação. Com tais diretrizes, os engenheiros de
teste possuem uma visão prática de quais elementos podem ser testados e
como eles podem ser aplicados. Além disso, as estratégias também destacam
oportunidades de reutilização dos artefatos de teste automatizados
produzidos durante a engenharia de domínio e aplicação.
Diretrizes para Implementação das Estratégias de Teste da LPS. O
trabalho também apresentou diretrizes concretas para a implementação das
estratégias de teste propostas, a partir do uso de tecnologias modernas de
automação de teste, tais como, frameworks de teste de unidade e integração,
assim como ferramentas de scripts de testes funcionais no nível de sistema.
Extensão de Ferramenta de Derivação para Gerência de Variabilidades
em Artefatos de Teste. A dissertação também apresentou uma extensão da
ferramenta GenArch que pode ser usada para gerenciar e customizar
variabilidades em artefatos de teste para cada uma das estratégias propostas
na dissertação. A extensão de tal ferramenta envolveu a criação e
processamento de uma anotação com semântica relacionada a artefatos de
teste, assim como adaptações em seus respectivos modelos e
funcionalidades de derivação para contemplar também a customização de tais
artefatos.
121
Aplicação da Abordagem em um Estudo de Caso. Como forma de
avaliação preliminar da abordagem proposta, ela foi aplicada a um estudo de
caso de uma linha de produto para o domínio de sistemas web. O estudo de
caso permitiu ilustrar a concretização da abordagem no contexto de
tecnologias modernas de teste, tais como, framework JUnit e ferramenta de
teste de sistema Selenium, assim como avaliar a viabilidade de gerência e
customização de variabilidades em artefatos de teste para o domínio web.
7.2 Trabalhos Futuros
Como trabalhos futuros para a abordagem apresentada nesta dissertação de
mestrado pode-se destacar:
Extensão da abordagem de teste de LPS proposta neste trabalho para o
contexto de testes não-funcionais, tais como, teste de desempenho, stress e
segurança;
Avaliação sistemática qualitativa e quantitativa com outras abordagens de
teste propostas através da realização de estudos de caso e experimentos
controlados;
Derivação automática de casos de teste de unidade e integração, e seus
respectivos mocks, a partir da anotação @Variability proposta originalmente
no GenArch. Tal anotação permite indicar explicitamente pontos de variação
existentes na arquitetura da LPS, podendo ser usada como referências para a
criação de casos de teste e mocks;
Explorar o uso de técnicas avançadas de modularização para promover o
reuso de casos de teste de unidade e integração de forma alternativa a
técnica de template proposta nesta dissertação, com o objetivo de comparar
os benefícios, desvantagens e complementaridade de cada abordagem.
Melhorar a extensão do GenArch proposta para a gerência de variabilidades
em casos de teste, de forma a contemplar a seleção específica de templates
de teste com base nos estágios definidos durante o processo de derivação;
Desenvolver extensão do GenArch para lidar com linhas de produto de
software implementadas em outras linguagens. O objetivo inicial deste
trabalho futuro é adaptar a ferramenta para auxiliar o processo de teste do
122
middleware (LPS) de TV Digital que apresenta grande parte do seu código
escrito em C++. Por tal middleware se tratar de uma LPS com características
diferentes a linha de produto E-Commerce, novas estratégias de teste
poderão também ser elaboradas. Além disso, o novo estudo de caso permitirá
avaliar o uso da abordagem em um diferente domínio.
123
Referências
[Almeida et al., 2004] E.S. Almeida, A. Alvaro, D. Lucrédio, V.C. Garcia, and S.R.L.
Meira (2004). Rise project: Towards a robust framework for software reuse. In D.
Zhang, É. Grégoire, and D. DeGroot, editors, IRI, pages 48–53. IEEE Systems, Man,
and Cybernetics Society.
[Alves et al., 2005] V. Alves, P. Matos, et al. Extracting and Evolving Mobile Games
Product Lines. Proceedings of Software Product Line Conference (SPLC´2005),
Springer-Verlag, 2005.
[Antkiewicz e Czarnecki, 2004] M. Antkiewicz, K. Czarnecki. FeaturePlugin: Feature
modeling plug-in for Eclipse, OOPSLA’04 Eclipse Technology eXchange (ETX)
Workshop, 2004.
[Apel e Batory, 2006] S. Apel, and D. Batory. When to Use Features and Aspects?: a
Case Study. Proceedings of the 5th international conference on Generative
programming and component engineering, Portland, Oregon, USA, ACM Press,
2006.
[Apel et al., 2006] S. Apel, T. Leich, et al. Aspectual Mixin Layers: Aspects and
Features in Concert. Proceeding of the 28th international conference on Software
engineering, Shanghai, China, ACM Press, 2006.
[Araújo et al., 2002] J. Araújo, A. Moreira, I. Brito, and A. Rashid,. Aspect-oriented
Requirements with UML. Workshop on Aspect-oriented Modeling with UML. 2002.
[Beizer, 1990] B. Beizer. Software Testing Techniques, 2nd ed. Van Nostrand
Reinhold, 1990.
[Bertolino e Gnesi, 2003] A. Bertolino and S. Gnesi. Use case-based testing of
product lines. ACM SIGSOFT Software Engineering Notes, 2003.
124
[Bertolino et al., 2002] A. Bertolino, A. Fantechi, S. Gnesi, G. Lami, and A. Maccari.
Use Case Description of Requirements for Product Lines, REPL’02, Essen,
Germany, Avaya Labs Tech. Rep.ALR-2002-033, September 2002.
[Budinsky et al., 2003] F. Budinsky, D. Steinberg, et al. Eclipse Modeling Framework,
Addison-Wesley, 2003.
[Clements e Northrop, 2001] P. Clements and L. Northrop. Software Product Lines:
Practices and Patterns, Addison-Wesley Professional, 2001.
[Colyer, 2004] A. Colyer. Eclipse AspectJ: Aspect-Oriented Programming with
AspectJ and the Eclipse AspectJ Development Tools, Addison-Wesley, 2004.
[Czarnecki, 1998] K. Czarnecki. Generative Programming: Principles and Techniques
of Software Engineering Based on Automated Configuration and Fragment-Based
Component Models. Dissertation, Department of Computer Science and Automation,
Technical University of Ilmenau, 1998.
[Cirilo et al., 2007] E. Cirilo, U. Kulesza, and C. Lucena. GenArch: Uma Ferramenta
baseada em Modelos para Derivação de Produtos de Software. Simpósio Brasileiro
de Componentes, Arquiteturas e Reutilização de Software, 2007.
[Cirilo, 2008] E. Cirilo. GenArch: Uma Ferramenta Baseada em Modelos para
Derivação de Produtos de Software. Mestrado (Dissertação) - Departamento de
informática do Centro Técnico Científico da PUC - Rio, 2008.
[Czarnecki e Helsen, 2006] K. Czarnecki and S. Helsen. Feature-Based Survey of
Model Transformation Approaches. IBM Systems Journal, 2006. 45(3): pp. 621-640.
[Chen et al., 2009] L. Chen, M. A. Babar, and N. Ali. Variability Management in
Software Product Lines: A Systematic Review. 13th International Software Product
Line Conference - SPLC, 2009.
[Cockburn, 2001] A. Cockburn. Writing Effective Use Cases. Addison Wesley, 2001.
125
[Dijkstra, 1972] E.W. Dijkstra. Notes on structured programming. In Structured
Programming, by O. - J.Dahl, E.W.Dijkstra, and C.A.R. Hoare, Academic Press,
1972.
[Fewster e Graham, 1999] M. Fewster and D. Graham. Software Test Automation,
Addison-Wesley Professional, 1999.
[Filman et al., 2005] R. Filman, T. Elrad, et al. Aspect-Oriented Software
Development, Addison-Wesley, 2005.
[Freeman et al., 2004] S. Freeman, T. Mackinnon, N. Pryce, and J. Walnes. jMock:
Supporting Responsibility-Based Design With Mock Objects. OOPSLA’04, Oct.24-28,
2004, Vancouver, British Columbia, Canada.
[Gamma et al., 1994] E. Gamma, R. Helm, R.Johnson and J. M. Vlissides. Design
Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley
Professional, 1994.
[Garcia et al., 2006] A. Garcia, T. Batista, A. Rashid, and C. Sant’anna. Driving and
Managing Architectural Decisions with Aspects. In SHAring and Reusing architectural
Knowledge (SHARK '2006), v.31, 2006.
[Gears, 2010] Gears/BigLever. <http://www.biglever.com>. Acessado em 21/06/2010.
[Hoffman e Wilkin, 2002] D. Hoffman and S. Wilkin. Junit extensions for
documentation and inheritance. In Proceedings of the 20th Pacific Northwest
Software Quality Conference, pages 71-84, 2002.
[Hui Zeng e Rine, 2004 ] W. Z. Hui Zeng and D. Rine. Analysis of testing effort by
using core assets in software product line testing. SPLiT - Workshop on Software
Product Line Testing, 2004.
[jMock, 2010] jMock. <http://www.jmock.org/>. Acessado em 10/06/2010.
126
[Juristo e Moreno, 2006] N. Juristo and A. M. Moreno. Guest editors’ introduction:
Software testing practices in industry. IEEE Software, 2006.
[Kauppinen, 2003] R. Kauppinen. Testing framework-based software product lines.
Master’s thesis, University of Helsinki Department of Computer Science, 2003.
[Kiczales, 1997] G. Kiczales. Aspect-Oriented Programming. European Conference
of Object-Oriented Programming (ECOOP’97), Springer - Verlag, 1997.
[Kiczales et al., 2001] G. Kiczales, et al. An overview of AspectJ. In: Proceedings of
the 15th European Conference on Object-Oriented Programming. [S.l.]: Springer -
Verlag, 2001. p. 327-353.
[Kishi e Noda, 2006] T. Kishi and N. Noda. Formal verification and software product
lines. Communications of the ACM, 2006.
[Kolb, 2003] R. Kolb. A risk-driven approach for efficiently testing software product
lines. GPCE - 5th Generative Programming and Component Engineering, 2003.
[Kolb e Muthig, 2006] R. Kolb and D. Muthig. Making testing product lines more
efficient by improving the testability of product line architectures. In ROSATEA:
Proceedings of the ISSTA workshop on Role of software architecture for testing and
analysis, New York, NY, USA, 2006.
[Krueger, 2006] C. Krueger. “Introduction to the Emerging Practice of Software
Product Line Development”, In: Methods and Tools, vol 14, nr. 3, pp 3-15, Fall 2006.
[Kulesza et al., 2006] U. Kulesza, V. Alves, et al. Improving Extensibility of Object-
Oriented Frameworks with Aspect-Oriented Programming. Proceedings of 9th
International Conference on Software Reuse, ICSR 2006 Turin, Italy, June 12-15,
2006. Lecture Notes in Computer Science: Reuse of Off-the-Shelf Components,
Springer - Verlag: 231-245, 2006.
127
[Lau, 2006] S. Q. Lau. “Domain Analysis of E-Commerce Systems Using Feature-
Based Model Templates”. Dissertation. Waterloo, Ontario, Canada, 2006.
[Lougran et al., 2004] N. Lougran and A. Rashid. Framed Aspects: Supporting
Variability and Configurability for AOP. Proceedings of 8th International Conference
on Software Reuse, ICSR 2004, Springer - Verlag: 127-140, 2004.
[Machado, 2010] I.C. Machado. RiPLE-TE: A Software Product Lines Testing
Process. Mestrado (Dissertação) - Centro de Informática da Universidade Federal de
Pernambuco, 2010.
[Mackinnon et al., 2000] T. Mackinnon, S. Freeman, and P. Craig. Endo-Testing: Unit
Testing with Mock Objects. eXtreme Programming and Flexible Processes in
Software Engineering - XP2000, 2000.
[Mariano et al., 2011] H. Mariano, U. Kulesza, R. Coelho, E. Aranha. Uma
Abordagem para Projeto, Implementação e Derivação de Testes de Linhas de
Produto Web. XVII Simpósio Brasileiro de Sistemas Multimídia e Web - WebMedia,
2011.
[McGregor, 2001a] J. D. McGregor. A Practical Guide to Testing Object-Oriented
Software. Addison Wesley, 2001.
[McGregor, 2001b] J. D. McGregor. Testing a software product line. Technical Report
CMU/SEI-2001-TR-022, Software Engineering Institute, Carnegie Mellon University,
December 2001.
[McGregor e Sykes, 2001] J. D. Mcgregor and D. A. Sykes. A Practical Guide to
Testing Object-Oriented Software. Object Technology Series. AddisonWesley, 2001.
[Mezini et al., 2004] M. Mezini and K. Ostermann. Variability Management with
Feature-Oriented Programming and Aspects. Proceedings of the 12th ACM
SIGSOFT twelfth international symposium on Foundations of software engineering,
Newport Beach, CA, USA, ACM Press, 2004.
128
[Myers, 2004] G. J. Myers. The Art of Software Testing. 2nd ed. John Wiley &
Sons,Inc., 2004.
[Nebut et al., 2006] C. Nebut, Y. L. Traon, and J.- M. Jézéquel. System testing of
product lines: From requirements to test cases. In Software Product Lines, 2006.
[openArchitectureWare,2010]http://www.openarchitectureware.org/pub/documentatio
n/4.3.1/html/contents/core_reference.html#xpand_reference_introductio. Acessado
em 18/06/2010.
[Ostrand e Balcer, 1998] T.J. Ostrand and M.J. Balcer. The Category Partition
Method For Specifying and Generating Functional Tests. ACM Comm. 31 (6), June
1988, pp. 676-686.
[Parnas, 1976] D. L. Parnas. On the Design and Development of Program Families.
IEEE Transactions on Software Engineering (TSE), 1976. 2(1): pp. 1-9.
[Pohl e Metzger, 2006] K. Pohl and A. Metzger. Software product line testing.
Communications of the ACM, 2006.
[Pohl et al., 2005] K. Pohl, G. Böckle, et al. Software Product Line Engineering:
Foundations, Principles and Techniques, Springer, 2005.
[pure::variants, 2010] Pure::Variants. <http://www.pure-systems.com>. Acessado em
21/06/2010.
[Pressman, 2002] R. S. Pressman. Engenharia de Software, McGraw-Hill, 2002.
[Rajput, 2000] W.E. Rajput, E-commerce systems architectures and applications,
Artech House, 2000.
[Reis et al., 2007] S. Reis, A. Metzger, and K. Pohl. Integration testing in software
product line engineering: A model-based technique. In FASE - Fundamental
Approaches to Software Engineering, 2007.
129
[Reuys et al., 2006] A. Reuys, S. Reis, E. Kamsties, and K. Pohl. The scented
method for testing software product lines. In Software Product Lines, 2006.
[SEI, 2010] SEI - Software Engineering Institute. A framework for software product
line practice, version 5.0. Pittsburgh.
<http://www.sei.cmu.edu/productlines/frame_report/PL.essential.act.htm>. Acessado
em 01/05/2010.
[Selenium, 2010] Selenium IDE. <http://seleniumhq.org/docs/>. Acessado em
12/06/2010.
[Sommerville, 2003] I. Sommerville. Engenharia de Software, Pearson Education do
Brasil, 2003.
[Shavor et al., 2003] S. Shavor, J. D'Anjou, et al. The Java Developer's Guide to
Eclipse, Addison-Wesley Professional, 2003.
[Sybren et al., 2005] D. Sybren, S. Marco, et al. "Product derivation in software
product families: a case study." J. Syst. Softw. 74(2): 173-194, 2005.
[Tevanlinna et al., 2004] A. Tevanlinna, J. Taina, and R. Kauppinen. Product family
testing: a survey. ACM SIGSOFT Software Engineering Notes, 29(2):12, 2004.
[Torres, 2011] M. Torres. Avaliação Sistemática de Ferramentas de Derivação de
Produto. Mestrado (Dissertação) – Departamento de Informática e Matemática
Aplicada da UFRN, 2011.
[Weiss e Lai, 1999] D. Weiss and C. Lai. Software Product-Line Engineering: A
Family-Based Software Development Process, Addison-Wesley Professional, 1999.
Top Related