Teste Funcional: Uma abordagem Auxiliada por Aspectos
André Dantas Rocha∗, Adenilso da Silva Simão, José Carlos Maldonado, Paulo Cesar Masiero
[rocha,adenilso,jcmandon,masiero]@icmc.usp.br
Laboratório de Engenharia de Software
Instituto de Ciências Matemáticas e de Computação da Universidade de São Paulo Av. do Trabalhador São-Carlense, 400 - Centro - Cx. Postal 668
São Carlos - São Paulo - CEP 13560-970
Resumo
Nesse artigo é apresentada uma abordagem para o teste funcional de programas Java auxiliada por aspec-tos. Introduz-se a ferramenta AFTT – Aspect-based Functional Testing Tool, que oferece suporte a alguns critérios funcionais e utiliza recursos do AspectJ para permitir a análise de cobertura de teste funcional. Um exemplo ilustra o funcionamento e aplicação da ferramenta.
Abstract
This paper presents an aspect-based approach for the functional test of Java programs and introduces the Aspect-based Functional Testing Tool – AFTT. The tool supports some functional criteria and uses AspectJ features to allow functional test coverage analysis. An example illustrates the application of the tool.
1. Introdução
A Programação Orientada a Aspectos (POA) [9] oferece apoio para implementar de forma modular interes-ses espalhados por várias clasinteres-ses, tais como segurança, sincronização e persistência. A POA tem motivado pesquisas em diversas áreas da Engenharia de Software e já encontram-se na literatura propostas para sua aplicação não apenas à construção, mas também às fases de engenharia de requisitos, modelagem e teste de programas.
Testes podem ser vistos como um interesse que abrange todo o sistema, e desta forma, podem ser encap-sulados sob a forma de aspectos [2]. A separação entre o código funcional e o código de teste auxilia o manuseio de ambos, e a facilidade de inserir e remover aspectos na aplicação pode levar à criação de cenários de teste de forma mais rápida. Além disso, aspectos podem ser facilmente removidos quando a atividade de teste é finalizada, conservando intacto o programa original.
As linguagens orientadas a aspectos oferecem recursos que podem ser aplicados em diversas atividades de teste. Um exemplo é a instrumentação de programas utilizando linguagens como o AspectJ [8], que implementa mecanismos que facilitam o acesso aos objetos, atributos, parâmetros e resultados de métodos e permite que determinadas verificações, muitas vezes difíceis de ser executadas usando apenas recursos da orientação a objetos, sejam simplificadas. Essas características tornam a POA uma técnica útil para o teste funcional, pois a interceptação da execução de métodos e a captura de seus contextos (incluindo parâmetros e resultados), é essencial nesse tipo de teste, no qual consideram-se principalmente as entradas e saídas das operações.
Neste artigo apresenta-se uma abordagem que visa a auxiliar a aplicação do teste funcional em programas Java, utilizando a Programação Orienta a Aspectos. A principal motivação do trabalho é investigar o uso de aspectos no apoio à atividade de teste, para permitir a análise de cobertura em critérios do teste funcional e conseqüentemente fornecer subsídios à geração de casos de teste que exercitem funcionalidades do software ainda não cobertas. Ferramentas que apóiam o teste funcional, em geral, enfatizam a automatização da geração de casos de teste, e não oferecem análise de cobertura segundo critérios do teste funcional. Para
suprir essas duas características introduz-se a ferramenta AFTT – Aspect-based Functional Testing Tool, que usa os recursos providos pelo AspectJ para instrumentação do programa em teste, execução dos critérios funcionais e checagem de invariantes, pré e pós-condições.
Este artigo encontra-se organizado da seguinte forma: na Seção 2 são abordados de forma sucinta os con-ceitos e critérios principais do teste funcional de software. Na Seção 3 são descritas algumas abordagens para a instrumentação de programas Java. Na Seção 4 são apresentadas algumas propostas para o teste utilizando a POA. Nas Seções 5 e 6 descrevem-se a ferramenta AFTT e um exemplo de sua aplicação ao teste funcional de programas Java. Na Seção 7 é apresentado o estágio atual do trabalho e perspectivas futuras.
2. Teste Funcional
No teste funcional (ou teste caixa-preta) os requisitos de teste são estabelecidos a partir das especificações do software, e sua implementação não é necessariamente considerada. De acordo com Ostrand e Balcer [16], o objetivo do teste funcional é encontrar discrepâncias entre o comportamento atual do sistema e o descrito em sua especificação. Assim, consideram-se apenas as entradas, saídas e estado do programa e o testador não tem necessariamente acesso ao código fonte do software. No teste funcional podem ser utilizados diversos critérios, dentre os quais destaca-se, por sua simplicidade, o Particionamento em Classes
de Equivalência.
Nesse critério o domínio de entrada do programa é dividido em classes de dados, de onde os casos de teste são derivados [18]. A identificação das classes de equivalência é feita particionando-se cada condição de entrada em um ou mais grupos, o que leva à criação de dois tipos de classe: válidas (entradas válidas para o programa) e inválidas (demais entradas) [14]. O particionamento do domínio de entrada deve ser feito de forma que para cada classe, qualquer um dos seus elementos seja representativo de toda a classe. Assim, se um caso de teste de uma determinada classe de equivalência revela um erro, qualquer outro caso de teste nessa classe deve revelar o mesmo erro.
No Particionamento em Classes de Equivalência busca-se produzir casos de teste que cubram diversas classes de erros e que ao mesmo tempo reduzam o total de casos necessários. Dessa forma, o critério exige que cada caso de teste elaborado cubra o máximo de classes válidas possível, e que seja construído um caso de teste individual para cada classe inválida.
Alguns critérios funcionais utilizam os conceitos do Particionamento em Classes de Equivalência, podendo ser considerados como variantes “mais fortes”. Dentre esses critérios pode-se citar a Análise de
Valor-Limite [14, 18] e o Teste Funcional Sistemático [11]. Esse último ainda não encontra suporte automatizado,
e também está sendo implementado na AFTT.
3. Instrumentação e Teste de Programas Java
O teste de software normalmente envolve uma etapa na qual se realiza a instrumentação do programa em teste. A instrumentação consiste em inserir código auxiliar no programa que está sendo testado, o que permite ao testador observar o comportamento do programa e obter informações ou medidas referentes à sua execução. Essas informações permitem conhecer, por exemplo, o estado do sistema e os métodos que foram executados durante o teste da aplicação e dessa forma, fornecem subsídios para avaliar a adequação dos casos de teste utilizados. A instrumentação pode ser realizada em tempo de compilação ou dinamicamente, quando o código de instrumentação é inserido/removido durante a execução do programa.
Algumas ferramentas como Java Instrumentation Engine [19] permitem a instrumentação diretamente so-bre o código fonte, por meio da introdução de comandos (ou anotações) de instrumentação em locais es-pecíficos. A instrumentação do código fonte possui um nível maior de abstração, pois é feita no nível da linguagem de programação. No entanto, além de exigir a disponibilidade do código, esse tipo de abordagem leva à manutenção de dois códigos fontes: um instrumentado e outro não.
Protocolos como o Guaraná [15] utilizam uma abordagem distinta, baseada em implementações modifi-cadas da JVM1com o objetivo de oferecer recursos de instrumentação dinâmica via reflexão computaci-onal. Apesar de não necessitar do código fonte, a modificação da JVM diminui a versatilidade de teste
do software, uma vez que o programa a ser testado deverá ser executado na máquina virtual modificada, obrigatoriamente.
Uma terceira abordagem é a utilizada por ferramentas como Javassist [3] e BCEL [4], que permitem mani-pulação do bytecode Java e introdução de código de instrumentação por meio da inserção de instruções de baixo nível. A instrumentação do bytecode, por sua vez, apesar de eliminar os problemas citados anterior-mente, muitas vezes exige o conhecimento da estrutura do bytecode e portanto não é muito intuitiva. A POA se mostra uma alternativa interessante para a instrumentação e teste de programas, pois permite a modularização desses interesses sob a forma de aspectos. Esse tipo de separação auxilia na manutenção do código de teste e evita a existência de duas versões do programa (como na instrumentação de código fonte). Além disso, linguagens como o AspectJ efetuam a composição diretamente sobre o bytecode e geram código instrumentado compatível com a linguagem Java, evitando o uso de JVMs especiais.
Alguns autores tem usado a POA para instrumentar programas, com diversas finalidades [1, 5, 12, 17], con-tornando assim alguns dos problemas citados anteriormente. Apesar dessa técnica estar sendo utilizada em diversas áreas, ainda são desconhecidas abordagens específicas para instrumentação de programas visando especificamente o teste de software segundo critérios e técnicas estabelecidos pela comunidade de teste.
4. Teste auxiliado pela POA
Algumas propostas já se encontram disponíveis para teste de software auxiliado pela POA. Uma dessas abordagens é a proposta por Monk e Hall [13], na qual imitações virtuais de objetos são usadas como uma alternativa aos objetos imitadores tradicionais (objetos mock) no teste de unidade. Na abordagem adotada pelos autores nenhum objeto imitador é criado e ao invés disso, o AspectJ é utilizado para interceptar cha-madas aos métodos que estão sendo testados e retornar o valor desejado. Idéia semelhante é implementada pela ferramenta VirtualMock [21], que auxilia o teste de unidade também usando objetos imitadores virtuais e o AspectJ.
Pode-se citar também a proposta de Bruel et al. [2], na qual o AspectJ é utilizado para o teste de componen-tes de software. Em sua abordagem, cada caso de componen-teste é descrito por um aspecto e, durante o processo de composição, código de teste é inserido no componente, tornado-o “testável”. Novos atributos e métodos são introduzidos na classe base permitindo acesso ao estado do sistema e as transições de estado são capturadas por meio de pointcuts e tratadas nas execuções dos advices.
A POA também tem sido utilizada para a verificação de invariantes e para o teste de pré e pós-condições, bem como para alterar o comportamento de objetos no sistema e gravar as entradas e o comportamento de métodos [7]. Alguns autores também têm aplicado a POA para geração de casos de teste compatíveis com o JUnit [6], como é o caso da ferramenta Cricket Cage [20].
Apesar de já existirem algumas iniciativas que utilizam a POA no auxílio ao teste, evidenciam-se nos trabalhos publicados nessa área abordagens de teste apenas práticas, nas quais não se consideram os critérios e métodos estabelecidos e adotados pela comunidade de teste de software. As implementações, ainda que bastante úteis, limitam-se a abordagens ad-hoc e conceitos importantes de teste são ignorados. Essa perspectiva, em que desconsideram-se princípios importantes de teste, pode levar a testes incompletos ou muitas vezes dispendiosos.
5. A Ferramenta AFTT
A AFTT – Aspect-based Functional Testing Tool é uma ferramenta que utiliza aspectos para auxiliar o teste funcional de programas Java. A AFTT estende o JUnit, permitindo que a análise de cobertura de diversos critérios funcionais seja feita a partir de casos de teste elaborados nesse framework, e oferece su-porte aos critérios Particionamento em Classes de Equivalência, Analise de Valor-Limite e Teste Funcional
Sistemático. Além disso, permite que invariantes, pré e pós-condições do sistema sejam avaliadas.
A arquitetura da ferramenta é mostrada na Figura 1. A AFTT disponibiliza uma interface gráfica por meio da qual o testador tem acesso às principais funcionalidades do software, como entrada de dados e consultas a relatórios. Por meio dessa interface os casos de teste podem ser executados, habilitados e desabilitados. A interface também fornece funções que permitem a escolha do critério funcional que será utilizado no teste da aplicação e recursos para efetuar sua instrumentação. Na instrumentação são utilizados aspectos,
que capturam operações específicas do programa em teste e executam os critérios funcionais. Os dados resultantes da execução do programa instrumentado são armazenados em um arquivo XML utilizando a camada de persistência, que implementa a interface de acesso a esses dados. O módulo de consulta utiliza a camada de persistência para efetuar consultas específicas sobre o repositório, utilizadas para a geração dos relatórios. Programa em teste Instrumentação Relatórios Consulta Persistência JUnit Critérios Interface Registro da Execução (XML) Testador
Figura 1: Arquitetura da AFTT
Na Figura 2 é exibido o diagrama de classes da ferramenta instanciada para o exemplo da aplicação PDV (apresentado na próxima seção). Na figura são exibidas as principais classes e aspectos da AFTT utilizados no processo de instrumentação e teste da aplicação (em cinza) e as classes da aplicação (em branco). O aspecto abstratoAbstractInstrumentationimplementa as características e comportamento básicos para a instrumentação de operações da aplicação em teste e execução de critérios funcionais. Como as operações que deverão ser interceptadas pela ferramenta ainda não são conhecidas, esse aspecto possui um pointcut abstrato denominadooperationCall(), que deverá ser concretizado em cada aspecto filho. Nesse pointcut são definidas as regras para seleção das operações que serão testadas, e sobre ele atua um advice do tipo
around, que é responsável por exercitar os critérios escolhidos pelo testador.
Dois outros aspectos representam papeis importantes na ferramenta. O aspectoInheritancemodifica a hie-rarquia sob a classeTestCase(pertencente ao JUnit), introduzindo uma classe intermediária (CustomTestCase). Essa estrutura permite que o testador utilize normalmente o JUnit na elaboração dos casos de teste e a AFTT utilize uma versão instrumentada dessa classe. O aspectoPolicyEnforcement, por sua vez, efetua verifi-cações sobre os aspectos implementados pelo testador (filhos deAbstractInstrumentation) e observa se as regras de instanciação foram seguidas. Essa regras consistem basicamente na elaboração de métodos específicos e com nomenclatura apropriada e que serão utilizados pela ferramenta. Neste artigo apenas a instrumentação é abordada.
6. Teste da Aplicação PDV
No exemplo a seguir ilustra-se a aplicação da ferramenta no teste da aplicação Ponto de Venda (PDV), adap-tada de Larman [10]. Por questões de brevidade aborda-se apenas o critério Particionamento em Classes
de Equivalência, em uma das operações do sistema. Os demais critérios e operações seguem os mesmos
princípios.
A aplicação PDV automatiza as operações executadas em um ponto de venda. Basicamente, o sistema permite que sejam efetuadas compras por meio de três operações, que devem ocorrer em seqüencia: os itens da compra são adicionados sucessivamente, informando-se o código do produto e a quantidade desejada (entrarItem(int,int)). A primeira entrada leva à criação de uma nova venda, enquanto as demais apenas acrescentam novos itens de venda à venda atual. Após a entrada de todos os itens a venda é finalizada (terminarVenda()) e o pagamento é efetuado (registrarPagamento(float)). A operação que trata do pagamento é responsável por calcular o troco. As classes de equivalência para esta operação estão descritas na Tabela 1.
No diagrama da Figura 2 é possível observar, além das classes da AFTT, as classes da aplicação PDV. A classe CasosDeTestePDV implementa os casos de teste do JUnit e a classe PDV contém a operação
TraceManager trace() AbstractInstrumentation <<aspect>> CasosDeTestePDV main() test1() test2() test3() test4() test5() PDV entrarItem(cod, qtd) terminarVenda() registrarPagamento(valor) RegistrarPagamento_Valor valid_valor_igual_total() invalid_valor_menor_total() <<aspect>> RegistrarPagamento_Venda valid_venda_existente() invalid_venda_inexistente() <<aspect>> PolicyEnforcement <<aspect>> TestCase <<junit>> <<uses>> <<crosscuts>> <<crosscuts>> <<crosscuts>> <<crosscuts>> <<uses>> valid_valor_maior_total() CustomTestCase Inheritance <<aspect>> <<declare-extends>>
Figura 2: Classes principais da ferramenta e da aplicação PDV utilizando o critério Parti-cionamento em Classes de Equivalência
Condição de entrada Classes válidas Classes inválidas
Valor fornecido 1. Valor fornecido = total
2. Valor fornecido > total 3. Valor fornecido < total Existência da Venda 4. A venda existe 5. A venda não existe
Tabela 1: Classes de equivalência da operação registrarPagamento(float)
registrarPagamento(float), sobre a qual será efetuado o teste funcional. Ressalta-se que a implementa-ção das operações não é conhecida, e apenas suas assinaturas e comportamentos desejados estão disponí-veis.
Tendo sido implementados os casos de teste no JUnit, procede-se a instanciação da ferramenta para o teste da aplicação. Isso é feito por meio da criação de aspectos, que devem especializar o aspecto abstrato
AbstractInstrumentation. O pointcut operationCall() deve ser concretizado em cada aspecto elabo-rado, definindo a chamada à operação a ser testada. Recomenda-se criar um aspecto para cada condição de entrada de cada operação, permitindo maior controle sobre as operações em teste. Além do pointcut, cada aspecto deve conter métodos que descrevem as classes de equivalência. Esses métodos devem ser declarados como públicos e implementados com retorno booleano, permitindo que a classe de equivalência seja descrita sob a forma de predicado. Os métodos devem ser nomeados com prefixos especiais, conforme descrito na Tabela 2.
Critério Prefixo Descrição
Classes de Equivalência valid Classe de equivalência válida Valor-Limite invalid Classe de equivalência inválida Funcional Sistemático boundary Valor-limite
Pré e pós-condições pre Pré-condição
pos Pós-condição
Invariantes invariant Invariante
Para a operaçãoregistrarPagamento(float)foram elaborados dois aspectos2, um para cada condição de entrada. O aspectoRegistrarPagamento_Valorrepresenta a condição de entradaValor fornecido (Ta-bela 1) e pode ser visualizado na Figura 3. Na Figura também é possível visualizar o pointcut concretizado
operationCall()(linha 7), que especifica a operação em teste, além das diversas classes de equivalência dessa condição de entrada. De forma semelhante ao JUnit, o métodosetUp(float) (linhas 10–13), foi implementado no aspecto. A principal função desse método é capturar os parâmetros da operação em teste, sendo ele disparado sempre que uma operação é interceptada e antes das classes de equivalência correspon-dentes serem executadas. Apesar de opcional, quando implementado, o método permite que a captura dos parâmetros seja feita em um único local.
O funcionamento da ferramenta é exibido no diagrama da Figura 5, na qual se evidencia o join point na execução dos testes (losango preto). De forma resumida, a seqüencia do teste é descrita a seguir:
1. Os casos de teste são executados normalmente, via JUnit. Para cada caso de teste executado são guardados dados importantes do caso de teste, como seu número e nome;
2. Durante a execução dos casos de teste as operações da classe em teste são chamadas e sua intercep-tação é feita pelos aspectos criados pelo testador (no exemplo, o aspectoRegistrarPagamento_Valor); 3. A cada interceptação de operação um pointcut do tipo around (definido no aspecto
AbstractInstru-mentation– Figura 4) é executado, e realiza três tarefas:
(a) Captura os valores dos parâmetros passados à operação (métodosetUp). Também localiza e executa, utilizando reflexão, todos os métodos implementados no aspecto que represen-tam pré-condições;
(b) Dá prosseguimento à operação interceptada e captura seu resultado;
(c) De posse dos valores de entrada e saída da operação, localiza e executa todos os méto-dos implementaméto-dos no aspecto que representam classes de equivalência e pós-condições (também utilizando reflexão).
O resultado das execuções das classes de equivalência, pré e pós-condições é armazenado em um arquivo XML, por meio da classe TraceManager. Com base no arquivo de registro, é possível efetuar a análise de cobertura das classes de equivalência (ou pré/pós-condições).
1 public aspect RegistrarPagamento_Valor extends AbstractMethodInterceptor {
2 /** atributos **/ 3 PDV pdv;
4 float quantia;
5
6 /** pointcut concretizado indicando a operação a ser interceptada **/
7 public pointcut operationCall() : call(public void PDV.registrarPagamento(float));
8
9 /** método de configuração **/ 10 public void setUp(float quantia) {
11 this.pdv = (PDV) getTargetClass();
12 this.quantia = quantia;
13 }
14
15 /** classe de equivalência ’valor = total’ **/ 16 public boolean valid_valor_igual_total() {
17 return pdv.getVenda().total() == quantia;
18 }
19 ...
20 }
Figura 3: Trecho do aspecto RegistrarPagamento_Valor
Para o teste da aplicação PDV foram elaborados cinco casos de teste, que encontram-se implementados na classeCasosDeTestePDV(Figura 2). Como descrito anteriormente, o critério Particionamento em Classes
de Equivalência exige que um caso de teste seja elaborado para cada classe inválida e um conjunto mínimo
1 public abstract aspect AbstractInstrumentation {
2 ...
3 /** execução dos predicados **/
4 Object around() : operationCall() && ... {
5
6 /** executa o método de configuração **/ 7 invokeSetUp(thisJoinPoint.getArgs());
8
9 /** executa os pré-testes **/ 10 doTests(thisJoinPoint, BEFORE);
11
12 /** captura o resultado da operação **/ 13 resultObject = proceed(); 14 15 /** executa os pós-testes **/ 16 doTests(thisJoinPoint, AFTER); 17 18 return resultObject; 19 } 20 ... 21 }
Figura 4: Trecho do aspecto AbstractInstrumentation
: CasosDeTestePDV : PDV : TraceManager main() test1() trace() registrarPagamento(164.1) operationCall() valid_valor_igual_total( ) <<aspect>> : RegistrarPagamento_Valor setup( ) trace() valid_valor_maior_total( ) trace() invalid_valor_menor_total( )
Figura 5: Diagrama de seqüencia do teste da aplicação PDV utilizando o critério Particio-namento em Classes de Equivalência
de casos de teste seja construído contemplando as classes válidas. Em vista disso, dentre os casos de teste elaborados, três (test1, test2 e test3) exercitam as três classes de equivalência da condição de entradaValor
fornecido(Tabela 1). Na Figura 6 é mostrada a implementação do caso de teste test1, que exercita a classe
de equivalênciaValor fornecido = total(Tabela 1). Os casos de teste test2 e test3 exercitam as demais classes de equivalência dessa condição de entrada.
A AFTT permite que seja analisada a cobertura por condição de entrada ou por operação. Uma condição de entrada é coberta quando todas as suas classes de equivalência são exercitadas. Uma operação, por sua vez, é coberta quando todas as suas condições de entrada são cobertas (ou seja, todas as suas classes de equivalência são exercitadas). Na Figura 7 é exibida a cobertura das condições de entrada da opera-çãoregistrarPagamento(float). Nota-se que os cinco casos de teste elaborados não foram suficientes para exercitar todas as classes de equivalência dessa operação e novos casos de teste devem ser elabora-dos com o objetivo de exercitar as classes de equivalência da condição de entradaExistência da Venda
(Tabela 1). Na Figura 8 é possível observar a cobertura das operações da classe PDV. Apenas a operação
entrarItem(int,int) foi coberta. A operaçãoregistrarPagamento(float) possui duas condições de entrada e cinco classes de equivalência, das quais apenas quatro foram cobertas (Figura 7). Isso leva a 75% de cobertura da operação.
1 public void test1() { 2 pdv.entrarItem(1001,4); 3 pdv.entrarItem(1002,6); 4 pdv.terminarVenda(); 5 pdv.registrarPagamento(164.1f); 6 assertTrue(164.1f == pdv.getVenda().total()); 7 }
Figura 6: Caso de teste test1 da classe CasosDeTestePDV
Figura 7: Cobertura das condições de entrada da operação registrarPagamento(float)
Figura 8: Cobertura das operações da classe PDV
7. Considerações Finais
A POA traz benefícios ao teste funcional e pode ser utilizada para a instrumentação e teste de programas. Nesse artigo abordou-se o uso do AspectJ para instrumentação de programas Java e análise funcional de co-bertura por meio de uma ferramenta denominada AFTT. A ferramenta possui uma interface simples e exige um conhecimento mínimo da sintaxe do AspectJ, uma vez que a geração da estrutura básica dos aspectos é feita automaticamente. Além disso, a AFTT utiliza casos de teste elaborados no JUnit, framework bastante difundido entre a comunidade Java, e seu uso permite reaproveitar os casos gerados em fases anteriores. Essa características tornam sua utilização simples, facilitando o teste.
Atualmente os trabalhos têm sido dirigidos para o suporte ao teste de pré e pós-condições e complemen-tação da interface da ferramenta, incluindo novos relatórios. Em uma próxima etapa será implementado o suporte à composição sobre o bytecode Java, permitindo que a aplicação seja testada ainda que seu código fonte não esteja disponível. A criação dos predicados que avaliam as classes de equivalência ainda é feita manualmente e sua automatização é um requisito que deverá ser implementado nas próximas versões da AFTT.
Referências
1. Briand, L.; Labiche, Y.; Leduc, J. Towards the Reverse Engineering of UML Sequence Diagrams for
Distributed, Real-Time Java software. Relatório Técnico SCE-04-04, Software Quality Engineering
Laboratory – Carleton University, Ontario – Canada, 2004.
2. Bruel, J. M.; Araújo, J.; Moreira, A.; Royer, A. Using Aspects to Develop Built-In Tests for Com-ponents. In: Akkawi, F.; Aldawud, O.; Booch, G.; Clarke, S.; Gray, J.; Harrison, B.; Kandé, M.; Stein, D.; Tarr, P.; Zakaria, A., eds. Proceedings of the 4th AOSD Modeling With UML Workshop, San Francisco – CA, 2003.
3. Chiba, S. Javassist: Java bytecode manipulation made simple. 2004.
Disponível em: http://www.jboss.org/developers/projects/javassist.html (Acessado em 05/09/2004)
4. Dahm, M. Byte Code Engineering Library. 2002.
Disponível em:http://bcel.sourceforge.net/(Acessado em 05/09/2004)
5. Deters, M.; Cytron, R. K. Introduction of Program Instrumentation using Aspects. In: Proceedings of the OOPSLA 2001 Workshop on Advanced Separation of Concerns in Object-Oriented Systems, Tampa – FL: ACM, 2001.
6. Gamma, E.; Beck, K. JUnit, Testing Resources for Extreme Programming. 2002. Disponível em:http://www.junit.org/(Acessado em 06/12/2003)
7. Isberg, W. Get Test-Inoculated! Software Development Article, 2002.
Disponível em: http://www.sdmagazine.com/documents/s=7360/sdm0205b/ (Acessado em 26/10/2003)
8. Kiczales, G.; Hilsdale, E.; Hugunin, J.; Kersten, M.; Palm, J.; Griswold, W. G. An Overview of AspectJ. Lecture Notes in Computer Science, v. 2072, p. 327–355, 2001.
9. Kiczales, G.; Lamping, J.; Menhdhekar, A.; Maeda, C.; Lopes, C.; Loingtier, J.-M.; Irwin, J. Aspect-Oriented Programming. In: Aksit, M.; Matsuoka, S., eds. Proceedings of the European Conference on Object-Oriented Programming, v. 1241, Berlin, Heidelberg, and New York: Springer-Verlag, p. 220–242, 1997.
10. Larman, C. Utilizando UML e Padrões: Uma Introdução à Análise e Projeto Orientados a Objetos. 1 ed. Porto Alegre: Bookman, 492 p., 2000.
11. Linkman, S.; Vincenzi, A. M. R.; Maldonado, J. C. An Evaluation of Systematic Functional Testing Using Mutation Testing. In: Proceedings of VII International Conference on Empirical Assessment in Software Engineering, Staffordshire – UK, 2003, p. 1–15.
12. Mahrenholz, D.; Spinczyk, O.; Schroder-Preikschat, W. Program Instrumentation for Debugging and Monitoring with AspectC++. In: Proceedings of the The 5th International Symposium on Object-oriented Real-time Distributed Computing, Crystal City – USA: IEEE Press, 2002, p. 249–256. 13. Monk, S.; Hall, S. Virtual Mock Objects using AspectJ with JUnit. XProgramming.com, 2002.
Disponível em: http://xprogramming.com/xpmag/virtualMockObjects.htm (Acessado em 20/01/2004)
14. Myers, G. J. The Art of Software Testing. 1 ed. New York: Wiley, 177 p., 1979.
15. Oliva, A.; Buzato, L. E. Guaraná: Uma Arquitetura de Software para Reflexão Computacional Implementada em Java. Dissertação de Mestrado, Universidade Estadual de Campinas, Campinas –
SP, 1998.
16. Ostrand, T. J.; Balcer, M. J. The category-partition method for specifying and generating fuctional tests. Communications of the ACM, v. 31, n. 6, p. 676–686, 1988.
17. Pearson, C. A Framework for the Aspect-Oriented Dynamic Instrumentation of Java Programs. Re-latório Técnico, Department of Computing - Imperial College London, London – France, 2003. 18. Pressman, R. S. Engenharia de Software. 5 ed. Rio de Janeiro: McGraw-Hill, 843 p., 2002. 19. Tromer, E. Java Instrumentation Engine (JIE). 1999.
Disponível em:http://www.forum2.org/eran/jie/(Acessado em 06/09/2004) 20. Walend, D. Cricket Cage. 2002.
Disponível em:http://sourceforge.net/projects/cricketcage(Acessado em 18/01/2004) 21. Woolley, C. VirtualMock. 2003.