Você está na página 1de 59

Teste de Software Orientado a Objetos e a Aspectos:

Teoria e Prtica

Paulo Cesar Masiero, Otvio Augusto Lazzarini Lemos,


Fabiano Cutigi Ferrari e Jos Carlos Maldonado

Abstract

Software testing has been shown to be important for reducing the number of product faults, attracting
interest from both academy and industry. As novel development approaches and support technologies
are proposed, new challenges arise in the testing of software developed in these new contexts. For
instance, object-oriented (OO) programming, already adopted by the developer community, and, more
recently, aspect-oriented (AO) programming, have motivated various efforts for the establishment of
novel testing approaches and criteria. The goal of this chapter is to present theoretical and practical
aspects of the software testing activity in the OO and AO software development context. In particular,
we emphasize structural and fault-based techniques with the support of JaBUTi and JaBUTi/AJ testing
tools, developed by the software engineering research group at ICMC/USP.

Resumo

O teste de software tem se mostrado importante para reduzir a quantidade de defeitos presentes
nos produtos, atraindo o interesse tanto da academia quanto da indstria. medida que surgem
novas abordagens de desenvolvimento e tecnologias de apoio, surgem tambm novos desafios re-
lacionados ao teste de software aplicado nesses contextos. Por exemplo, o paradigma orientado a
objetos (OO) j consolidado entre a comunidade desenvolvedora e, mais recentemente, a programa-
o orientada a aspectos (POA) tm motivado diversos esforos dedicados ao estabelecimento de
abordagens e critrios de teste nesses contextos. O objetivo deste texto apresentar os aspectos
tericos e prticos relacionados atividade de teste de software, tanto no contexto de software OO
quanto orientado a aspectos (OA). Em particular, so enfatizadas as tcnicas estrutural e baseada
em defeitos com o apoio das ferramentas de teste JaBUTi e JaBUTi/AJ, desenvolvidas pelo grupo de
pesquisas em Engenharia de Software do ICMC/USP.

13
Masiero, Lemos, Ferrari e Maldonado

1.1. Introduo
Muitas propostas de tcnicas e ferramentas para a verificao, validao
e teste de software tm sido apresentadas no contexto da rea agregada sob
o nome de Garantia de Qualidade de Software (GQS). Dentre elas, o teste
uma das mais utilizadas e consiste na execuo de um produto com a inteno
de revelar defeitos. Sua importncia deve-se ao fato das outras atividades de
GQS serem insuficientes para a descoberta dos erros introduzidos ao longo do
desenvolvimento do software [Pressman 2000, Myers et al. 2004].
Apesar de ser impossvel provar que um software est absolutamente cor-
reto por meio de testes, a sua utilizao fornece evidncias da conformidade
com as funcionalidades especificadas [Myers et al. 2004]. Alm disso, uma
atividade de teste conduzida de forma sistemtica e criteriosa auxilia no en-
tendimento dos artefatos testados e evidencia as caractersticas mnimas do
ponto de vista da qualidade do software [Harrold 2000, Weyuker 1996].
A aplicao de um critrio de teste est fortemente condicionada sua
automatizao, sendo ento de fundamental importncia o desenvolvimento
de ferramentas de teste. Sem a utilizao de ferramentas que automatizem
a aplicao das tcnicas e critrios associados, a atividade de teste torna-
se onerosa, propensa a erros e limitada a programas muito simples. Dessa
forma, a qualidade do teste, alm de depender das tcnicas e critrios sendo
utilizados, tambm depende da disponibilidade de ferramentas de apoio. Alm
disso, ferramentas de teste facilitam a conduo de estudos experimentais que
visam avaliar e comparar os diversos critrios de teste [Vincenzi 2004].
Com a consolidao do paradigma orientado a objetos (OO) para de-
senvolvimento de software durante os anos 80, diversos esforos tm sido
dedicados ao estabelecimento de tcnicas e critrios de teste no contexto
desse paradigma. Embora a orientao a objetos tenha trazido benefcios
para o projeto e desenvolvimento de software, oferecendo uma nova viso
de como decompor problemas e novas tcnicas para modelar e implemen-
tar solues para esses problemas [Booch 1994], o teste de software OO
apresenta um novo conjunto de desafios ao engenheiro de software, relacio-
nados s caractersticas e construes especficas do paradigma OO como,
por exemplo, encapsulamento, herana, polimorfismo e acoplamento dinmico
[McDaniel and McGregor 1994, Binder 1999].
Alm disso, mesmo com o desenvolvimento de tcnicas para construo
de software OO, observa-se que independentemente da tcnica utilizada ou do
modo como o sistema decomposto, alguns interesses pertinentes encontram-
se espalhados ou entrelaados nas vrias unidades do cdigo desenvolvido,
no estando portanto decompostos de forma organizada e localizada em m-
dulos separados [Elrad et al. 2001]. A Programao Orientada a Aspectos
(POA) surgiu no final da dcada de 90 como uma opo para solucionar es-
sas dificuldades, permitindo que interesses que se encontram espalhados ou
entrelaados possam ser implementados to separadamente quanto possvel
[Kiczales et al. 1997]. Contudo, assim como para a orientao a objetos, a

14
Teste de Software OO e OA: Teoria e Prtica

adoo da POA como tcnica de desenvolvimento no evita que defeitos espe-


cficos relacionados s novas caractersticas e construes relacionadas sejam
introduzidos no software. Ressalte-se que a maioria dos esforos dedicados
pesquisa envolvendo orientao a aspectos concentrada no estabelecimento
dos conceitos e em como implement-los nas tecnologias de apoio. Poucas
ainda so as iniciativas para estabelecer critrios e estratgias de teste para
programas orientados a aspectos (OA)
Diversos grupos de pesquisa na rea de teste vm desenvolvendo ativida-
des de pesquisa concentradas no estudo de princpios, estratgias, mtodos
e critrios de teste e validao de software, bem como na especificao e im-
plementao de ferramentas de teste que apiem a realizao das atividades
de teste e viabilizem a avaliao do aspecto complementar dos critrios de
teste por meio de estudos empricos. Dentre os critrios de teste investigados
pelo grupo de Engenharia de Software do ICMC/USP destacam-se os crit-
rios estruturais e baseados em mutao, explorados nos contexto de software
procedimental e, mais recentemente, para programas OO e OA.
O presente texto busca abordar os aspectos tericos e prticos relaciona-
dos atividade de teste de software OO e OA, enfatizando o teste de unidade.
Nesta seo foi apresentado o contexto no qual este texto est inserido. As
prximas sees esto organizadas da seguinte forma: na Seo 1.2 so intro-
duzidos os conceitos bsicos e a terminologia pertinentes ao teste de software,
incluindo os critrios de teste mais difundidos das tcnicas estrutural e baseada
em defeitos. Alm disso, so apresentados os principais conceitos relaciona-
dos programao OO e OA. Na Seo 1.3 so apresentados os conceitos
envolvendo a aplicao de critrios estruturais e baseados em mutao aplica-
dos nesses contextos. Em seguida, na Seo 1.4, apresentam-se exemplos da
aplicao dos critrios abordados. Para os critrios estruturais, so discutidas
as ferramentas JaBUTi (OO) e JaBUTi/AJ (OA), incluindo uma breve apresen-
tao de seus aspectos operacionais. Apresenta-se tambm uma aplicao
prtica do teste de mutao em programas OO e OA. Por fim, na Seo 1.5,
so apresentadas as concluses e perspectivas de trabalhos futuros na rea
de teste de software.

1.2. Terminologia e Conceitos Bsicos


Em um projeto de software, os artefatos submetidos ao teste podem incluir
programas, especificaes de requisitos e de projeto, estruturas de dados ou
quaisquer outros artefatos conceitualmente executveis utilizados no desenvol-
vimento da aplicao. De maneira geral, cada um desses artefatos representa
uma funo que, por sua vez, descreve a relao entre um elemento de entrada
(chamado de elemento do domnio) e um elemento de sada. Para se testar o
software so necessrios cinco elementos: o artefato conceitualmente execut-
vel, a descrio do comportamento esperado (obtida por meio de um orculo),
a observao da execuo do artefato em teste, a descrio do domnio funcio-
nal e um mtodo para determinar se o comportamento observado corresponde

15
Masiero, Lemos, Ferrari e Maldonado

ao esperado [Adrion et al. 1982]. Dessa forma, podem ser definidas quatro
atividades no teste de software: planejamento, projeto dos casos de teste, exe-
cuo dos casos de teste e avaliao dos resultados [Pressman 2000]. Essas
atividades podem ser realizadas em cada uma das seguintes fases, nas quais
se divide tradicionalmente o teste de um software:
Teste de unidade: busca identificar defeitos1 na lgica e na implemen-
tao de cada unidade do software, isoladamente. Segundo o padro
IEEE 610.12 de 1990 [IEEE 1990], uma unidade um componente de
software indivisvel. Para se testar as unidades de um sistema, tem-se
a necessidade da implementao de pseudo-controladores (drivers) e
pseudo-controlados (stubs). Os drivers so responsveis por coordenar
e ativar a unidade que est sendo testada, passando a ela os dados de
teste. Os stubs, por sua vez, consistem em implementaes simplifica-
das que substituem entidades que interagem com a unidade em teste.
Teste de integrao: visa a descobrir defeitos nas interfaces das unida-
des, durante a integrao da estrutura do programa. No caso de um
programa OO, considerando-se o mtodo como uma unidade, um tipo
de teste de integrao consiste em testar cada mtodo juntamente com
os mtodos chamados direta ou indiretamente por ele dentro da mesma
classe. Para um dado paradigma, a definio do que consiste uma uni-
dade implica em diferentes definies de teste de unidade e de integra-
o. Neste texto, essas definies so apresentadas na Seo 1.3.1.
Teste de sistema: quer identificar defeitos nas funes e caractersticas
de desempenho do sistema como um todo. Alm disso, procura-se verifi-
car se todos os elementos do sistema (por exemplo, hardware, pessoal e
bases de dados) combinam adequadamente e se a funo/desempenho
global do sistema alcanada.
Um caso de teste um par ordenado (d, S(d)) tal que d um elemento
de um determinado domnio D (d D) e S(d) a sada esperada para uma
dada funo da especificao, quando d utilizado como entrada. Uma veri-
ficao completa de um determinado programa P poderia ser obtida testando-
se P com um conjunto de casos de teste T que inclui todos os elementos do
domnio. Entretanto, como geralmente o conjunto de elementos do domnio
infinito ou muito grande, torna-se necessria a obteno de subconjuntos
desses casos de teste. Para isso, podem ser utilizados critrios de teste que
auxiliam o testador, fornecendo um mtodo para a avaliao de conjuntos de
1Neste texto procura-se seguir o padro IEEE 610.12-1990 [IEEE 1990] nas definies
utilizadas para os termos defeito, erro e falha. Defeito definido como uma divergn-
cia entre o produto de software desenvolvido e o produto supostamente correto; erro
definido como um estado interno do produto de software que diverge do estado correto,
gerado pela execuo de um defeito presente nesse produto; e falha definida como a
manifestao externa de um erro quando esse interfere nos comandos que produzem a
sada do produto em execuo.

16
Teste de Software OO e OA: Teoria e Prtica

casos de teste e uma base para a seleo de casos de teste. No primeiro


caso os critrios de adequao servem para evidenciar a suficincia da ativi-
dade de teste e, no segundo caso, para ajudar na construo de casos de teste
[Frankl and Weyuker 2000].
Os critrios de teste so geralmente derivdos a partir de quatro tcnicas
conhecidas: funcional, estrutural, baseada em defeitos e baseada em estados,
que diferem pela abordagem de teste subjacente utilizada para gerar e avaliar
os casos de teste [Zhu et al. 1997].
A tcnica funcional, tambm chamada de teste caixa-preta, tem o objetivo
de determinar se o programa satisfaz aos requisitos funcionais e no-funcionais
encontrados na especificao. A tcnica estrutural ou teste caixa-branca, por
sua vez, concentra-se na cobertura de partes do cdigo-fonte a partir dos ca-
sos de teste, sendo portanto baseada em uma implementao especfica. Os
critrios estruturais so baseados na idia de que no se pode confiar em um
programa se alguns elementos estruturais nunca foram executados durante a
atividade de teste. O teste baseado em defeitos utiliza informaes sobre os
tipos de erros freqentemente cometidos no processo de desenvolvimento de
software para derivar os requisitos de teste. Nesse contexto, modelos de de-
feitos caractersticos tecnologia de implementao do software geralmente
so utilizados, sendo elaborados a partir da experincia dos engenheiros de
software e de dados experimentais. Por fim, o teste baseado em estados uti-
liza uma representao baseada em estados para modelar o comportamento
do sistema ou unidade que ser testada. Com base nesse modelo, critrios
de gerao de seqncias de teste podem ser utilizados de modo a garantir o
correto funcionamento do sistema ou unidade.
Essas tcnicas so consideradas complementares, sendo de fundamental
importncia o estabelecimento de estratgias de teste capazes de explorar as
vantagens de cada critrio. Nesse contexto, tm sido realizados vrios estudos
tericos e experimentais envolvendo a aplicao das diferentes tcnicas de
teste e a definio dessas estratgias [Zhu et al. 1997].
Neste texto so enfatizadas as tcnicas de teste estrutural e baseada em
defeitos devido sua grande relevncia, demonstrada pela extensa investiga-
o na comunidade de Engenharia de Software e grande quantidade de publi-
caes sobre essas tcnicas. Alm disso, elas constituem os principais tpicos
investigados pelo grupo de pesquisa dos autores na rea de teste. Em parti-
cular, abordada a aplicao dos critrios estruturais baseados em fluxo de
controle e em fluxo de dados e, para a tcnica baseada em defeitos, critrios
baseados em mutao.
Teste Estrutural
A tcnica estrutural vista como complementar tcnica funcional e
baseia-se na estrutura de um programa para derivar seus casos de teste. Em
geral, os critrios dessa tcnica utilizam o grafo de fluxo de controle ou grafo
de programa. Esse grafo ilustra o fluxo de controle lgico de um programa
utilizando uma notao-padro [Pressman 2000].

17
Masiero, Lemos, Ferrari e Maldonado

Considerando um programa P, constitudo de vrios comandos, um bloco


consiste em um conjunto de comandos no qual a execuo do primeiro co-
mando do bloco acarreta a execuo de todos os outros comandos do mesmo
bloco, na seqncia determinada. Sendo assim, cada comando de um bloco,
possivelmente com exceo do primeiro, tem um nico predecessor e exata-
mente um sucessor, exceto possivelmente o ltimo comando. Um grafo de
fluxo de controle consiste em uma correspondncia entre ns e blocos de um
programa, que indica possveis fluxos de controle entre esses blocos atravs
de arestas [Zhu et al. 1997].
No que diz respeito ao grafo de fluxo de controle, alguns conceitos so
importantes para o seu uso na tcnica estrutural. Dado um grafo de fluxo de
controle G = (N, E, s) em que N o conjunto de ns, E o conjunto de ares-
tas e s o n de entrada, um caminho corresponde a uma seqncia finita de
ns (n1 , n2 , ..., nk ), para k 2, tal que existam arestas de ni para ni+1 para
i = 1, 2, ..., k 1. Um caminho dito simples se todos os ns que compem
esse caminho, exceto possivelmente o primeiro e o ltimo, forem distintos. Se
todos forem distintos, incluindo o primeiro e o ltimo, o caminho dito livre
de lao. Os ns de entrada e ns de sada correspondem, respectivamente,
aos ns que no possuem nenhum antecessor e aos ns que no possuem
nenhum sucessor. Em outras palavras, os ns de entrada no possuem ne-
nhuma aresta de entrada e os ns de sada no possuem nenhuma aresta de
sada [Zhu et al. 1997]. Um caminho completo um caminho que vai do n de
entrada a um n de sada do grafo de fluxo de controle.
Outro termo importante no teste estrutural refere-se aos caminhos no-exe-
cutveis. Um caminho no-executvel um caminho do grafo de fluxo de
controle impossvel de ser coberto para qualquer elemento do domnio de en-
trada. Isso acontece quando as condies lgicas que deveriam ser satisfeitas
para que a seqncia de ns do caminho fosse executada so contraditrias
[Howden 1986].
A partir do grafo de fluxo de controle, podem ser escolhidos os caminhos
a serem executados, com o apoio dos diferentes critrios da tcnica estrutural.
Na Figura 1.1(a) mostrado o cdigo Java de um mtodo para validao de
identificadores, e na Figura 1.1(b) o seu respectivo grafo de fluxo de controle
adicionado tambm de informaes de fluxo de dados.
Os critrios de teste estrutural baseiam-se na idia de que no se pode
confiar em um programa P se existem certos caminhos que ainda no foram
percorridos. Esses critrios geralmente associam um conjunto T de casos de
teste (que contm um subconjunto das entradas do programa) com um con-
junto de caminhos no grafo de fluxo de controle de P, que so percorridos
quando esses casos de teste so executados. T satisfaz o critrio C para P
se e somente se todo caminho requerido por C um subcaminho de um dos
caminhos de [Rapps and J.Weyuker 1982]. Nesse caso, diz-se que T C-
adequado para o teste de P.
Os primeiros critrios estruturais propostos so baseados apenas no fluxo

18
Teste de Software OO e OA: Teoria e Prtica

d=definio
uc=cuso
1 d ={s} up=puso

up={s} up={s}

d={achar, valid_id}
2 3 uc={achar, s}
public static boolean verify(String s)
{
/* 01 */ if (s == null || s.length() == 0) up={s,valid_id} up={s,valid_id}
/* 02 */ return false;
/* 03 */ char achar;
/* 03 4 5 d={i}
*/ boolean valid_id;
/* 03 */ valid_id = true;
/* 03 */ achar = s.charAt(0);
/* 03 */ valid_id = valid_s(achar);
/* 03 */ if (s.length() == 1 && valid_id)
/* 04 */ return true;
/* 05 */ int i = 1; 6
/* 06 */ while (i < s.length()) {
/* 07 */ achar = s.charAt(i); up={i,s} up={i,s}
/* 07 */ if (!valid_f(achar))
/* 08 */ valid_id = false;
/* 09 d={achar}
*/ i++;
7 10
/* 09 uc={achar,
*/ }
s}
/* 10 */ if (valid_id && (s.length() <= 6))
/* 11 */ return true; up={s} up={s}
/* 12 */ return false;
/* 12 */ }
d={valid_id} 8 11 12

d={i}
9 uc={i} 13

Figura 1.1. Grafo Def-Uso do mtodo para validao de


identificadores

de controle da aplicao e, entre eles, os mais conhecidos so:


Todos-Ns: Este critrio exige que cada comando do programa seja exe-
cutado ao menos uma vez, ou seja, que cada n do grafo de fluxo de
controle seja coberto. Em geral esse um critrio tido como fraco, pois,
na prtica, no revela nem mesmo a existncia de defeitos mais simples
[Myers et al. 2004].
Todas-Arestas: Todas-Arestas requer que cada desvio do fluxo de con-
trole do programa seja exercitado pelo menos uma vez, ou seja, que cada
aresta do grafo seja coberta. No grafo de fluxo de controle/dados para o
mtodo de validao de identificadores apresentado na Figura 1.1, fcil
ver que, para este caso, a cobertura de todos os ns do grafo no implica
a cobertura de todos as arestas. Por exemplo, pode-se ter casos de
teste que passem pelos caminhos (1, 2), (1, 3, 4), (1, 3, 5, 6, 7, 8, 9, 6, 10, 11)
e (1, 3, 5, 6, 10, 12) e que cobrem todos os ns, porm no exercitem a
aresta 7 9.
Todos-Caminhos: O critrio Todos-Caminhos requer que todos os cami-
nhos possveis do grafo de fluxo de controle sejam executados. Esse

19
Masiero, Lemos, Ferrari e Maldonado

critrio o mais exigente do teste caixa-branca e o nmero de requisi-


tos de teste gerados para ele, mesmo em um programa simples, pode
ser demasiadamente grande (possivelmente infinito) [Myers et al. 2004].
Na Figura 1.1, por exemplo, em decorrncia do lao (6, 7, 8, 9, 6), tem-se
inmeros caminhos no grafo.
Alm dos critrios baseados em fluxo de controle, existem ainda os basea-
dos em fluxo de dados, os quais utilizam o grafo Def-Uso, construdo a partir do
grafo de fluxo de controle, estendido com informaes adicionais sobre as de-
finies e subseqentes usos das variveis contidas em um programa (como o
exemplo apresentado na Figura 1.1 (b)). Uma definio de varivel ocorre toda
vez que um valor atribudo a uma varivel. O uso de variveis, por sua vez,
pode ser de dois tipos: uso computacional (c-uso), em que o valor da varivel
utilizado em uma computao; e uso predicativo (p-uso), em que o valor da
varivel utilizado em uma estrutura condicional ou de repetio. A partir da,
se existe alguma sentena em um bloco contendo um c-uso ou definio de
uma varivel, adiciona-se essa informao ao n referente no grafo. J os p-
usos so associados s arestas do grafo, visto que o valor das variveis afeta
a seqncia de execuo do programa. Um caminho livre de definio para
uma varivel x dos ns i a j, um caminho (i, n1 , ..., nm , j), m 1, no qual no
h definies de x nos ns n1 , ..., nm [Rapps and J.Weyuker 1982]. Outro con-
ceito importante o de par Def-Uso, que se refere a um par de definio e
subseqente c-uso ou p-uso de uma varivel.
O critrio mais bsico da famlia de critrios definidos por Rapps e Weyuker
[1984] o critrio Todas-Definies. Entre os critrios dessa famlia, o critrio
Todos-Usos tem sido um dos mais utilizados e investigados. Para o propsito
deste texto, podem ser destacados os seguintes critrios baseados em fluxo
de dados:
Todas-Definies: Requer que cada definio de varivel seja exercitada
pelo menos uma vez, no importa se por um c-uso ou por um p-uso.
Todos-Usos: Requer que todas as associaes entre uma definio de
varivel e seus subseqentes usos (c-usos e p-usos) sejam exercitadas
pelos casos de teste, atravs de pelo menos um caminho livre de defini-
o.
Todos-Potenciais-Usos: Requer que pelo menos um caminho livre de
definio de uma varivel definida em um n i para todo n e todo arco
possvel de ser alcanado a partir de i seja exercitado.
Teste de Mutao
Um dos critrios mais investigados da tcnica baseada em defeitos o
teste baseado em Anlise de Mutantes, ou teste de mutao. Esse critrio tem
um forte relacionamento com o modelo de teste de falha nica de circuitos digi-
tais, para a deteco de defeitos lgicos [Friedman 1975, Acree 1980]. A idia
bsica gerar vrias verses do programa original ligeiramente modificado,
com o objetivo de revelar os defeitos mais comuns introduzidos nos progra-

20
Teste de Software OO e OA: Teoria e Prtica

mas pelos programadores [DeMillo 1978]. Dessa forma, o conjunto de casos


de teste tambm avaliado quanto sua capacidade de revelar esses defei-
tos. Se as sadas obtidas na execuo de um mutante so iguais s sadas do
programa original, cabe ao testador determinar se o mutante equivalente ao
programa original ou se existe a necessidade de se projetar novos casos de
teste que resultem em uma sada diferente para o mutante em questo.
A gerao dos mutantes tem como base duas hipteses: a hiptese do pro-
gramador competente e a hiptese do efeito de acoplamento [DeMillo 1978]. A
primeira assume que programas a serem testados esto corretos ou prximos
do correto. A segunda, por sua vez, assume que casos de teste capazes de
revelar defeitos mais simples tambm revelam defeitos mais complexos. Um
defeito simples est associado a uma alterao sinttica simples, enquanto que
um defeito complexo pode ser considerado como uma composio de defeitos
simples.
Para a aplicao do teste de mutao, dados um programa P e um conjunto
casos de teste T, quatro passos so necessrios:
1. Gerao do conjunto M de mutantes:
Operadores de mutao so aplicados em P para gerar um conjunto de
mutantes M. Os operadores implementam as regras de alterao que
so aplicadas no programa original. Ressalta-se que a definio dos
operadores de mutao depende da linguagem de programao ou de
especificao em que os artefatos a serem testados esto escritos.
2. Execuo de P com T :
A execuo de P com T realizada e verifica-se se o resultado o
esperado. O processo encerrado caso alguma sada seja incorreta.
Caso isso no ocorra, o prximo passo realizado. Geralmente cabe ao
prprio testador decidir se a sada ou no a esperada para cada caso
de teste, fazendo portanto o papel de orculo [Weyuker 1982].
3. Execuo dos mutantes de M com T :
Cada um dos mutantes em M executado com os casos de teste em T.
Se um mutante m apresenta uma sada diferente de P executado com
o mesmo caso de teste, conclui-se que o conjunto de casos de testes
sensvel e consegue expor a diferena entre m e P, e m considerado
morto. Caso contrrio, duas possibilidades so consideradas: ou T de
baixa qualidade, no conseguindo revelar a diferena entre m e P, ou m
equivalente a P. Encerrada a execuo dos mutantes, o escore (score)
de mutao pode ser calculado pela seguinte frmula:

DM(P,T )
ms(P, T ) = M(P)EM(P)

Sendo:
ms(P,T): escore da mutao (mutation score);
DM(P,T): nmero de mutantes mortos por T;

21
Masiero, Lemos, Ferrari e Maldonado

M(P): nmero total de mutantes gerados;


EM(P): nmero de mutantes equivalentes identificados.
O resultado desse clculo sempre um valor no intervalo [0, 1], forne-
cendo uma medida de adequao de T, sendo que quanto mais prximo
de 1 for o resultado, mais adequado T.
4. Anlise dos mutantes:
Esse o passo que requer mais interveno humana. Inicialmente,
decide-se se o teste deve ou no continuar, dependendo do escore da
mutao. Resultados prximos a 1 sugerem um conjunto de casos de
teste T suficientemente bom e pode-se optar por encerrar o teste. Caso
decida-se por continuar o teste, cada um dos mutantes m vivos ana-
lisado se ele ou no equivalente a P.
O problema de determinar a equivalncia entre dois programas, nesse
caso P e um mutante m, geralmente indecidvel. Nesse contexto, em-
bora a automatizao completa dessa atividade no seja possvel, al-
guns mtodos e heursticas tm sido propostos para a determinao
da equivalncia entre P e m [Budd 1981, Simo and Maldonado 2000,
Vincenzi et al. 2002].
A aplicao da Anlise de Mutantes apresenta um alto custo devido princi-
palmente grande quantidade de mutantes gerados at mesmo para progra-
mas pequenos e dificuldade na identificao dos mutantes equivalentes ao
programa original. Diversos trabalhos tm investigado a adoo de estratgias
de aplicao do critrio de forma a reduzir seu custo, principalmente relaci-
onado ao nmero de mutantes gerados, entretanto sem perdas significativas
na eficcia em revelar defeitos. Dentre elas, destacam-se a Mutao Aleat-
ria, que consiste em gerar apenas uma porcentagem de mutantes para cada
operador selecionado [Acree et al. 1979]; a Mutao Restrita, em que um sub-
conjunto de operadores de mutao selecionado e aplicado na gerao dos
mutantes [Mathur and Wong 1993]; e a Mutao Seletiva, na qual os operado-
res responsveis pela gerao do maior nmero de mutantes no so utilizados
[Offutt et al. 1993]. Os resultados obtidos com a aplicao dessas estratgias
de mutao apontam que possvel reduzir expressivamente o custo de aplica-
o do critrio (ganhos prximos a 80%) sem redues significativas no escore
de mutao, que pode ficar muito prximo a 1, ou seja, quase 100% de mutan-
tes no-equivalentes mortos.
Para o contexto de teste de integrao, Delamaro et al. [2001a] estende-
ram o critrio Anlise de Mutantes, definindo o critrio Mutao de Interface,
que busca assegurar que as interaes entre as diferentes unidades sejam
testadas adequadamente. Foi proposto um conjunto de operadores de muta-
o cuja principal diferena para os operadores de mutao de unidade est
nos pontos do cdigo que so enfatizados para serem mutados. Para esses
novos operadores, esses pontos correspondem aos pontos de comunicao
entre duas unidades.

22
Teste de Software OO e OA: Teoria e Prtica

Conforme destacado anteriormente, novas abordagens e tecnologias de


desenvolvimento requerem a adaptao ou proposio de novas tcnicas e cri-
trios de teste adequados para esses contextos. Em particular, isso se aplica
s tcnicas e critrios de teste enfatizados nesta seo, no que diz respeito ao
teste de software OO e OA. Assim, faz-se necessrio o entendimento dos prin-
cipais conceitos e construes introduzidos pelo paradigma OO e pela POA.

1.2.1. Programao Orientada a Objetos


O paradigma OO consolidou-se nos anos 80 como o paradigma de escolha
para muitos desenvolvedores de produtos de software [Pressman 2000]. Seus
conceitos foram estendidos alm das tecnologias de apoio programao, re-
sultando desde em linguagens de modelagem at em modelos de processos
de desenvolvimento, como a UML e o Processo Unificado.
Os objetos constituem o principal elemento da orientao a objetos. Um
objeto pode ser definido como uma estrutura que retm informaes e um
conjunto de operaes, disponibilizando funcionalidades especficas para seus
usurios [Wirfs-Brock et al. 1990, Cox and Novobilski 1991]. As informaes
retidas em um objeto so conhecidas como atributos e as operaes so co-
nhecidas como mtodos (ou funes-membro em algumas linguagens como,
por exemplo, C++ [Stroustrup 1986]). Um objeto solicitado para realizar
uma determinada operao por meio do envio de uma mensagem (chamada
ao respectivo mtodo) que informa a esse objeto o que realizar. A resposta
gerada primeiramente pela escolha do mtodo que implementa a opera-
o solicitada; em seguida, a operao executada e o controle retornado
ao solicitante juntamente com uma possvel resposta mensagem recebida
[Cox and Novobilski 1991].
Uma classe consiste em uma entidade esttica que contm a definio
dos atributos de um objeto e a implementao das operaes disponveis para
ele. Um objeto uma instncia de uma classe gerada em tempo de execuo,
sendo que cada um dos objetos possui, a princpio, suas prprias instncias2
de cada um dos atributos e operaes. O conjunto corrente dos valores dos
atributos de um objeto caracteriza o estado desse objeto.
A visibilidade do estado do objeto controlada pelos mecanismos de ocul-
tamento de informaes, que esto diretamente relacionados com os mecanis-
mos de encapsulamento. O encapsulamento permite que um objeto responda
chamada de uma determinada operao, isentando o usurio de precisar
saber como essa operao executada e quais dados sero manipulados
para realizar essa operao. Em conjunto com o conceito de ocultamento de
informaes, que possibilita a remoo da visibilidade de determinados dados
e operaes encapsuladas em uma classe [Wirfs-Brock et al. 1990], pode-se
isolar a implementao dessa classe das demais. Dessa forma, permite-se
2Em geral, as linguagens OO permitem a definio de atributos e mtodos estticos, que
so compartilhados por todos os objetos instanciados a partir da classe em que so
definidos.

23
Masiero, Lemos, Ferrari e Maldonado

a realizao de manuteno no cdigo dessa classe sem a necessidade de


mudanas em outras classes do sistema que dependem dos seus servios.
A identificao de atributos e operaes comuns a vrias classes de obje-
tos permite a definio de uma nova classe que includa em um nvel superior
de uma hierarquia [Booch 1994]. Todas as classes que aparecem no nvel in-
ferior da hierarquia possuem, a princpio, todas as informaes e operaes de
classes que esto em nveis superiores do mesmo ramo da hierarquia. Tem-
se ento uma relao de herana, sendo que as classes em um nvel inferior
herdam as informaes e operaes definidas nas classes em nveis superi-
ores. Assim, novas classes no precisam ser completamente desenvolvidas,
mas podem herdar partes de funcionalidades de outras classes. A partir da
somente as funcionalidades especficas devem ser implementadas na classe
herdeira [Cox and Novobilski 1991].
Definidas as hierarquias de classes utilizando-se os mecanismos de he-
rana, o desenvolvedor pode usufruir de tipos polimrficos, em geral apoiado
pelas tecnologias de desenvolvimento de software OO. De acordo com a defi-
nio de Booch [1994] , polimorfismo representa o conceito da teoria dos tipos
na qual um simples nome pode denotar objetos instanciados a partir de diferen-
tes classes que so relacionadas a uma superclasse comum. Dessa forma,
um identificador de objeto do tipo de uma superclasse pode ser atribudo para
diferentes objetos instanciados a partir de suas subclasses. Isso permite que
um objeto envie uma mensagem sem saber para qual objeto a mensagem est
sendo enviada. Nesse caso, diferentes tipos de objetos podem estar definidos
para responder mensagem, cada um sua maneira [Wirfs-Brock et al. 1990].
No caso do uso de tipos polimrficos, o mecanismo de acoplamento dinmico
encarrega-se de resolver, em tempo de execuo, qual objeto responder
mensagem e qual mtodo ser executado.
Na Figura 1.2 apresentado um modelo de uma aplicao OO, adaptado
do trabalho do AspectJ Team [2003]. As classes presentes no modelo re-
presentam a funcionalidade bsica de um sistema de simulao de telefonia
no qual um cliente pode realizar e receber chamadas telefnicas locais ou
de longa distncia, e pode atender mais de uma chamada simultaneamente,
resultando em uma conferncia. Cada chamada simples (classes Local ou
LongDistance) possui uma conexo (classe Connection), e uma confern-
cia possui duas ou mais conexes.
Nesse exemplo, alguns dos conceitos introduzidos pela orientao a obje-
tos podem ser observados. Entre eles, os conceitos de classe, mtodos e atri-
butos, e a relao de herana estabelecida entre a superclasse Connection
e suas subclasses Local e LongDistance. Embora no seja explcito no
exemplo, o polimorfismo pode ser observado com a utilizao de um identifi-
cador declarado como sendo do tipo Connection, cuja instanciao pode ser
tanto do tipo Local quanto LongDistance. O tipo corrente instanciado e atri-
budo ao identificador decidido em tempo de execuo, e os comportamentos
apropriados so executados dependendo do tipo identificado.

24
Teste de Software OO e OA: Teoria e Prtica

1 -connections *
*
Call Connection
* -isMobile : Boolean
-state : int
*
+complete() : void
+drop() : void
1 -caller * +connects() : bool

Customer
-receiver -name : String
-phoneNumber : String
-areacode : int Local LongDistance
1
-password : String
-calls
+addCall()
+removeCall() -caller
+localTo()
+pickup()
+hangup() 1
+merge()

1 -receiver

Figura 1.2. Modelo de aplicao OO de telefonia

A linguagem Java [Sun Microsystems 2006] uma das linguagens de de-


senvolvimento de software OO que possibilita a aplicao dos principais con-
ceitos e recursos do paradigma. Java ser utilizada nos exemplos apresenta-
dos nas prximas sees deste texto.

1.2.2. Programao Orientada a Aspectos


Em meados dos anos 90, alguns pesquisadores constataram a existncia
de certos interesses que, mesmo com a utilizao da programao OO, no se
encaixavam em mdulos individuais, ficando espalhados por vrias unidades
do cdigo (tambm chamados de interesses transversais). A POA foi con-
cebida como uma proposta de resoluo desse problema, a partir do uso de
mecanismos que permitem o isolamento desses interesses.
O mecanismo de quantificao, introduzido pela POA, possibilita a imple-
mentao de mdulos isolados, os aspectos, que tm a capacidade de afetar
outros mdulos do sistema de forma transversal. Dessa forma, em POA um
nico aspecto pode contribuir para a implementao de diversos outros mdu-
los que implementam as funcionalidades bsicas, chamados de mdulos base
[Elrad et al. 2001].
A quantificao permite que a estrutura de implementao represente mais
adequadamente o projeto do sistema, pois sem ela certos tipos de interesses
tendem a emaranhar-se com outros e/ou espalharem-se por diversos mdulos.
Por exemplo, na Figura 1.3 so representados por meio de barras os diferentes
mdulos presentes na implementao OO do servidor Tomcat. As partes dos
mdulos que implementam o interesse de registro (logging) esto destacadas

25
Masiero, Lemos, Ferrari e Maldonado

nas barras. O espalhamento pode ser verificado pelo fato de diferentes m-


dulos possurem cdigo referente a esse interesse. O emaranhamento pode
ser verificado pelo fato da existncia de cdigo que implementa mais de uma
funcionalidade uma principal e a de registro em mdulos isolados. Dessa
forma existe uma separao de interesses no rigorosamente adequada, na
qual cada mdulo implementaria um nico interesse. Alguns tipos de emara-
nhamento e espalhamento podem ser resolvidos pelas tcnicas de software
tradicionais, entretanto, existem outros que, por sua prpria natureza, no fi-
cam bem modularizados quando utilizados esses paradigmas.

Figura 1.3. Estrutura de mdulos do Tomcat

Para que os aspectos possam adicionar comportamento em outros m-


dulos por meio do mecanismo de quantificao necessrio que se pos-
sam identificar pontos concretos da execuo de um programa. Esses pon-
tos so chamados pontos de juno (join points) do programa. Dessa forma,
uma linguagem orientada a aspectos deve fornecer um modelo por meio
do qual esses pontos possam ser identificados. Por exemplo, em AspectJ
[Kiczales et al. 2001, Kiczales and Mezini 2005], que consiste em uma exten-
so de Java que apia a POA, o modelo de pontos de juno baseado
nas construes da linguagem e os pontos so identificados por eventos do
tipo: chamada ou execuo de um mtodo com um certo nome (ou padro de
nome), leitura/escrita de atributos com um certo nome (ou padro de nome),
entre outros. AspectJ ser utilizada nos exemplos apresentados nas prximas
sees deste texto.
Um conjunto de pontos de juno ou somente conjunto de juno (point-
cut) identifica diversos pontos de juno em um sistema. Atravs do con-
junto de juno, um comportamento transversal (crosscutting behavior ) pode
ser definido nos pontos de juno identificados por ele. Esses comportamentos
transversais so implementados por meio de construes similares aos mto-
dos chamadas de adendos (advice), que podem executar antes, depois ou no
lugar dos pontos de juno identificados. Esses adendos so chamados de

26
Teste de Software OO e OA: Teoria e Prtica

adendos anteriores, posteriores e de contorno, respectivamente. Por exem-


plo, para implementar um interesse de registro que imprime uma mensagem
toda vez que um mtodo chamado, poderia ser utilizado um aspecto com
um adendo anterior que executaria toda vez que qualquer mtodo do sistema
fosse chamado.
Outro mecanismo importante introduzido pela POA a declarao intertipo
(ou introduo). Esse tipo de declarao permite que um aspecto introduza
membros (geralmente mtodos ou atributos) em algum outro tipo (classe ou
interface, por exemplo). Essas introdues so utilizadas quando o interesse
implementado no aspecto tambm utiliza atributos e mtodos que deveriam
fazer parte dos mdulos que o aspecto afeta.
Depois do cdigo-base (referente aos mdulos base) e os aspectos serem
codificados, necessrio um processo de combinao (weaving) dos mdulos
em uma aplicao executvel. Assim, toda linguagem de programao orien-
tada a aspectos deve contar tambm com um combinador (weaver ), respon-
svel por essa tarefa. A combinao pode ser feita em diversos momentos,
dependendo da deciso de implementao tomada para cada linguagem de
programao especfica. Por exemplo, a combinao dinmica o processo
de combinao que ocorre em tempo de execuo, enquanto que combinao
esttica ocorre em tempo de compilao.
Na Figura 1.4 apresentado o modelo da aplicao de telefonia mostrada
anteriormente para ilustrar a POO, acrescido de uma classe e trs aspectos. A
classe Timer implementa um cronmetro e utilizada no clculo do tempo de
uma chamada. As funcionalidades adicionadas pelos aspectos so descritas
abaixo:
Timing implementa o interesse de cronometragem e responsvel
por medir os tempos das conexes por cliente, iniciando e parando um
cronmetro da classe Timer associado a cada conexo;
Billing implementa o interesse de faturamento e responsvel por
garantir que cada conexo tenha um cliente pagador o cliente que inicia
a chamada e tambm que as chamadas locais, de longa distncia e de
celulares devem ser cobradas com taxas diversas;
TimerLog implementa um registro que imprime na tela os horrios em
que um cronmetro inicia e pra.
Ambos os aspectos Timing e Billing entrecortam a classe Call para
marcar os tempos das ligaes e tarifar cada uma com base na durao. Eles
possuem adendos posteriores que afetam os mtodos responsveis pelos in-
cio e fim das ligaes, j que esses so os pontos adequados para se marcar
os tempos e atribuir as tarifas.
O exemplo apresentado mostra os principais conceitos da POA. No entanto,
pode-se observar que os aspectos afetam poucos pontos da aplicao. Em
aplicaes maiores, em geral os aspectos afetam mais pontos, o que mais
interessante do ponto de vista da moduralizao de interesses transversais. De

27
Masiero, Lemos, Ferrari e Maldonado

aspect crosscuts crosscuts aspect crosscuts aspect


Billing Timing TimerLog

*
Call
Timer
* -startTime : long
-stopTime : long

-connections *
1
1 -caller

Connection
Customer
-receiver -isMobile : Boolean
-name : String -state : int
-phoneNumber : String *
+complete() : void
-areacode : int
1 +drop() : void
-password : String
* +connects() : bool
-calls
+addCall()
+removeCall() -caller
+localTo()
+pickup()
+hangup() 1
Local LongDistance
+merge()

1 -receiver

Figura 1.4. Modelo da aplicao de telefonia acrescido


dos aspectos

qualquer modo, o mecanismo pode ser entendido mesmo quando um conjunto


restrito de pontos afetado pelos aspectos.
AspectJ
A linguagem AspectJ uma extenso de Java criada para permitir a pro-
gramao orientada a aspectos de maneira genrica, no contexto dessa lingua-
gem. Basicamente, as novas construes do AspectJ consistem em: conjuntos
de juno (pointcut) que identificam conjuntos de pontos de juno; aden-
dos que definem o comportamento em um dado conjunto de juno; constru-
es para afetar estaticamente a estrutura dos mdulos bsicos do programa
(declaraes intertipos e que alteram a hierarquia de classes); e os aspec-
tos (aspect) que encapsulam as construes novas e as tradicionais de uma
classe Java3 .
Na Figura 1.5 mostrado um exemplo de conjunto de juno nomeado. Um
conjunto de juno pode ser definido como uma combinao de outros conjun-
tos de juno, utilizando operadores lgicos binrios e (&&) e ou (||). Alm
disso, o operador unrio de negao (!) tambm pode ser usado quando no
se quer capturar pontos de juno definidos por um conjunto de juno espe-
cfico. O primeiro conjunto de juno que compe atualiza, por exemplo,

3 A maior parte desta seo foi baseada no livro de Laddad [Laddad 2003].

28
Teste de Software OO e OA: Teoria e Prtica

captura todas as chamadas ao mtodo move da classe ElementoDeFigura,


que recebe dois inteiros como parmetros e no retorna nenhum valor.

modificador nome do conjunto


de acesso de juno assinatura a casar

public pointcut atualiza(): call(public void ElementoDeFigura.move(int,int)) ||


call(public void ElementoDeFigura.set*(..));

operador de
palavra-chave para tipo do conjunto composio
declarar um de juno
conjunto de juno

Figura 1.5. Exemplo de definio de conjunto de juno


nomeado

As notaes coringa *, .. e +, denotam respectivamente: qualquer


nmero de caracteres com exceo do ., qualquer nmero de caracteres in-
cluindo o ., e qualquer subclasse ou subinterface de um dado tipo (tipo no
AspectJ refere-se a uma classe, interface, tipo primitivo ou aspecto). Uma re-
ferncia completa sobre a linguagem AspectJ pode ser encontrada no website
desenvolvido pelo AspectJ Team [2003].
A seguir so discutidas as aplicaes das tcnicas de teste estrutural e
baseadas em defeitos no contexto de software OO e OA,enfatizando o teste
de unidade. Para o teste estrutural, so abordados os critrios baseados em
fluxo de controle e fluxo de dados, e para o teste baseado em defeitos, os
critrios baseados em Anlise de Mutantes.

1.3. Teste de Software OO e OA


A POO e a POA acrescentaram novas construes e conceitos aos j
conhecidos das linguagens de programao tradicionais e que, portanto, de-
vem ser explorados em abordagens de teste adequadas para esses contextos.
Neste texto so apresentadas tanto as aplicaes diretas das abordagens de
teste que foram propostas para o paradigma procedimental, quanto algumas
adaptaes necessrias para a aplicao de cada uma das tcnicas de teste
nesses novos contextos. Particularmente, so tratadas as tcnicas estrutural
(baseada em fluxo de controle e de dados) e baseada em defeitos (teste de
mutao).
Em geral, os critrios estruturais definidos para teste de unidade do para-
digma procedimental so diretamente aplicveis para o contexto de teste de
unidade OO, considerando-se os mtodos como as unidades a serem testa-
das. No entanto, para o teste de integrao, as propriedades especficas ao
paradigma OO tm maior impacto. Por exemplo, o mecanismo de acoplamento
dinmico pode trazer indecidibilidade para o teste, pois pode ser impossvel

29
Masiero, Lemos, Ferrari e Maldonado

predizer em tempo de compilao qual trecho de cdigo ser executado em


um determinado ponto. Como neste texto a nfase est no teste de unidade,
questes envolvendo essas dificuldades so discutidas em outros trabalhos
[Binder 1999, Alexander and Offutt 2000, Vincenzi 2004].
Por outro lado, em POA um dos principais mecanismos que devem ser
considerados nas abordagens de teste a quantificao. Quando aspectos
adicionam comportamento por meio dos conjuntos de juno em diversos m-
dulos do programa, a estrutura original dos mdulos-base modificada aps
a combinao, ou seja, novas interfaces so introduzidas dentro dos mdulos
[Kiczales and Mezini 2005]. Como os mtodos afetados tm sua estrutura in-
terna modificada, uma abordagem de teste adequada deve levar em conta e
explicitar essas alteraes. Na abordagem estrutural apresentada neste ca-
ptulo, o modelo de fluxo de controle e de dados adaptado para explicitar os
locais em que os adendos so executados nos mtodos. A partir desse modelo,
critrios de teste foram concebidos para fazer com que o testador concentre-se
nesses pontos, exercitando-os a partir dos casos de teste.

1.3.1. Fases do Teste de Software OO e OA


Com base nos conceitos de teste apresentados na seo anterior, pode-se
considerar que em programas OO as menores unidades a serem testadas so
os mtodos; e em programas OA, considerando-os como extenses de progra-
mas OO (como acontece nos escritos em AspectJ), os mtodos (inclusive os
intertipo declarados) e os adendos. A classe qual o mtodo pertence pode ser
vista como o driver do mtodo, pois sem ela no possvel execut-lo. Alm
disso, o aspecto somado a um ponto de juno que faa com que o adendo
seja executado podem ser vistos como o driver do adendo, pois sem eles no
possvel executar o adendo (a no ser que haja alguma infra-estrutura es-
pecial que permita a execuo do adendo como se fosse um mtodo, o que
descartaria a necessidade do ponto de juno). Alm disso, mtodos comuns
e intertipo declarados pertencentes a aspectos podem tambm necessitar de
infra-estrutura especial para serem executados em isolamento.
Por definio, uma classe engloba um conjunto de atributos e mtodos que
manipulam esses atributos; e um aspecto engloba basicamente conjuntos de
atributos, mtodos, adendos e conjuntos de juno. Assim sendo, conside-
rando uma nica classe ou um nico aspecto j possvel pensar em teste de
integrao. Mtodos da mesma classe ou mesmo aspecto, bem como adendos
e mtodos de um mesmo aspecto, podem interagir para desempenhar funes
especficas, caracterizando uma integrao que deve ser testada.
Levando em conta tais consideraes, e baseando-se no particionamento
utilizado por Sommerville [2001] e na abordagem de Harrold e Rother-
mel [1994] , a atividade de teste de programas OO e OA poderia ser dividida
nas seguintes fases [Lemos et al. 2004]:
1. Teste de Unidade: O teste de cada mtodo e adendo isoladamente,
tambm chamado de teste intra-mtodo ou intra-adendo.

30
Teste de Software OO e OA: Teoria e Prtica

2. Teste de Mdulo: O teste de uma coleo de unidades dependentes


unidades que interagem por meio de chamadas ou interaes com
adendos. Essa fase pode ser dividida nos seguintes tipos de teste (con-
siderando classes e aspectos como entidades diferentes):
Inter-mtodo: Consiste em testar cada mtodo pblico juntamente
com outros mtodos da mesma classe chamados direta ou indire-
tamente (chamadas indiretas so aquelas que ocorrem fora do es-
copo do prprio mtodo, dentro de um mtodo chamado em qual-
quer profundidade).
Adendo-mtodo: Consiste em testar cada adendo juntamente com
outros mtodos chamados por ele direta ou indiretamente.
Mtodo-adendo: Consiste em testar cada mtodo pblico junta-
mente com os adendos que o afetam direta ou indiretamente (con-
siderando que um adendo pode afetar outro adendo). Nesse tipo
de teste no considerada a integrao dos mtodos afetados com
os outros mtodos chamados por eles, nem com mtodos chama-
dos pelos adendos.
Inter-adendo: Consiste em testar cada adendo juntamente com ou-
tros adendos que o afetam direta ou indiretamente.
Inter-mtodo-adendo: Consiste em testar cada mtodo pblico jun-
tamente com os adendos que o afetam direta e indiretamente, e
com mtodos chamados direta ou indiretamente por ele. Esse tipo
de teste inclui os quatro primeiros tipos de teste descritos acima.
Intra-classe: Consiste em testar as interaes entre os mtodos p-
blicos de uma classe quando chamados em diferentes seqncias,
considerando ou no a interao com os aspectos.
Inter-classe: Consiste em testar as interaes entre classes dife-
rentes, considerando ou no a interao dos aspectos.
3. Teste de Sistema: A integrao de todos os mdulos, inclusive com o
ambiente de execuo, forma um subsistema ou um sistema completo.
Para essa fase geralmente utilizado o teste funcional.

1.3.2. Teste Estrutural de Programas OO


Neste texto, seguindo os trabalhos de Vincenzi [2004] e Vincenzi et al.
[2005], a linguagem Java utilizada para demonstrar os critrios estruturais
aplicados no contexto de programas OO. Mais especificamente, a idia via-
bilizar o teste estrutural de programas Java a partir do bytecode4 Java, permi-
tindo tambm, com isso, o teste estrutural de componentes5 para os quais os
4
Cdigo objeto de Java que consiste em instrues similares s instrues de linguagens
de montagem, porm que armazenam informaes de alto nvel das classes compiladas.
5Componente, nesse caso, definido como um conjunto de entidades de composio de
software com interface bem definida e especificada.

31
Masiero, Lemos, Ferrari e Maldonado

cdigos-fonte nem sempre se encontram disponveis.


Um modelo de fluxo de dados subjacente foi definido, caracterizando as
instrues de bytecode responsveis pela definio e/ou o uso de variveis. De
posse do modelo de fluxo de dados, um modelo de representao de programa
o Grafo Definio-Uso (DU) construdo, considerando os mecanismos de
tratamento de exceo, em geral, presentes nas linguagens OO. Desse modo,
o grafo DU utilizado para representar o fluxo de controle e o fluxo de dados
intra-mtodo, tanto da execuo normal do programa quanto na presena de
excees.
Um grafo DU de uma dada unidade u definido como um grafo dirigido DU
(u) = (N, E, s, O), tal que:
N representa o conjunto de ns de um grafo DU: N = {n|n corresponde
a uma seqncia linear de computaes, ou bloco de instrues, de u};
E N N = Er Ee o conjunto completo de arestas do DU. Cada aresta
e E representa a transferncia de controle que pode ocorrer entre dois
ns, tal que:
Er e Ee correspondem a dois subconjuntos disjuntos de arestas
regulares e de exceo, respectivamente:
Er o conjunto de arestas regulares definido como Er =
{(ni , n j )| o bloco de instrues em n j pode ser executado ime-
diatamente aps o bloco de instrues em ni e (ni , n j ) / Ee }.
Ee o conjunto de arestas de exceo definido como Ee =
{(ni , n j )| as instrues de ni esto no escopo de um tratador
de exceo que inicia em n j };
s N o n de entrada de u. s o nico n do grafo que no possui
nenhuma aresta de entrada;
O N o conjunto (possivelmente vazio) de ns de sada. Ou seja, cada
o O no possui nenhuma aresta de sada.
Para cada DU construdo a partir do bytecode Java, as componentes do
grafo so representadas da seguinte forma:
Ns regulares so representados por crculos com o rtulo contendo a
primeira instruo de bytecode do bloco;
Ns de chamada so representados por crculos duplos;
Ns de sada so representados por ns negritados;
Arestas de exceo so representadas por arestas tracejadas, repre-
sentando o fluxo de controle do ponto onde uma exceo gerada at o
primeiro n correspondente ao tratador daquela exceo.
Na Figura 1.6 mostrada parte do cdigo-fonte da aplicao de telefonia
discutida anteriormente nas sees 1.2.1 e 1.2.2. O construtor da classe Call
(linhas 518) ser utilizado para demonstrar o DU. A lgica envolvida no cons-
trutor consiste em checar se a chamada de longa distncia ou local e instan-
ciar um objeto Connection correspondente. Na Figura 1.7 mostrada parte

32
Teste de Software OO e OA: Teoria e Prtica

do bytecode gerado para o construtor da classe Call e o DU correspondente


(porm sem informaes de fluxo de dados).

1 public class Call {


2 private Customer caller, receiver;
3 private Vector connections = new Vector();
4
5 public Call(Customer caller, Customer
6 receiver, boolean iM)
7 {
8 this.caller = caller;
9 this.receiver = receiver;
10 Connection c;
11 if (receiver.localTo(caller)) {
12 c = new Local(caller, receiver, iM);
13 } else {
14 c = new LongDistance(caller,
15 receiver, iM);
16 }
17 connections.addElement(c);
18 }
19
20 public void pickup() {
21 ...
22 }
23
24 public boolean isConnected(){
25 ...
26 }
27
28 public void hangup(Customer c) {
29 for(Enumeration e =
30 connections.elements();
31 e.hasMoreElements();) {
32 ((Connection)e.nextElement()).drop();
33 }
34 }
35
36 public boolean includes(Customer c){
37 ...
38 }
39
40 public void merge(Call other){
41 ...
42 }
43 }

Figura 1.6. Parte do cdigo da classe Call da aplicao


de telefonia

0: aload_0
1: invokespecial java.lang.Object.<init> ()V (15)
4: aload_0
...
30: ifeq #48
33: new <telecom.Local> (32)
...
48: new <telecom.LongDistance> (36)
60: aload_0
...

Figura 1.7. Parte do bytecode e DU do construtor da classe Call

Uma vez que o grafo DU de cada mtodo tenha sido obtido, critrios po-

33
Masiero, Lemos, Ferrari e Maldonado

dem ser definidos para derivar diferentes requisitos de teste, os quais podem
ser utilizados tanto para avaliar a qualidade de um determinado conjunto de
teste quanto para a prpria gerao de dados de teste. Ao todo, oito critrios
de teste estruturais foram definidos. Vincenzi [Vincenzi 2004] optou por sepa-
rar os requisitos de teste em dois conjuntos disjuntos: (1) os que podem ser
cobertos durante a execuo normal do programa, denominados independen-
tes de exceo; e (2) os que para serem cobertos exigem, obrigatoriamente,
que uma exceo tenha sido lanada, denominados dependentes de exceo.
Desse modo, foram estabelecidos os seguintes critrios:
Todos-Ns:
Todos-Ns-Independentes-de-Exceo (Todos-Nsei ): Requer que
cada n n N do grafo DU que alcanvel por pelo menos um ca-
minho livre de exceo, ou seja, caminhos que no incluam arestas
de exceo, seja exercitado por algum caso de teste.
Todos-Ns-Dependentes-de-Exceo (Todos-Nsed ): Requer que
cada n n N do grafo DU que no alcanvel por pelo menos
um caminho livre de exceo seja exercitado por algum caso de
teste.
Todas-Arestas:
Todas-Arestas-Independentes-de-Exceo (Todas-Arestasei ): Re-
quer que cada aresta e E do grafo DU que alcanvel por pelo
menos um caminho livre de exceo seja exercitada por algum
caso de teste.
Todas-Arestas-Dependentes-de-Exceo (Todas-Arestased ): Re-
quer que cada aresta e E do grafo DU que no alcanvel por
pelo menos um caminho livre de exceo seja exercitada por algum
caso de teste.
Todos-Usos:
Todos-Usos-Independentes-de-Exceo (Todos-Usosei ): Requer
que seja exercitado pelo menos um caminho livre de exceo e
livre de definio para uma varivel definida em um n n para todo
n e toda aresta que possui um uso da mesma varivel e que possa
ser alcanada a partir de n.
Todos-Usos-Dependentes-de-Exceo (Todos-Usosed ): Requer
que seja exercitado pelo menos um caminho que no seja livre
de exceo mas que seja livre de definio para uma varivel defi-
nida em um n n para todo n e toda aresta que possui um uso da
mesma varivel e que possa ser alcanada a partir de n.
Todos-Potenciais-Usos [Maldonado 1991]:
Todos-Pot-Usos-Independentes-de-Exceo (Todos-Pot-Usosei ):
Requer que seja exercitado pelo menos um caminho livre de
exceo e livre de definio de uma varivel definida em um n n
para todo n e toda aresta possvel de ser alcanada a partir de n.

34
Teste de Software OO e OA: Teoria e Prtica

Todos-Pot-Usos-Dependentes-de-Exceo (Todos-Pot-Usosed ):
Requer que seja exercitado pelo menos um caminho que no seja
livre de definio mas que seja livre de definio para varivel
definida em um n n para todo n e toda aresta possvel de ser
alcanada a partir de n.
Apesar de se ter evidncias da viabilidade prtica da aplicao desses cri-
trios no teste intra-mtodo, estudos experimentais e tericos ainda so ne-
cessrios para avaliar detalhadamente os resultados [Vincenzi 2004]. Alm
disso, o teste estrutural por si s apresenta algumas limitaes em sua apli-
cao como, por exemplo, o problema da no-executabilidade, que acontece
quando no existem dados de teste que faam com que requisitos de teste em
particular sejam satisfeitos [Zhu et al. 1997].
Em particular o custo, eficcia e dificuldade de satisfao entre os critrios
so propriedades interessantes para serem investigadas nesse contexto. A
ferramenta JaBUTi que implementa os critrios apresentados aqui, e ser vista
na Seo 1.4, pode auxiliar na conduo de tais estudos, j que fornece uma
maneira automatizada de aplicao do teste estrutural.
Teste Estrutural de Integrao OO
At o presente momento, poucos trabalhos abordam o teste estrutu-
ral de integrao no contexto de programas OO. Entretanto, alguns es-
foros podem ser observados nessa direo [Harrold and Rothermel 1994,
Alexander and Offutt 2000]. Em particular, pode ser destacado o trabalho de
Harrold e Rothermel [1994], que adapta o teste de fluxo de dados para clas-
ses.
Assim como so testados os procedimentos de forma isolada (teste intra-
procedimental) e a interao entre eles (teste interprocedimental), a mesma
idia pode ser aplicada aos mtodos isolados de uma classe (teste intra-
mtodo abordado anteriormente), e aos mtodos de uma classe que intera-
gem entre si (teste inter-mtodo). Alm disso, no paradigma OO devem ser
consideradas tambm as interaes de fluxo de dados que acontecem quando
usurios de uma classe invocam seqncias de mtodos de maneira arbitrria
[Harrold and Rothermel 1994]. Por exemplo, em uma classe D, com atributo a e
mtodos m1 , m2 , m3 , deve ser analisado se as diferentes seqncias de chama-
das (por exemplo: m2 , m1 , m3 , m2 ) no provocam nenhum estado inconsistente
na classe D com relao ao atributo a.
Harrold e Rothermel consideram ainda o teste de fluxo de dados na inte-
grao das classes, que corresponde a um quarto nvel de teste, o inter-classe.
Esse tipo de teste envolve os pares def-uso em que a definio de uma vari-
vel se encontra em uma classe e o uso em outra. Detalhes sobre o teste de
integrao no so tratados aqui, j que neste texto dada nfase ao teste
de unidade. No entanto cabe destacar que esses problemas so objetos dos
trabalhos em andamento de alguns grupos de pesquisas em Engenharia de
Software.
Assim como na POO, para que os critrios estruturais possam ser aplicados

35
Masiero, Lemos, Ferrari e Maldonado

na POA, necessrio que sejam definidos os grafos de fluxo de controle e


de dados adequados. A seguir definem-se genericamente os grafos de fluxo
para programas OA e sua instanciao para a linguagem AspectJ, seguido da
definio dos critrios baseados nesses modelos.

1.3.3. Teste Estrutural de Programas OA


No fluxo de controle de programas OA, quando os aspectos definem com-
portamento em algum ponto do sistema por meio dos adendos, pode ser detec-
tado um novo tipo de interao. Quando o ponto de juno alcanado, o fluxo
de controle passado para o adendo do aspecto que afeta aquele ponto, retor-
nando ao final da execuo. Esse tipo de interao pode ser comparada com
uma chamada a mtodo, na qual o fluxo de controle passado para o mtodo
chamado, retornando ao final de sua execuo. Porm, a dependncia in-
versa, pois no primeiro caso o desenvolvedor do mtodo insere explicitamente
a chamada ao mtodo para atender os propsitos do mtodo em programao,
enquanto que no segundo caso so os aspectos os responsveis por definir
o comportamento extra em pontos de juno especficos. Como comentado
por Kiczales & Mezini [Kiczales and Mezini 2005], a composio de programas
OA define o surgimento de novas interfaces em diversos mdulos do sistema.
Dessa forma, esses novos elementos estruturais devem ser levados em conta
durante o teste estrutural desses programas.
O Grafo de Fluxo de Controle Orientado a Aspectos (AOCFG) um grafo
definido com o objetivo de apoiar o teste de unidade de um programa OA
[Lemos 2005]. Como possvel que em uma linguagem OA os adendos sejam
afetados por outros adendos como, por exemplo, em AspectJ o AOCFG
pode ser usado para representar tanto mtodos quanto adendos.
Um grafo AOCFG de uma dada unidade u tem as mesmas componentes
do DU definido para programas OO mais a componente C, ou seja, AOCFG
(u) = (N, E,C, s, O). A componente C definida como segue:
C N o conjunto (possivelmente vazio) de ns transversais que re-
presentam um n no qual ocorre uma interao com um adendo de um
dado aspecto. Esses ns representam as interfaces adicionadas pelos
aspectos para que os adendos sejam executados;
O Grafo Def-Uso Orientado a Aspectos (AODU) o AOCFG com informa-
es de definies e usos de variveis, para a aplicao de critrios baseados
em fluxo de dados. Como o grafo AODU um AOCFG estendido, necessria
apenas a construo do AODU para se derivar requisitos de teste tanto para
o fluxo de controle quanto para o fluxo de dados do programa. Neste texto o
grafo AODU definido a partir do bytecode Java produto da compilao/com-
binao de programas escritos na linguagem AspectJ, seguindo o trabalho de
Vincenzi et al. [Vincenzi et al. 2005], como discutido na seo anterior.
A representao grfica do AODU semelhante do DU apresentado na
seo anterior, porm, neste caso existe um tipo de n extra:
Ns transversais so representados por elipses tracejadas, com infor-

36
Teste de Software OO e OA: Teoria e Prtica

mao de qual tipo de adendo afeta aquele ponto (posterior, anterior ou


de contorno before, after ou around), e a qual aspecto pertence. Por
exemplo, se h uma interao com um adendo posterior de um aspecto
Aspect em um certo ponto, o n transversal correspondente adicionado
com a informao  a f ter Aspect .

1 public aspect Timing { 44 after(Customer cust) returning


2 public long Customer.totalConnectTime = 0; 45 (Connection conn): args(cust, ..)
3 46 && call(Connection+.new(..))
4 public long 47 { conn.payer = cust; }
5 getTotalConnectTime(Customer cust) { 48
6 return cust.totalConnectTime; 49 public abstract long Connection.callRate();
7 } 50
8 51 public long LongDistance.callRate() {
9 private Timer Connection.timer = 52 return LONG_DISTANCE_RATE;
10 new Timer(); 53 }
11 54
12 public Timer getTimer(Connection conn) { 55 public long Local.callRate() {
13 return conn.timer; 56 return LOCAL_RATE;
14 } 57 }
15 after (Connection c) returning () : 58
16 target(c) && call(void 59 after(Connection conn) returning () :
17 Connection.complete()) { 60 Timing.endTiming(conn) {
18 getTimer(c).start(); 61 long time = Timing.aspectOf().
19 } 62 getTimer(conn).getTime();
20 pointcut endTiming(Connection c): target(c) 63 long rate = conn.callRate();
21 && call(void Connection.drop()); 64 long cost = rate * time;
22 65 if (conn.isMobile()) {
23 after(Connection c) returning () : 66 if (conn instanceof LongDistance) {
24 endTiming(c) { 67 long receiverCost =
25 getTimer(c).stop(); 68 MOBILE_LD_RECEIVER_RATE * time;
26 c.getCaller().totalConnectTime += 69 conn.getReceiver().addCharge
27 getTimer(c).getTime(); 70 (receiverCost);
28 c.getReceiver().totalConnectTime += 71 }
29 getTimer(c).getTime(); 72 }
30 } 73 getPayer(conn).addCharge(cost);
31 } 74 }
32 75
33 public aspect Billing { 76 public long Customer.totalCharge = 0;
34 declare precedence: Billing, Timing; 77 public long getTotalCharge(Customer cust)
35 public static final long LOCAL_RATE = 3; 78 { return cust.totalCharge; }
36 public static final long 79
37 LONG_DISTANCE_RATE = 10; 80 public void Customer.addCharge(long charge)
38 public static final long 81 { totalCharge += charge; }
39 MOBILE_LD_RECEIVER_RATE = 5; 82 }
40
41 public Customer Connection.payer;
42 public Customer getPayer(Connection conn)
43 { return conn.payer; }

Figura 1.8. Cdigo dos aspectos Timing e Billing da


aplicao de telefonia

Na Figura 1.8 mostrada outra parte do cdigo-fonte da aplicao de tele-


fonia apresentada nas Sees 1.2.1 e 1.2.2, referente aos aspectos Timing e
Billing. O mesmo construtor da classe Call (Figura 1.6), utilizado na seo
anterior para mostrar o DU, utilizado para demonstrar o AODU. Como o as-
pecto Billing possui um adendo para atribuir a tarifa da chamada ao cliente
no momento da instanciao de alguma classe filha de Connection (linhas
4548), o construtor de Call afetado por esse adendo nos dois pontos em
que as instncias de Local (linha 12 na Figura 1.6) e LongDistance (linhas
1415 na Figura 1.6) so criadas. Na Figura 1.9 mostrada parte do bytecode

37
Masiero, Lemos, Ferrari e Maldonado

gerado para o construtor da classe Call e o AODU correspondente (porm


sem informaes de fluxo de dados).
0 aload_0
1 invokespecial #15 <Method Object()>
4 aload_0
...
27 invokevirtual #30 <Method boolean
localTo(telecom.Customer)>
30 ifeq 78
33 aload_1
...
52 invokespecial #34 <Method
Local(telecom.Customer,
telecom.Customer, boolean)>
...
69 invokevirtual #110 <Method void
ajc$afterReturning$telecom_Billing$
1$8a338795(
telecom.Customer, telecom.Customer,
boolean, telecom.Connection)>
72 nop
73 astore 4
75 goto 120
78 aload_1
...
97 invokespecial #37 <Method
LongDistance(telecom.Customer,
telecom.Customer, boolean)>
...
114 invokevirtual #110 <Method void
ajc$afterReturning$telecom_Billing$
1$8a338795(
telecom.Customer, telecom.Customer,
boolean, telecom.Connection)>
117 nop
118 astore 4
120 aload_0
121 getfield #20 <Field java.util.Vector
connections>
124 aload 4
126 invokevirtual #41 <Method void
addElement(java.lang.Object)>
129 return

Figura 1.9. Bytecode e AODU do construtor da classe Call

Com base no AODU, trs critrios de teste estruturais foram definidos


[Lemos 2005, Lemos et al. 2005]:
Todos-Ns-Transversais (Todos-Nsc ): Requer que cada n c C seja
exercitado por pelo menos um caso de teste. Ou seja, este critrio exige
que cada execuo de adendo que ocorre na unidade afetada seja al-
canada.
Todas-Arestas-Transversais (Todas-Arestasc ): Requer que cada aresta
transversal, ou seja, cada aresta que tem como n origem ou destino um
n transversal, seja exercitada por pelo menos um caso de teste.
Todos-Usos-Transversais (Todos-Usosc ): Requer que cada par def-uso
cujo uso est em um n transversal seja exercitado por pelo menos um
caso de teste.
Os critrios definidos anteriormente para a POO continuam sendo vlidos
tambm nesse contexto pois, no caso da linguagem AspectJ, programas OA
so superconjuntos de programas OO. Assim, tambm se torna interessante
definir uma estratgia de aplicao desses critrios, baseada na dificuldade

38
Teste de Software OO e OA: Teoria e Prtica

de satisfao dos critrios e em outras propriedades. Porm, at o presente


momento, no se observam investigaes nesse sentido, o que indica uma
necessidade de trabalhos futuros.
Alm disso, importante salientar que os mesmos problemas encontrados
anteriormente para a POO continuam valendo para a POA (como, por exemplo,
o problema da no-executabilidade).
Teste Estrutural de Integrao OA
Os mesmos problemas encontrados no teste de integrao de programas
OO tambm so encontrados no contexto de software OA. Alm disso, com a
introduo dos aspectos como mdulos de programao, novas questes de-
vem ser investigadas no que diz respeito integrao interna desses mdulos
(por exemplo, adendos de um aspecto que interagem com mtodos do mesmo
aspecto); integrao com as classes; e integrao de aspectos com aspectos
(quando esses interagem em pontos de juno comuns).
Considerando um programa OA, um defeito em particular pode estar locali-
zado em trs locais diferentes: na lgica de um adendo; na lgica dos mdulos
base; ou na lgica de composio (no caso deste texto no conjunto de juno),
que define onde os adendos iro executar [Alexander 2003]. Como um adendo
uma construo similar a mtodo, e o programa-base no geral composto
de classes, poucas adaptaes so necessrias para a aplicao do teste es-
trutural nessas unidades, como visto anteriormente. Entretanto, nota-se uma
necessidade maior de adaptaes no que diz respeito ao teste da lgica de
composio (ou dos conjuntos de juno), para o teste eficaz das regras de
composio, procurando identificar defeitos no que diz respeito seleo dos
pontos de juno.
Detalhes sobre o teste de integrao OA no so tratados aqui, j que neste
texto dada nfase ao teste de unidade. No entanto, na Seo 1.3.5 algumas
outras questes gerais so discutidas, sob a tica do teste de mutao.
A seguir so discutidas as adaptaes do teste de mutao para sua apli-
cao nos contextos de software OO e OA.

1.3.4. Teste de Mutao de Programas OO


As linguagens de programao possuem caractersticas prprias que impli-
cam na definio dos operadores de mutao, embora os mesmos conceitos
possam ser aplicados independentemente da linguagem na qual o produto a
ser testado esteja escrito [Delamaro et al. 2001]. Por outro lado, linguagens
com construes sintticas semelhantes possibilitam que operadores de mu-
tao possam ser aplicados indistintamente em produtos gerados nessas lin-
guagens, ou requerem alteraes simples na descrio dos operadores. Por
exemplo, as linguagens C e C++ permitem a declarao de variveis globais,
porm o conceito de varivel global no existe na linguagem Java. Portanto,
a princpio, operadores de mutao para programas C que fazem alteraes
relacionadas a esses elementos so aplicveis a programas C++, mas no a
programas Java. Por outro lado, tanto em Java quanto em C++, os atributos de

39
Masiero, Lemos, Ferrari e Maldonado

uma classe podem ser considerados como variveis globais, pois so visveis
para todos os mtodos pertencentes classe. Dessa forma, o conjunto de va-
riveis globais na aplicao de teste de mutao em programas Java pode ser
restringido ao conjunto dos atributos da classe em teste.
Para o teste de mutao de programas OO, escritos em C++ e Java, Vin-
cenzi [2004] avaliou a aplicabilidade de conjuntos de operadores de mutao
definidos originalmente para serem aplicados em teste de mutao de pro-
gramas C [Agrawal et al. 1989, Delamaro 1997, Delamaro et al. 2001] e Java
[Ma et al. 2002]. Vincenzi procurou adaptar a aplicao destes operadores
para os nveis de teste intra-mtodo, inter-mtodo e inter-classe. Cada um dos
conjuntos foi avaliado e, quando necessrio, foram propostas as adaptaes
necessrias.
Vale ressaltar que cada linguagem possui particularidades. Sendo assim,
dependendo do tipo de defeito que se deseja enfatizar no teste, novos ope-
radores de mutao podem ser definidos para model-los. Por exemplo, em
alguns pontos, a linguagem C++ pode ser considerada mais flexvel do que
Java pela possibilidade de se definir heranas mltiplas e sobrecargas de ope-
radores. Novos operadores de mutao poderiam ser propostos para tratar
exclusivamente esses defeitos.
A aplicao do teste de mutao de programas OO nos nveis de unidade
e integrao discutida a seguir. Os conjuntos de operadores para cada fase
de teste so apresentados, inclusive suas aplicabilidades em programas Java
e C++.
Teste de Mutao de Unidade (Teste Intra-Mtodo)
Agrawal et. al [1989] definiram um conjunto de 80 operadores de mutao
para teste de unidade de programas escritos na linguagem C. Os operado-
res so distribudos em quatro classes: cinco operadores para mutao de
constantes, 16 operadores para mutao de comandos, 12 operadores para
mutao de variveis e 47 operadores para mutao de operadores6 . Cada
classe de operadores formada por um conjunto de operadores que modelam
diferentes defeitos em estruturas de um mesmo tipo. Por exemplo, o operador
SWDD (while Replacement by do-while), que pertence classe de ope-
radores para mutao de comandos, substitui o comando de iterao while
pelo comando do-while. A letra inicial do nome de cada operador possibilita
a identificao da classe qual esse operador pertence, sendo elas C cons-
tante, S comando (statement), V varivel e O operador. As demais letras
so utilizadas para descrever o operador, como no exemplo apresentado.
Analisando a aplicabilidade dos 80 operadores para as linguagens C++ e

6Neste texto, o termo operador utilizado tanto para se referir a um operador de muta-
o quanto a um operador tradicional de uma linguagem de programao (por exemplo,
operadores aritmticos ou lgicos). Se a utilizao do termo causar ambigidade, o
termo completo (por exemplo, operador de mutao ou operador aritmtico) ser uti-
lizado.

40
Teste de Software OO e OA: Teoria e Prtica

Java, Vincenzi [2004] concluiu que todos so aplicveis a C++, por se tratar de
um superconjunto da linguagem C, e 59 so aplicveis a Java. Dentre os ope-
radores no aplicveis a Java, esto um operador que trata do comando goto,
cinco operadores que so especficos para mutao de ponteiros e registros
(struct), e 15 operadores de mutao de operadores.
Vincenzi tambm definiu sete novos operadores para tratar de caractersti-
cas especficas da linguagem Java, sendo que trs desses tambm so aplic-
veis a C++. Os quatro novos operadores exclusivos para Java foram definidos
para tratar dos comandos break e continue, enquanto os trs aplicveis
tanto a Java quanto C++ foram definidos para tratar de variveis de referncia.
A descrio desses operadores apresentada na Tabela 1.1. A descrio dos
demais operadores pode ser encontrada no trabalho de Agrawal et al. [1989].

Tabela 1.1. Novos operadores de mutao de unidade de


programas OO
Operador Descrio
VGCR Troca uma referncia de classe por todas as demais referncias de classe globais
do mesmo tipo.
VLCR Troca uma referncia de classe por todas as demais referncias de classe locais
do mesmo tipo.
VCAR Troca as referncias a um atributo da classe por todas as outras referncias a
atributos do mesmo tipo.
SBLR Troca os comandos break, com ou sem rtulos, pelos demais comandos break
e break rotulados vlidos da unidade.
SCLR Troca os comandos continue, com ou sem rtulos, pelos demais comandos
continue e continue rotulados vlidos da unidade.
SLBC Troca os rtulos dos comandos break pelos rtulos dos comandos continue
vlidos da unidade.
SLCB Troca os rtulos dos comandos continue pelos rtulos dos comandos break
vlidos da unidade.

O conjunto final de operadores ficou totalizado em 66 operadores para Java


e 83 operadores para C++. Na Tabela 1.2 (adaptada do trabalho de Vincenzi
[2004]) est sumarizado o conjunto resultante de operadores. A primeira co-
luna da tabela contm as siglas que representam o nome dos operadores. O
smbolo  indica que esse operador no estava presente no conjunto inicial.
A segunda e terceira coluna so utilizadas para indicar se o operador aplic-

vel para as linguagens Java e C++, respectivamente. O smbolo significa
que o operador aplicvel para a respectiva linguagem, e significa que
o operador no aplicvel. Ainda, M significa que o operador no direta-
mente aplicvel, mas foi adaptado gerando um ou mais dos novos operadores
propostos por Vincenzi.
Na Figura 1.10 apresentado um exemplo de aplicao de um operador
de mutao em um mtodo de um programa Java. O mtodo merge utilizado
nesse exemplo foi obtido do classe Call, que compe a aplicao de telefonia
introduzida na seo 1.2.1. O operador utilizado o operador SMVB (Move
Brace Up or Down), que move o } que encerra um bloco de comandos de

41
Masiero, Lemos, Ferrari e Maldonado

Tabela 1.2. Operadores de mutao de unidade


Operador Java C++

CGCR Operador Java C++
CLCR
OAAA
CGSR
OAAN
CLSR
OABA
CRCR
OABN
Total 5/5 5/5 OAEA
(a) Mutao de Constantes
OALN
OARN

Operador Java C++ OASA

VASM OASN

VDTR OBAA

VGAR OBAN

VGPR M OBBA

 VGCR OBBN

VGSR OBEA

VGTR M OBLN


VLAR OBNG

VLPR M OBRN


 VLCR OBSA

VLSR OBSN

VLTR M OCNG

VSCR M OCOR

 VCAR OEAA

VTWD OEBA
Total 10/15 15/15 OESA
(b) Mutao de Variveis OIPM
OLAN
Operador Java C++ OLBN

OLLN
SBRC OLNG
SBRn
OLRN
SCRB OLSN
SCRn
OMMO
SDWD OPPO
SGLR M
ORAN
 SBLR ORBN
 SCLR
ORLN

 SLBC ORRN
 SLCB
ORSN

SMTC OSAA
SMTT
OSAN
SMVB OSBA
SRSR
OSBN
SSDL OSEA
SSOM
OSLN
SSWM OSRN
STRI
OSSA
STRP OSSN
SWDD
Total 32/47 47/47
Total 19/20 16/20
(d) Mutao de Operadores
(c) Mutao de Comandos

42
Teste de Software OO e OA: Teoria e Prtica

um lao para cima e para baixo, excluindo ou incluindo comandos no bloco.


O cdigo original do adendo apresentado na Figura 1.11(a), e os mutantes
gerados so apresentados nas Figuras 1.11(b), 1.11(c) e 1.11(d).

public void merge(Call other){ public void merge(Call other){


for(Enumeration e = for(Enumeration e =
other.connections.elements(); other.connections.elements();
e.hasMoreElements();){ e.hasMoreElements();){
Connection conn = Connection conn =
(Connection)e.nextElement(); (Connection)e.nextElement();
other.connections.removeElement(conn); other.connections.removeElement(conn);
connections.addElement(conn); }
} connections.addElement(conn);
} }

(a) Mtodo Original (b) Mutante 1


public void merge(Call other){ public void merge(Call other){
for(Enumeration e = for(Enumeration e =
other.connections.elements(); other.connections.elements();
e.hasMoreElements();){ e.hasMoreElements();){
Connection conn = }
(Connection)e.nextElement(); Connection conn =
} (Connection)e.nextElement();
other.connections.removeElement(conn); other.connections.removeElement(conn);
connections.addElement(conn); connections.addElement(conn);
} }

(c) Mutante 2 (d) Mutante 3


Figura 1.10. Exemplo de mutao de um mtodo escrito em Java

Na Seo 1.4.3 apresentado um exemplo de aplicao do teste de muta-


o de unidade em programas OO, inclusive com os casos de teste que podem
ser utilizados para matar os mutantes gerados e a identificao de possveis
mutantes equivalentes.
Teste de Mutao de Integrao (Teste inter-mtodo e inter-classe)
Vincenzi [2004] adaptou o critrio Mutao de Interface
[Delamaro et al. 2001] para o teste de mutao inter-mtodo. Conforme
apresentado na Seo 1.2, a principal diferena entre os operadores de
mutao de unidade e mutao de interface est nos pontos do cdigo
que so enfatizados para serem mutados. Os operadores de mutao de
interface esto relacionados aos pontos de comunicao entre duas unidades.
Considerando duas unidades u1 e u2 , com u1 chamando u2 , as mutaes so
realizadas tanto nos pontos em que u1 faz chamadas a u2 quanto nos pontos
relacionados interface de u2 como, por exemplo, variveis de retorno de u2
e variveis globais. Os operadores foram agrupados de acordo com o local
de aplicao, podendo ser tanto na unidade chamadora quanto na unidade
chamada. Operadores do Grupo I, num total de 24, so aplicados em u2 .
Operadores do Grupo II so aplicados em u1 , totalizando nove operadores
nesse grupo. A descrio desses operadores pode ser encontrada no trabalho
de Delamaro [1997] e Delamaro et al. [2001a].
Os operadores de mutao de interface foram originalmente definidos para

43
Masiero, Lemos, Ferrari e Maldonado

o teste de programas C. Assim, Vincenzi [2004] analisou sua aplicabilidade


para o teste de programas OO escritos nas linguagens C++ e Java. De acordo
com a anlise, todos os operadores so aplicveis para as duas linguagens,
bastando redefinir os conjuntos de variveis envolvidos na aplicao dos ope-
radores.
Ainda no contexto de teste de integrao, Ma et al. [2002] definiram um
conjunto de operadores de mutao para o teste inter-classe. Esses operado-
res foram projetados para tratar de defeitos especficos aos novos conceitos e
construes introduzidos pelo paradigma OO, entre eles encapsulamento, he-
rana e polimorfismo. O conjunto, composto por 24 operadores, foi elaborado
com base em taxonomias de defeitos apresentadas nos trabalhos de Kim et
al. [2000], Offutt et al. [2001] e Chevalley e Thvenod-Fosse [2003]. Alm de
apresentarem uma taxonomia de defeitos, Kim et al. e Chevalley e Thvenod-
Fosse propuseram tambm operadores de mutao para modelar os defeitos
presentes em suas taxonomias. Ressalta-se que os defeitos enfatizados por
Kim et al. contemplam defeitos de programas OO em geral, embora tenham
sido baseados na linguagem Java. J os defeitos enfatizados por Chevalley e
Thvenod-Fosse referem-se exclusivamente a programas escritos em Java.
Esses operadores foram includos no trabalho de Ma et al., que estenderam
o conjunto definindo novos operadores, alm de redefinir alguns j existentes.
Os 24 operadores resultantes foram agrupados de acordo com as caracters-
ticas e conceitos do paradigma OO e os defeitos relacionados, sendo eles:
ocultamento de informao (um operador); herana (sete operadores); poli-
morfismo (quatro operadores); sobrecarga de mtodos (quatro operadores);
caractersticas especficas de Java (quatro operadores); e enganos comuns de
programao (quatro operadores). A descrio desses operadores pode ser
encontrada no trabalho de Ma et al. [2002].
Analisando-se a aplicabilidade desses grupos de operadores em progra-
mas implementados em C++ e Java, Vincenzi [2004] constatou que apenas o
grupo de operadores que tratam de caractersticas especficas da linguagem
Java no aplicvel para programas escritos em C++. O restante dos opera-
dores aplicvel tanto a C++ quanto a Java.

1.3.5. Teste de Mutao de Programas OA


Conforme enfatizado na seo 1.2, alm dos conceitos do teste de mu-
tao poderem ser aplicados em tipos variados de artefatos conceitualmente
executveis de software como, por exemplo, cdigo-fonte de programas e es-
pecificaes formais, as similaridades entre diferentes linguagens propiciam a
reutilizao de operadores de mutao indistintamente entre as linguagens ou
com pequenas alteraes entre suas implementaes.
A aplicao do teste de mutao de programas OA nos nveis de unidade
e integrao discutida a seguir. A linguagem utilizada como base a Aspe-
ctJ, embora os conceitos possam ser aplicados a programas escritos em ou-
tras linguagens OA.

44
Teste de Software OO e OA: Teoria e Prtica

Teste de Mutao de Unidade OA


Embora a linguagem AspectJ introduza novas construes que implemen-
tam os conceitos relacionados orientao a aspectos, as unidades de cdigo
executveis implementadas nos aspectos (adendos, mtodos e mtodos inter-
tipo declarados) so escritas em cdigo Java nativo. Dessa forma, os operado-
res de mutao de unidade de programas Java, apresentados na seo 1.3.4,
podem ser diretamente aplicados em unidades de programas AspectJ.
Para efeito de ilustrao, na Figura 1.11 apresentado um exemplo de
aplicao de um operador de mutao em um adendo escrito em AspectJ. O
cdigo utilizado nesse exemplo foi obtido do aspecto Timing, que compe a
aplicao de telefonia introduzida nas sees anteriores deste texto. O ope-
rador utilizado o operador OAAA, que realiza a troca de cada operador de
atribuio aritmtica pelos demais operadores e atribuio aritmtica dispon-
veis na linguagem. No caso da linguagem Java, os operadores de atribuio
aritmtica disponveis so +=, -=, *=, /= e %=. O cdigo original do
adendo apresentado na Figura 1.11(a), e os mutantes gerados so apresen-
tados na Figura 1.11(b) (somente a linha alterada apresentada para cada
mutante gerado).

1 public aspect Timing {


2 ... linha 6:
3 after(Connection c) returning () : c.getCaller().totalConnectTime -=
4 endTiming(c) { c.getCaller().totalConnectTime *=
5 getTimer(c).stop(); c.getCaller().totalConnectTime /=
6 c.getCaller().totalConnectTime += c.getCaller().totalConnectTime %=
7 getTimer(c).getTime();
8 c.getReceiver().totalConnectTime += linha 8:
9 getTimer(c).getTime(); c.getReceiver().totalConnectTime -=
10 } c.getReceiver().totalConnectTime *=
11 } c.getReceiver().totalConnectTime /=
c.getReceiver().totalConnectTime %=

(a) Adendo Original (b) Mutantes Gerados


Figura 1.11. Exemplo de mutao de um adendo escrito
em AspectJ

Na Seo 1.4.4 apresentado um exemplo de aplicao do teste de muta-


o de unidade em programas OA, inclusive com os casos de teste que podem
ser utilizados para matar os mutantes gerados e a identificao de possveis
mutantes equivalentes.
Teste de Mutao de Integrao OA
Em relao ao teste de integrao, novas questes esto envolvidas. Mais
especificamente, essas questes esto relacionadas s construes introduzi-
das pelo POA, at ento no presentes no teste de programas desenvolvidos
sob os paradigmas procedimental e OO.
Critrios definidos para o teste de integrao, tanto para teste estrutural
[Linnenkugel and Mllerburg 1990, Vilela et al. 1999] quanto para o teste de

45
Masiero, Lemos, Ferrari e Maldonado

mutao [Delamaro et al. 2001], enfatizam os pontos de comunicao entre


duas unidades e as variveis envolvidas nessa comunicao. As interfaces en-
tre essas unidades, no caso de programas procedimentais ou OO, so bem
definidas, e os pontos de comunicao (por exemplo, uma chamada a um m-
todo e o retorno aps sua execuo) so explcitos no cdigo.
J no caso de programas OA, os conceitos de quantificao e de inconsci-
ncia [Filman and Friedman 2000] possibilitam a execuo dos comportamen-
tos transversais (implementados em aspectos) em diversos pontos da execu-
o do programa, sem a necessidade da insero de chamadas explcitas a
esses comportamentos. O prprio fluxo de execuo do programa pode ser
completamente alterado. A aplicao de um operador de mutao especfico
para atuar nos elementos que definem um conjunto de juno pode aumen-
tar ou restringir a abrangncia desse conjunto, podendo implicitamente definir
novas interfaces entre as unidades do programa, ou remover uma ou mais in-
terfaces anteriormente estabelecidas.
Nesse contexto, o teste de integrao pode ser observado sob dois pontos
de vista. O primeiro como sendo uma adaptao do critrio Mutao de In-
terface [Delamaro et al. 2001], de forma a enfatizar os pontos de comunicao
entre as unidades nos diversos tipos de interao apresentados na seo 1.3.1.
A interface de um adendo, por exemplo, pode ser caracterizada pelos argumen-
tos e objetos capturados pelo ponto de juno relacionado a esse adendo, e os
operadores definidos para aplicao do critrio poderiam ser aplicados nesses
pontos, alm dos pontos j definidos originalmente no critrio.
O segundo, por sua vez, relaciona-se com outros conceitos e construes
introduzidos pela orientao a aspectos, por exemplo, conjuntos de juno e
precedncia de aspectos. Existe ainda a necessidade de se definir um con-
junto de operadores de mutao especfico para atuar sobre esses elementos.
Nessa linha, uma proposta inicial foi apresentada por Mortensen e Alexander
[2004], envolvendo a aplicao de uma abordagem mista de teste estrutural
e de mutao para programas OA escritos em AspectJ, tentando mapear os
tipos de defeitos enfatizados taxonomia de defeitos proposta por Alexander
et al. [2004]. Especificamente em relao ao teste de mutao, so definidos
trs operadores de mutao que atuam: na definio de conjuntos de juno;
aumentando ou reduzindo sua abrangncia; e na precedncia de aspectos. No
entanto, somente uma definio de alto-nvel dos operadores apresentada,
no entrando em detalhes de como esses operadores podem ser aplicados.
Ressalta-se ainda que essas so idias iniciais, existindo a necessidade de
uma formalizao, de modo a possibilitar a aplicao sistemtica do critrio e
o desenvolvimento de mecanismos de apoio automatizado.
A seguir so apresentados exemplos da aplicao dos critrios discutidos
no decorrer deste texto. Para os critrios estruturais, so discutidas as ferra-
mentas JaBUTi (OO) e JaBUTi/AJ (OA), incluindo uma breve apresentao de
seus aspectos operacionais. Apresenta-se tambm uma aplicao prtica do
teste de mutao em programas OO e OA.

46
Teste de Software OO e OA: Teoria e Prtica

1.4. Automatizao e Exemplos de Aplicao


A atividade de teste, se realizada manualmente, geralmente propensa a
erros e limitada a aplicaes de pequeno porte. Nesse contexto, ferramentas
de teste podem auxiliar na automatizao dessa tarefa, permitindo a aplicao
prtica de critrios de teste, o teste de programas maiores e mais complexos, o
apoio a estudos experimentais e a transferncia das tecnologias de teste para
a indstria. Alm disso as ferramentas de teste possibilitam a realizao de
testes de regresso, utilizados quando evolues so feitas no programa e os
casos de teste armazenados so executados novamente para a validao da
aplicao modificada [Domingues 2002].
Para o teste de programas OO em C++ e Java, existem vrias ferramen-
tas e, entre elas, podem ser citadas: C++ Test, JProbe Suite, JTest, Pano-
rama C/C++, Panorama for Java e xSuds Toolsuite. A maioria delas apia
o teste estrutural e algumas delas apiam o teste funcional, alm de apre-
sentarem algumas outras funcionalidades de anlise do programa em teste
[Domingues 2002].
Nesta seo so utilizadas as ferramentas JaBUTi e JaBUTi/AJ, constru-
das para apoiar o teste estrutural de unidade de programas OO e OA, para
demonstrar a automatizao da atividade de teste utilizando critrios estrutu-
rais. Em seguida apresenta-se a aplicao do teste de mutao de unidade em
programas OO e OA com o auxlio de exemplos.

1.4.1. A Ferramenta JaBUTi


A ferramenta JaBUTi (Java Bytecode Understanding and Testing)
[Vincenzi 2004, Vincenzi et al. 2005], desenvolvida no ICMC/USP em colabo-
rao com a Fundao Eurpedes Soares da Rocha (UNIVEM) de Marlia/SP
e a Universidade do Texas em Dallas/USA, visa a ser um ambiente completo
para o entendimento e teste de programas e componentes Java. A idia b-
sica da ferramenta viabilizar o teste de programas Java em nvel de bytecode,
possibilitando, com isso, no somente o teste de programas Java para os quais
o cdigo-fonte esteja disponvel, mas tambm o teste de componentes Java.
JaBUTi fornece ao testador diferentes critrios de teste estruturais para a
anlise de cobertura, um conjunto de mtricas estticas para se avaliar a com-
plexidade das classes que compem do programa/componente, e implementa,
ainda, algumas heursticas de particionamento de programas que visam a au-
xiliar a localizao de defeitos. Neste texto, dada nfase parte responsvel
pela anlise de cobertura. Mais informaes sobre as demais funcionalidades
da ferramenta podem ser obtidas no trabalho de Vincenzi [2004].
Considerando o suporte anlise de cobertura de programas Java, a fer-
ramenta implementa atualmente oito critrios de teste intra-mtodos definidos
por Vincenzi [2004] , sendo quatro critrios de Fluxo de Controle (Todos-Nsei ,
Todos-Nsed , Todas-Arestasei ,Todas-Arestased ) e quatro critrios de Fluxo de
Dados (Todos-Usosei , Todos-Usosed , Todos-Pot-Usosei e Todos-Pot-Usosed ).
No que diz respeito a esses critrios, estudos demonstram que, para

47
Masiero, Lemos, Ferrari e Maldonado

Figura 1.12. Gerenciador de projetos de teste da JaBUTi

programas C, conjuntos de teste que determinam as maiores coberturas


tm uma maior probabilidade de detectar defeitos no programa em teste
[Wong and Mathur 1995]. O mesmo se aplica para Java sem perda de ge-
neralidade. Uma vez que, em geral, existe um grande nmero de requisitos
de teste para serem cobertos, uma caracterstica interessante da ferramenta
JaBUTi a utilizao de cores diferentes dando indicaes ao testador para
facilitar a gerao de casos de teste que satisfaam um maior nmero de re-
quisitos em menor tempo. As diferentes cores representam diferentes pesos
que so associados aos requisitos de teste de cada critrio. Informalmente,
os pesos correspondem ao nmero de requisitos de teste que so cobertos
quando um requisito de teste particular satisfeito. Assim, cobrir os requisitos
de teste de maior peso leva a um aumento na cobertura de forma mais rpida.
Para ilustrar os aspectos operacionais da JaBUTi, utilizada a mesma apli-
cao de simulao de telefonia apresentada ao longo deste texto. Em parti-
cular utilizada a classe Call, cujo cdigo foi parcialmente listado na Seo
1.3.2.
Considerando a utilizao da ferramenta JaBUTi via interface grfica, o
primeiro passo para conduzir uma atividade de teste a criao de um projeto
de teste, o qual contm informaes sobre as classes a serem testadas. Para
a criao do projeto de teste o testador deve, primeiramente, fornecer o nome
de uma classe base a partir da qual as demais classes relacionadas sero
identificadas. Fornecido o nome da classe base, a ferramenta exibe a janela
do Gerenciador de Projeto (Project Manager), como ilustrado na Figura 1.12.
Do lado esquerdo dessa janela encontra-se o conjunto completo das classes
que foram identificadas a partir da classe base e que podem ser selecionadas
para serem testadas. No exemplo, foi escolhida a classe Call.
Pressionando o boto Ok, JaBUTi cria um novo projeto (Telecom.jbt no
exemplo), constri o grafo DU para cada mtodo de cada classe a ser testada,
deriva os requisitos de teste de cada critrio, calcula o peso desses requisitos,
e apresenta na tela o bytecode de uma das classes sendo testadas, como
ilustrado na Figura 1.13(a). Alm da visualizao do bytecode, a ferramenta
oferece ainda a visualizao do cdigo fonte (quando se encontra disponvel) e

48
Teste de Software OO e OA: Teoria e Prtica

do grafo DU de cada mtodo (Figura 1.13(b)).

(a) Bytecode inicial

(b) Cdigo-fonte e DU iniciais

Figura 1.13. Telas iniciais da JaBUTi

49
Masiero, Lemos, Ferrari e Maldonado

Uma vez que o conjunto de requisitos de teste de cada critrio foi determi-
nado, tais requisitos podem ser utilizados para avaliar a qualidade de um con-
junto de teste existente e/ou para desenvolver novos casos de teste visando a
melhorar a cobertura dos requisitos pelo conjunto de teste. O testador pode,
por exemplo, decidir criar um conjunto de teste com base em critrios de teste
funcionais ou mesmo gerar um conjunto de teste ad-hoc e avaliar a cobertura
desse conjunto de teste em relao a cada um dos critrios de teste estruturais
da JaBUTi. Por outro lado, o testador pode visualizar o conjunto de requisitos
de teste de cada critrio gerado para cada um dos mtodos das classes sendo
testadas, verificar quais deles ainda no foram cobertos por algum caso de
teste e ento desenvolver um novo caso de teste que satisfaa tais requisitos.
As Figuras 1.14(a) e 1.14(b) ilustram parte dos requisitos de teste do construtor
da classe Call gerados pelos critrios Todos-Nsei e Todos-Usosei , respecti-
vamente.

(a) Todos-Nsei (b) Todos-Usosei

Figura 1.14. Requisitos de teste para dois dos critrios


livres de exceo, para o construtor da classe Call

Ainda, como pode ser observado na Figura 1.14, a ferramenta permite ao


testador ativar/desativar diferentes combinaes de requisitos de teste, bem
como marcar um determinado requisito de teste como no-executvel quando
no existir um caso de teste capaz de cobri-lo.
A ttulo de ilustrao de um processo de teste para a aplicao de telefonia,
pode-se utilizar os critrios para testar cada uma das classes envolvidas no
sistema. Por exemplo, para a classe Call, cria-se conjuntos de teste para
cobrir cada um dos requisitos de teste indicados pela ferramenta, focando-se
em cada um dos mtodos.
Na Figura 1.15(a) mostrado o cdigo do mtodo includes da classe
Call utilizado para verificar se um dado cliente est ou no includo em uma

50
Teste de Software OO e OA: Teoria e Prtica

(a) Cdigo-fonte (b) DU

Figura 1.15. Cdigo-fonte e DU do mtodo includes da


classe Call, com os requisitos de teste referentes ao
critrio Todas-Arestasei destacados

chamada. O atributo connections da classe Call utilizado para manter


uma lista dos clientes includos na chamada. Para saber se um dado cli-
ente faz parte da chamada, basta fazer um lao sobre os elementos do vetor,
verificando se o cliente corresponde a algum desses elementos. Na Figura
1.15(a) a ferramenta destaca no cdigo do mtodo os requisitos referentes
ao critrio Todas-Arestasei , depois de todos os ns do mtodo terem sido co-
bertos a partir de dois casos de teste (os dois primeiros mostrados na Figura
1.16). Os casos de teste so construdos com o apoio do framework JUnit
[Beck and Gamma 2006], podendo ser importados para execuo na JaBUTi.
Para cobrir o requisito ainda no satisfeito com relao ao critrio Todas-
Arestasei , o testador pode verificar qual aresta ainda no foi coberta e, para
isso, pode utilizar o grafo DU (mostrado na Figura 1.15(b)). Observando esse
grafo e analisando o cdigo-fonte e o bytecode, percebe-se que a aresta que
falta a 1337, referente condio em que a varivel booleana result tem
valor verdadeiro (ou seja, o cliente est includo na chamada), e o vetor ainda
no foi percorrido inteiramente. Assim, para cobri-la basta criar um caso de
teste no qual o cliente faz parte da chamada e est localizado no incio do
vetor, com outros tambm conectados no restante do vetor. O terceiro caso de
teste apresentado na Figura 1.16 cobre esta condio.
Ao executar esse caso de teste para exercitar tal aresta, percebe-se que o
programa no retorna, entrando em lao infinito. Com isso detectado um de-
feito no programa: como atribudo o valor verdadeiro para a varivel result
nas primeiras iteraes do lao, nas prximas iteraes, o teste lgico ou
avaliado como verdadeiro e, por causa da avaliao curto-circuito utilizada em
Java (ou seja, quando a primeira parte da expresso avaliada como verda-
deira, a segunda no chega a ser avaliada), o mtodo nextElement que itera
sobre os elementos de connections no mais chamado. Assim, a condi-
o de sada do mtodo, que o trmino da iterao sobre o vetor, nunca
satisfeita, fazendo com que o lao nunca termine.
Esse exemplo evidencia a utilidade da ferramenta de teste no auxlio para

51
Masiero, Lemos, Ferrari e Maldonado

public void testIncludesTrue() {


Customer jim = new Customer("Jim", 650, "1111");
Customer mik = new Customer("Mik", 500, "1112");
Call c = new Call(jim, mik, false);
c.pickup();
assertTrue(c.includes(mik));
}

public void testIncludesFalse() {


Customer jim = new Customer("Jim", 650, "1111");
Customer mik = new Customer("Mik", 500, "1112");
Customer luk = new Customer("Luke", 400, "1113");
Call c = new Call(jim, mik, false);
c.pickup();
assertFalse(c.includes(luk));
}

//Cobrindo Todas-Arestas-ei
public void testIncludesEdge() {
Customer jim = new Customer("Jim", 650, "1111");
Customer mik = new Customer("Mik", 500, "1112");
Customer john = new Customer("John", 500, "1113");
Customer cris = new Customer("Cris", 500, "1114");
Customer carl = new Customer("Carl", 500, "1115");
Customer luke = new Customer("Luke", 500, "1116");

Call c1 = new Call(jim, mik, false);


c1.pickup();
Call c2 = new Call(john, cris, false);
c2.pickup();
Call c3 = new Call(carl, luke, false);
c3.pickup();
c1.merge(c2);
c1.merge(c3);
assertTrue(c1.includes(jim));
}

Figura 1.16. Casos de teste para cobrir Todos-Nsei e


Todas-Arestasei do mtodo includes

encontrar defeitos no software. Outro ponto importante a ser notado que a


aplicao dos critrios seria muito complicada sem a utilizao de uma ferra-
menta como a JaBUTi, pois realizar tal atividade manualmente sem incorrer
em erros , em geral, impraticvel.
Os critrios baseados em fluxo de dados no foram explorados nesta seo
devido a limitaes de espao. Entretanto, em geral, tais critrios mostram-se
bastante eficientes para auxiliar o entendimento e o teste dos sistemas, pois
so mais difceis de serem satisfeitos do que os critrios baseados em fluxo de
controle.

1.4.2. A Ferramenta JaBUTi/AJ


A ferramenta JaBUTi foi estendida para possibilitar a utilizao dos critrios
estruturais orientados a aspectos, ou seja, os critrios Todos-Ns-Transversais,
Todas-Arestas-Transversais e Todos-Usos-Transversais [Lemos 2005]. Nessa
verso a ferramenta foi denominada JaBUTi/AJ.
Para o teste estrutural da aplicao de telefonia em sua verso OA, pri-
meiramente deve-se criar um projeto na ferramenta JaBUTi/AJ, escolhendo os
arquivos relevantes, inclusive os aspectos, similarmente ao que foi feito com
a ferramenta JaBUTi. Nesta seo nfase dada aos critrios OA aborda-

52
Teste de Software OO e OA: Teoria e Prtica

dos e, desse modo, os mdulos interessantes a serem testados so: a classe


Call e o aspecto Timing, pois eles so afetados por adendos. Na Figura 1.17
so mostrados os elementos requeridos para o critrio Todos-Ns-Transversais
(All-Nodes-c), para todas as unidades sendo testadas. A classe Call aparece
com cinco requisitos de teste, o que quer dizer que ela afetada por adendos
em cinco pontos; e o aspecto Timing aparece com dois elementos requeridos.
interessante notar que a informao dada por esse critrio valiosa no s
para o testador mas tambm para o desenvolvedor pois, com os elementos
requeridos, o testador/desenvolvedor sabe exatamente em quais classes/as-
pectos os adendos esto definindo comportamento e tambm a quantidade de
adendos afetando as classes/aspectos.

Figura 1.17. Elementos requeridos para o critrio todos-


ns-transversais para a aplicao de telefonia

Para testar a classe Call a partir do critrio Todos-Ns-Transversais, ne-


cessrio saber quais mtodos esto sendo afetados pelos adendos. Para isso,
o testador pode visualizar tanto o bytecode quanto o cdigo-fonte e observar
em quais pontos a ferramenta indica os requisitos de teste. Na Figura 1.18
mostrada a tela da ferramenta JaBUTi/AJ com o cdigo-fonte da classe Call,
com os requisitos de teste referentes ao critrio Todos-Ns-Transversais des-
tacados no cdigo. Na verdade, percebe-se que, nesse caso, os elementos
requeridos acabam sendo os pontos de juno afetados pelos adendos. Por
exemplo, no caso do construtor de Call, deve haver algum adendo que define
comportamento nas chamadas aos construtores de LongDistance e Local.
Isso pode ser conferido visualizando o grafo AODU do construtor de Call (Fi-
gura 1.19(a)). Os ns transversais 33 e 78 indicam que um adendo posterior

53
Masiero, Lemos, Ferrari e Maldonado

do aspecto Billing afeta aqueles pontos (esse o adendo responsvel por


atribuir a fatura pela ligao ao cliente chamador). A partir da o critrio Todos-
Ns-Transversais requer que esses ns sejam cobertos, ou seja, que existam
casos de teste que os exercitem.

Figura 1.18. Cdigo-fonte da classe Call com os elementos


requeridos do critrio Todos-Ns-Transversais
em destaque

Analisando a lgica do construtor de Call, para cobrir os ns transversais


so necessrios dois casos de teste: um que realize uma chamada local e ou-
tro que realize uma chamada de longa distncia. Como o adendo que atribui
a fatura ao cliente chamador deve distinguir entre chamadas locais e de longa
distncia, aqui o testador j pode ter evidncias de que o aspecto est imple-
mentado corretamente, j que o adendo afeta o ponto onde uma chamada local
criada e tambm o ponto onde uma chamada de longa distncia criada. A
partir dos dois casos de teste, que testaro se o mtodo realmente cria uma
chamada local quando os clientes possuem o mesmo cdigo de rea e uma
chamada de longa distncia quando os clientes possuem cdigos de rea di-
ferentes, possvel cobrir os dois ns transversais referentes s execues do
adendo para os dois casos.
Quanto ao mtodo hangup, tambm afetado por adendos, a lgica a se-

54
Teste de Software OO e OA: Teoria e Prtica

guinte: quando a ligao concluda, necessrio terminar todas as conexes


relacionadas a ela, o que feito por meio de um lao. Como o adendo do as-
pecto de cronometragem deve parar o cronmetro toda vez que uma conexo
terminada, ele executado depois de cada chamada ao mtodo drop. J
no caso do aspecto de faturamento, este tambm deve afetar o mesmo ponto,
pois cada vez que uma conexo terminada, tambm necessrio calcular o
custo da chamada e atribu-lo fatura do cliente chamador. Na Figura 1.19(b)
mostrado o grafo AODU do mtodo hangup, com as execues dos adendos
representadas pelos ns transversais 11 e 32. Para cobrir esses ns trans-
versais necessrio um caso de teste que inicie uma chamada e a termine.
Quando o mtodo hangup chamado, os adendos so executados no trmino
de cada conexo relacionada com a chamada.
Aqui o testador tambm pode ter evidncias de que os aspectos esto im-
plementados corretamente e, alm disso, que esto interagindo de forma cor-
reta j que o aspecto de faturamento acionado aps o aspecto de cronome-
tragem. Nota-se que a precedncia dos aspectos importante nesse caso,
pois se o aspecto de faturamento agisse antes do aspecto de cronometragem,
o sistema falharia. Esse tipo de defeito faz parte do modelo de defeitos de-
finido por Alexander [Alexander et al. 2004]. Tambm importante notar que
esse caso evidencia a eficincia da abordagem, no que diz respeito a auxiliar
na descoberta desse tipo de defeito.

(a) Grafo AODU do construtor da classe (b) Grafo AODU do mtodo hangup
Call

Figura 1.19. Grafos AODU do construtor e do mtodo da


classe Call

55
Masiero, Lemos, Ferrari e Maldonado

O mtodo pickup utilizado para simular o momento em que o cliente tira


o telefone do gancho e completa a ligao, sendo afetado pelo adendo poste-
rior do aspecto Timing. Isso feito para que o aspecto inicie o cronmetro
toda vez que uma conexo completada, por meio do adendo. Para cobrir o
n transversal necessrio apenas um caso de teste que execute o mtodo,
completando uma ligao e verificando que o cronmetro iniciado.

No caso do aspecto Timing, os dois adendos posteriores que iniciam e


terminam o cronmetro so afetados pelos adendos posteriores do aspecto
TimerLog, para que seja registrado o tempo de incio e parada do cronme-
tro. Nesses pontos podem ser observadas interaes aspecto-aspecto, pois o
aspecto TimerLog afeta o aspecto Timing. Para cobrir os ns transversais
necessrio um caso de teste que inicie e termine uma ligao, sensibilizando
os adendos do aspecto Timing que iniciam e terminam o cronmetro e, por
conseqncia, sensibilizando tambm o aspecto TimerLog.

A ttulo de ilustrao, trs defeitos referentes POA foram inseridos na apli-


cao de telefonia: um relacionado com a precedncia dos aspectos (foi tro-
cada a precedncia dos aspectos, ou seja Billing Timing, por Timing
Billing) e dois relacionados com as definies dos conjuntos de juno (mais
especificamente aos conjuntos de juno definidos em Timing, que identifi-
cam o incio e o fim das ligaes).

Para detectar esses defeitos, o testador pode utilizar o grafo AODU do m-


todo hangup: com a alterao do conjunto de juno que define quando as
chamadas terminam, o adendo de Billing que calcula a fatura deveria afetar
esse ponto, mas percebe-se a falta do n transversal. Com um caso de teste
que faa asseres com relao fatura, o defeito revelado.

O segundo defeito tambm relacionado com definies de conjuntos de


juno, porm agora sobre o conjunto de juno que define o incio da cha-
mada. Tal defeito pode ser detectado no teste do mtodo pickup, no qual
deveria ser iniciado o cronmetro da chamada. Com um caso de teste que
verifica o tempo da conexo o defeito revelado.

O terceiro defeito refere-se precedncia dos aspectos e tambm pode


ser detectado no teste do mtodo hangup, pois ainda assim a fatura no ser
calculada corretamente, j que o cronmetro s parado depois da execuo
do adendo de fatura (e o clculo da fatura depende da execuo do adendo de
cronometragem). Esse defeito tambm pode ser evidenciado a partir da obser-
vao do AODU, pois o n transversal referente ao adendo do clculo da fatura
precede o referente ao adendo da cronometragem (inverso ao que aparece na
Figura 1.19(b), com o programa correto). Dois casos de teste escritos no JUnit,
que cobrem os ns transversais e que auxiliam o testador a encontrar os trs
defeitos, esto apresentados na Figura 1.20.

56
Teste de Software OO e OA: Teoria e Prtica

public void testCoverCCNodesPickup() {


Customer jim = new Customer("Jim", 650, "3361-1111");
Customer mik = new Customer("Mik", 650, "3361-1112");

Call c1 = new Call(jim, mik, false);

c1.pickup();
assertTrue(Timing.aspectOf().getTotalConnectTime(jim) == 0);
}

public void testCoverCCNodesCallHangup() {


Customer jim = new Customer("Jim", 650, "3361-1111");
Customer mik = new Customer("Mik", 650, "3361-1112");

Call c1 = new Call(jim, mik, false);

c1.pickup();
wait(2.0);
c1.hangup();
assertTrue((Timing.aspectOf().getTotalConnectTime(jim) > 150) &&
(Timing.aspectOf().getTotalConnectTime(jim) < 250));
assertTrue((Billing.aspectOf().getTotalCharge(jim) > 450) &&
(Billing.aspectOf().getTotalCharge(jim) < 750));
}

Figura 1.20. Casos de teste que revelam os defeitos re-


lacionados com a POA

1.4.3. Aplicao do Teste de Mutao de Unidade em Programas


OO
Nesta seo apresentado um exemplo de aplicao do teste de mutao
de unidade de programas OO escritos em Java. Nesse exemplo utilizada a
mesma aplicao de simulao de telefonia apresentada ao longo deste texto.
Em particular, so consideradas somente as funcionalidades da verso OO da
aplicao, cujo teste estrutural foi apresentado na seo 1.4.1 e no qual se
identificou um defeito no mtodo includes da classe Call. Esse defeito foi
corrigido na aplicao utilizada nesta seo.
Na Figura 1.21 destaca-se parte do cdigo da classe Call. Em particular,
apresenta-se a implementao do mtodo construtor da classe e do mtodo
merge. Para efeito ilustrativo, alguns dos operadores de mutao de unidade
apresentados na Seo 1.3.4 so selecionados para serem aplicados nesses
mtodos. A descrio desses operadores apresentada na Tabela 1.3.

Tabela 1.3. Operadores selecionados para o exemplo


Operador Descrio
SSDL Remove cada um dos comandos da unidade.
STRI Troca o comando if(e) pelos comandos if(trap_on_true(e)) e
if(trap_on_false(e)), interrompendo a execuo do programa quando
a expresso testada for verdadeira ou falsa, respectivamente.
OCNG Insere operador de negao em predicados (comandos condicionais).
SMTC Introduz, no incio de cada lao, uma chamada funo
false_after_nth_loop_iteration(N), que fora o encerramento
do lao aps N iteraes.

Nas Figuras 1.22, 1.23, 1.24 e 1.25 so apresentados os mutantes gerados

57
Masiero, Lemos, Ferrari e Maldonado

1 public class Call {


2 private Customer caller, receiver;
3 private Vector connections = new Vector();
4
5 public Call(Customer caller, Customer receiver,
6 boolean iM) {
7 this.caller = caller;
8 this.receiver = receiver;
9 Connection c;
10 if (receiver.localTo(caller)) {
11 c = new Local(caller, receiver, iM);
12 } else {
13 c = new LongDistance(caller, receiver, iM);
14 }
15 connections.addElement(c);
16 }
17
18 ...
19
20 public void merge(Call other){
21 for(Enumeration e =
22 other.connections.elements();
23 e.hasMoreElements();){
24 Connection conn =
25 (Connection)e.nextElement();
26 other.connections.removeElement(conn);
27 connections.addElement(conn);
28 }
29 }
30 }

Figura 1.21. Parte do cdigo da classe Call da aplicao


de telefonia

por cada um dos operadores da Tabela 1.3. Algumas observaes sobre a


aplicao dos operadores nesse exemplo:
O smbolo > no incio de uma linha indica a linha ou trecho de cdigo
que foi modificado;
A aplicao de alguns operadores pode gerar mutantes que no compi-
lam. Por exemplo, o operador SSDL, quando aplicado ao mtodo cons-
trutor, gerou trs desses mutantes7 . Dependendo da estratgia ado-
tada pelo testador (e possivelmente implementada em uma ferramenta
de apoio), esses mutantes podem ou no serem gerados durante a apli-
cao do respectivo operador de mutao ou, ainda, serem automatica-
mente marcados como mortos durante a execuo do teste.
Os mutantes marcados com eq foram identificados como equivalentes.
Os mtodos utilitrios (por exemplo, trap_on_true(e)) foram imple-
mentadas como mtodos estticos de uma classe auxiliar (Util), con-
forme se pode observar nos mutantes gerados.
Para o operador SMTC, a funo false_after_nth_loop_iter-
ation(N) pode ser configurada com qualquer valor para N. Nesse
exemplo, a funo foi configurada com N=2.
Os casos de teste apresentados na Figura 1.26 foram implementados com
o objetivo de matar os mutantes dos mtodos construtor e merge gerados com
7 Os mutantes no compilveis no foram listados por questes de espao.

58
Teste de Software OO e OA: Teoria e Prtica

public Call(Customer caller, Customer receiver, public Call(Customer caller, Customer receiver,
boolean iM) { boolean iM) {
> this.caller = caller;
this.receiver = receiver; >
Connection c; Connection c;
if (receiver.localTo(caller)) { if (receiver.localTo(caller)) {
c = new Local(caller, receiver, iM); c = new Local(caller, receiver, iM);
} else { } else {
c = new LongDistance(caller, receiver, iM); c = new LongDistance(caller, receiver, iM);
} }
connections.addElement(c); connections.addElement(c);
} }

M1eq M2eq
public Call(Customer caller, Customer receiver, public void merge(Call other){
boolean iM) { >
this.caller = caller; }
this.receiver = receiver;
Connection c;
if (receiver.localTo(caller)) {
c = new Local(caller, receiver, iM);
} else {
c = new LongDistance(caller, receiver, iM);
}
>
}

M3 M4
public void merge(Call other){ public void merge(Call other){
for(Enumeration e = for(Enumeration e =
other.connections.elements(); other.connections.elements();
e.hasMoreElements();){ e.hasMoreElements();){
Connection conn = Connection conn =
(Connection)e.nextElement(); (Connection)e.nextElement();
other.connections.removeElement(conn); >
> connections.addElement(conn);
} }
} }

M5 M6
Figura 1.22. Mutantes gerados pelo operador SSDL

public Call(Customer caller, Customer receiver, public Call(Customer caller, Customer receiver,
boolean iM) { boolean iM) {
this.caller = caller; this.caller = caller;
this.receiver = receiver; this.receiver = receiver;
Connection c; Connection c;
> if (Util.trap_on_true( > if (Util.trap_on_false(
receiver.localTo(caller))) { receiver.localTo(caller))) {
c = new Local(caller, receiver, iM); c = new Local(caller, receiver, iM);
} else { } else {
c = new LongDistance(caller, receiver, iM); c = new LongDistance(caller, receiver, iM);
} }
connections.addElement(c); connections.addElement(c);
} }

M7 M8
Figura 1.23. Mutantes gerados pelo operador STRI

a aplicao dos operadores apresentados na Tabela 1.3. Na Tabela 1.4 apre-


sentada a relao dos mutantes mortos por cada caso de teste. Como se pode

59
Masiero, Lemos, Ferrari e Maldonado

public Call(Customer caller, Customer receiver, public void merge(Call other){


boolean iM) { for(Enumeration e =
this.caller = caller; other.connections.elements();
this.receiver = receiver; > !e.hasMoreElements();){
Connection c; Connection conn =
> if (!receiver.localTo(caller)) { (Connection)e.nextElement();
c = new Local(caller, receiver, iM); other.connections.removeElement(conn);
} else { connections.addElement(conn);
c = new LongDistance(caller, receiver, iM); }
} }
connections.addElement(c);
}

M9 M10
Figura 1.24. Mutantes gerados pelo operador OCNG

public void merge(Call other){


for(Enumeration e = other.connections.elements();
e.hasMoreElements();){
> if (Util.false_after_nth_loop_iteration(2)) {
Connection conn = (Connection)e.nextElement();
other.connections.removeElement(conn);
connections.addElement(conn);
}
}
}

M11
Figura 1.25. Mutante gerado pelo operador SMTC

observar, um nico caso de teste pode matar mais de um mutante.

Tabela 1.4. Casos de teste X mutantes OO mortos


Caso de Teste Mutante
testCallConstruction M3 / M7
testCallMerging01 M3 / M7 / M4 / M5 / M10
testCallMerging02 M7 / M4 / M6 / M10
testCallInstantiation01 M7
testCallInstantiation02 M8
testCallType() M7 / M8 / M9

Aps construo e a execuo dos seis casos de teste apresentados, o


nico mutante vivo foi o gerado pelo operador SMTC (mutante M11). Durante
a construo de um caso de teste para matar esse mutante, observou-se uma
falha na sua execuo. Ao tentar realizar duas combinaes (merging) con-
secutivas de chamadas, observou-se no segundo merging que as conexes
da chamada recebida como parmetro (duas, nesse caso de teste) no eram
todas transferidas para a chamada corrente. O caso de teste projetado apre-
sentado na Figura 1.27.
O cdigo do mtodo merge original apresentado novamente na Figura
1.28(a). Durante a depurao do cdigo, detectou-se o defeito na linha 5. Du-

60
Teste de Software OO e OA: Teoria e Prtica

public void testCallConstruction() { public void testCallMerging01() {


Customer jim = new Customer("Jim", 650, Customer jim = new Customer("Jim", 650,
"3361-1111"); "3361-1111");
Customer mik = new Customer("Mik", 650, Customer mik = new Customer("Mik", 650,
"3361-1112"); "3361-1112");
Call c1 = new Call(jim, mik, false); Customer joe = new Customer("Joe", 650,
assertTrue(c1.includes(jim)); "3361-1113");
} Call c1 = new Call(jim, mik, false);
Call c2 = new Call(mik, joe, false);
public void testCallInstantiation01() { c1.merge(c2);
Customer jim = new Customer("Jim", 650, assertTrue(c1.includes(joe));
"3361-1111"); }
Customer mik = new Customer("Mik", 650,
"3361-1112"); public void testCallMerging02() {
try { Customer jim = new Customer("Jim", 650,
Call c1 = new Call(jim, mik, false); "3361-1111");
assertTrue(true); Customer mik = new Customer("Mik", 650,
} "3361-1112");
catch (RuntimeException e) { Customer joe = new Customer("Joe", 650,
assertTrue(false); "3361-1113");
} Call c1 = new Call(jim, mik, false);
} Call c2 = new Call(mik, joe, false);
c1.merge(c2);
public void testCallInstantiation02() { assertFalse(c2.includes(mik));
Customer jim = new Customer("Jim", 650, }
"3361-1111");
Customer kat = new Customer("Kat", 750, public void testCallType() {
"3361-1112"); Customer jim = new Customer("Jim", 650,
try { "3361-1112");
Call c1 = new Call(jim, kat, false); Customer mik = new Customer("Mik", 650,
assertTrue(true); "3361-1113");
} ByteArrayOutputStream baos =
catch (RuntimeException e) { new ByteArrayOutputStream();
assertTrue(false); PrintStream ps = new PrintStream(baos, true);
} System.setOut(ps);
} Call c1 = jim.call(mik, false);
String s1 = baos.toString().trim();
assertEquals(s1,
"[new local connection " +
"from Jim(650) to Mik(650)]");
}

Figura 1.26. Casos de teste criados para matar mutantes OO

1 public void testCallMerging03() {


2 Customer jim = new Customer("Jim", 650, "3361-1111");
3 Customer mik = new Customer("Mik", 650, "3361-1112");
4 Customer joe = new Customer("Joe", 650, "3361-1113");
5 Call c1 = new Call(joe, mik, false);
6 Call c2 = new Call(mik, jim, false);
7 Call c3 = new Call(mik, joe, false);
8 c1.merge(c2);
9 c3.merge(c1);
10 assertTrue(c3.includes(jim));
11 }

Figura 1.27. Caso de teste projetado para matar o mutante M11

rante a primeira iterao do lao, a conexo corrente removida do vetor de


conexes enumeradas. Com essa remoo, a conexo seguinte passa a cons-
tar na posio 0 do vetor. Entretanto, durante a segunda iterao, o ndice
criado para percorrer esse vetor j estava apontando para a segunda posio
do vetor, o que no estado corrente apontava para um elemento nulo. Portanto,
nesse caso, uma conexo no era transferida para a chamada resultante da
combinao (objeto corrente). Na Figura 1.28(b) apresentado uma possibili-

61
Masiero, Lemos, Ferrari e Maldonado

dade do mtodo merge corrigido.

1 public void merge(Call other){ 1 public void merge(Call other){


2 for(Enumeration e = 2 for(Enumeration e =
3 other.connections.elements(); 3 other.connections.elements();
4 e.hasMoreElements(); ){ 4 e.hasMoreElements(); ){
5 Connection conn = 5 Connection conn =
6 (Connection)e.nextElement(); 6 (Connection)e.nextElement();
7 other.connections.removeElement(conn); 7 connections.addElement(conn);
8 connections.addElement(conn); 8 }
9 } 9 other.connections.clear();
10 } 10 }

(a) (b)
Figura 1.28. Mtodo merge original e modificado

importante destacar que durante a aplicao do teste estrutural de uni-


dade na classe Call, todos os requisitos gerados para o mtodo merge foram
cobertos com um caso de teste. Entretanto, a aplicao do teste estrutural no
foi suficiente para revelar o defeito encontrado nesse mtodo. Destaca-se com
isso a importncia de se aplicar diferentes tcnicas e critrios de teste de forma
complementar, objetivando-se a melhoria de qualidade do produto final.
Ressalta-se tambm que aps a deteco e correo de um defeito no c-
digo do artefato original, como ocorrido nesse exemplo, o processo do teste de
mutao deve passar novamente pelos quatro passos apresentados na seo
1.2. Nesse caso, a gerao dos mutantes pode gerar um conjunto de mutantes
significativamente diferente do conjunto originalmente gerado, podendo reque-
rer novos casos de teste para mat-los. Alm disso, novos defeitos podero
ser inseridos no cdigo durante a correo dos defeitos j encontrados, reque-
rendo dessa forma que tanto o programa corrigido quanto os mutantes gerados
a partir dele sejam exercitados com o conjunto de teste.
Conforme discutido na Seo 1.2, indispensvel o uso de ferramentas de
apoio para que a atividade de teste alcance a qualidade desejada. Em parti-
cular, tm sido propostas e implementadas algumas ferramentas de apoio ao
teste de mutao de programas OO escritos em Java que utilizam os operado-
res de mutao discutidos nesta seo.

1.4.4. Aplicao do Teste de Mutao de Unidade em Programas


OA
Em continuidade ao exemplo de aplicao do teste de mutao, nesta se-
o apresentado um exemplo de sua aplicao no teste de unidade de pro-
gramas OA escritos em AspectJ, agora considerando a verso OA da aplicao
de simulao de telefonia. Ressalta-se que dois defeitos foram encontrados
nessa aplicao durante o desenvolvimento dos exemplos de teste estrutural
e de mutao de unidade de programas OO apresentados nas sees 1.4.1 e
1.4.3. Esses defeitos foram corrigidos na aplicao utilizada nesta seo.
Em relao aos operadores de mutao, os mesmos operadores utilizados

62
Teste de Software OO e OA: Teoria e Prtica

na seo anterior sero aplicados, sendo eles SSDL, STRI, OCNG e SMTC. Na
Figura 1.29 destaca-se parte do cdigo do aspecto Billing. Em particular,
destaca-se o adendo sobre o qual so aplicados os operadores de mutao
selecionados.

1 public aspect Billing {


2 ...
3 public static final long MOBILE_LD_RECEIVER_RATE = 5;
4 ...
5
6 after(Connection conn) returning () :
7 Timing.endTiming(conn) {
8 long time =
9 Timing.aspectOf().getTimer(conn).getTime();
10 long rate = conn.callRate();
11 long cost = rate * time;
12 if (conn.isMobile()) {
13 if (conn instanceof LongDistance) {
14 long receiverCost =
15 MOBILE_LD_RECEIVER_RATE * time;
16 conn.getReceiver().addCharge(receiverCost);
17 }
18 }
19 getPayer(conn).addCharge(cost);
20 }
21 ...
22 }
23
24
25 public aspect Timing {
26 ...
27
28 pointcut endTiming(Connection c): target(c)
29 && call(void Connection.drop());
30 ...
31 }

Figura 1.29. Parte do cdigo dos aspectos Billing e


Timing da aplicao de telefonia

Os casos de teste apresentados na Figura 1.30 foram implementados para


matar os mutantes dos mtodos construtor e merge gerados nesse exemplo,
que so mostrados nas Figuras 1.31, 1.32 e 1.33. Observa-se que o operador
SMTC no produz mutantes para o adendo selecionado.
Na Tabela 1.5 apresentada a relao dos mutantes mortos por cada caso
de teste. Da mesma forma que no exemplo apresentado na seo anterior,
pode-se observar que um nico caso de teste pode matar mais de um mutante.
Pode-se observar tambm que nesse exemplo no foram gerados mutantes
que no compilam ou equivalentes.

Tabela 1.5. Casos de teste X mutantes OA mortos


Caso de Teste Mutante
testMobileReceiverCharging Ma1 / Ma2 / Ma3 / Ma4 / Ma5 / Ma8 / Ma9
testMobileCallCharging Ma4 / Ma5
testNotMobileCallCharging Ma6
testLocalMobileCallCharging Ma4 / Ma7

63
Masiero, Lemos, Ferrari e Maldonado

public void testMobileReceiverCharging() { public void testNotMobileCallCharging() {


Customer jim = new Customer("Jim", 650, Customer jim = new Customer("Jim", 650,
"3361-1111"); "3361-1111");
Customer mik = new Customer("Mik", 750, Customer mik = new Customer("Mik", 650,
"3361-1112"); "3361-1112");
Call c1 = new Call(jim, mik, true); try {
c1.pickup(); Call c1 = new Call(jim, mik, false);
wait(2.0); c1.pickup();
c1.hangup(); c1.hangup();
double result = assertTrue(true);
Billing.aspectOf().getTotalCharge(mik); }
assertTrue(result > 0); catch (RuntimeException e) {
} assertTrue(false);
}
public void testMobileCallCharging() { }
Customer jim = new Customer("Jim", 650,
"3361-1111"); public void testLocalMobileCallCharging() {
Customer mik = new Customer("Mik", 750, Customer jim = new Customer("Jim", 650,
"3361-1112"); "3361-1111");
try { Customer mik = new Customer("Mik", 650,
Call c1 = new Call(jim, mik, true); "3361-1112");
c1.pickup(); try {
c1.hangup(); Call c1 = new Call(jim, mik, true);
assertTrue(true); c1.pickup();
} c1.hangup();
catch (RuntimeException e) { assertTrue(true);
assertTrue(false); }
} catch (RuntimeException e) {
} assertTrue(false);
}
}

Figura 1.30. Casos de teste criados para matar mutantes OA

after(Connection conn) returning () : after(Connection conn) returning () :


Timing.endTiming(conn) { Timing.endTiming(conn) {
long time = long time =
Timing.aspectOf().getTimer(conn).getTime(); Timing.aspectOf().getTimer(conn).getTime();
long rate = conn.callRate(); long rate = conn.callRate();
long cost = rate * time; long cost = rate * time;
if (conn.isMobile()) { if (conn.isMobile()) {
if (conn instanceof LongDistance) { >
long receiverCost = }
MOBILE_LD_RECEIVER_RATE * time; getPayer(conn).addCharge(cost);
> }
}
}
getPayer(conn).addCharge(cost);
}

Ma1 Ma2
after(Connection conn) returning () :
Timing.endTiming(conn) {
long time =
Timing.aspectOf().getTimer(conn).getTime();
long rate = conn.callRate();
long cost = rate * time;
>
getPayer(conn).addCharge(cost);
}

Ma3
Figura 1.31. Mutantes gerados pelo operador SSDL

Considerando a necessidade de apoio automatizado atividade de teste,


a ferramenta de apoio ao teste de mutao de unidades programas OO que

64
Teste de Software OO e OA: Teoria e Prtica

after(Connection conn) returning () : after(Connection conn) returning () :


Timing.endTiming(conn) { Timing.endTiming(conn) {
long time = long time =
Timing.aspectOf().getTimer(conn).getTime(); Timing.aspectOf().getTimer(conn).getTime();
long rate = conn.callRate(); long rate = conn.callRate();
long cost = rate * time; long cost = rate * time;
> if (Util.trap_on_true(conn.isMobile())) { if (conn.isMobile()) {
if (conn instanceof LongDistance) { > if (Util.trap_on_true(
long receiverCost = conn instanceof LongDistance)){
MOBILE_LD_RECEIVER_RATE * time; long receiverCost =
conn.getReceiver().addCharge(receiverCost); MOBILE_LD_RECEIVER_RATE * time;
} conn.getReceiver().addCharge(receiverCost);
} }
getPayer(conn).addCharge(cost); }
} getPayer(conn).addCharge(cost);
}

Ma4 Ma5
after(Connection conn) returning () : after(Connection conn) returning () :
Timing.endTiming(conn) { Timing.endTiming(conn) {
long time = long time =
Timing.aspectOf().getTimer(conn).getTime(); Timing.aspectOf().getTimer(conn).getTime();
long rate = conn.callRate(); long rate = conn.callRate();
long cost = rate * time; long cost = rate * time;
> if (Util.trap_on_false(conn.isMobile())) { if (conn.isMobile()) {
if (conn instanceof LongDistance) { > if (Util.trap_on_false(
long receiverCost = conn instanceof LongDistance)){
MOBILE_LD_RECEIVER_RATE * time; long receiverCost =
conn.getReceiver().addCharge(receiverCost); MOBILE_LD_RECEIVER_RATE * time;
} conn.getReceiver().addCharge(receiverCost);
} }
getPayer(conn).addCharge(cost); }
} getPayer(conn).addCharge(cost);
}

Ma6 Ma7
Figura 1.32. Mutantes gerados pelo operador STRI

after(Connection conn) returning () : after(Connection conn) returning () :


Timing.endTiming(conn) { Timing.endTiming(conn) {
long time = long time =
Timing.aspectOf().getTimer(conn).getTime(); Timing.aspectOf().getTimer(conn).getTime();
long rate = conn.callRate(); long rate = conn.callRate();
long cost = rate * time; long cost = rate * time;
> if (!conn.isMobile()) { if (conn.isMobile()) {
if (conn instanceof LongDistance) { > if (!(conn instanceof LongDistance)) {
long receiverCost = long receiverCost =
MOBILE_LD_RECEIVER_RATE * time; MOBILE_LD_RECEIVER_RATE * time;
conn.getReceiver().addCharge(receiverCost); conn.getReceiver().addCharge(receiverCost);
} }
} }
getPayer(conn).addCharge(cost); getPayer(conn).addCharge(cost);
} }

Ma8 Ma9
Figura 1.33. Mutantes gerados pelo operador OCNG

est em desenvolvimento no grupo ser estendida para apoiar tambm o teste


de mutao de unidades de programas OA escritos em AspectJ.

65
Masiero, Lemos, Ferrari e Maldonado

1.5. Concluses e Perspectivas


Neste texto foi apresentada uma viso geral da atividade de teste de soft-
ware, destacando sua importncia dentro do processo de desenvolvimento e a
necessidade de apoio automatizado. Foram enfatizadas as tcnicas estrutural
e baseada em defeitos; em particular, foram apresentados a aplicao de cri-
trios baseados em fluxo de controle, fluxo de dados e mutao no contexto
de teste de unidade de programas OO e OA. Questes relacionadas ao teste
de mutao na fase de integrao tambm foram brevemente exploradas.Com
as devidas adaptaes, observou-se que esses critrios, embora originalmente
propostos para o teste de programas procedimentais, podem ser utilizados para
o teste de software nos contextos de OO e OA tanto na fase de unidade quanto
na fase de integrao.
Durante a aplicao dos critrios de teste nos exemplos apresentados, fo-
ram identificadas falhas na execuo dos testes, que ocorreram devido a dois
defeitos presentes nos programas originais. Nesses casos, podem-se obser-
var evidncias sobre a eficcia dos critrios em revelar defeitos presentes no
software e, ainda, sobre o carter complementar das tcnicas de teste, visto
que um dos defeitos foi identificado durante a utilizao da tcnica estrutural e
o outro somente durante a aplicao do teste de mutao.
No que se refere a direes futuras, observa-se a necessidade de mais
investigaes no contexto de teste de software OO e OA. O paradigma OO,
embora j consolidado no que diz respeito s demais atividades do ciclo de de-
senvolvimento de software, ainda possui questes em aberto que impactam a
atividade de teste. Poucos ainda so os trabalhos que propem abordagens de
teste direcionadas s caractersticas especficas introduzidas pelo paradigma
como, por exemplo, encapsulamento e polimorfismo. Alm disso, ainda no
existe um consenso sobre uma estratgia ideal de teste de integrao e ferra-
mentas de apoio ao teste de software OO em geral.
A POA, por sua vez, uma abordagem relativamente recente, e o foco
principal das pesquisas realizadas e em andamento est no estabelecimento
de conceitos e em como implement-los nas tecnologias de apoio. Nota-se
que as mesmas necessidades encontradas para o teste de software OO esto
presentes no contexto de software OA, e algumas outras especficas como,
por exemplo, o teste adequado de conjuntos de juno e o teste de integrao
entre aspectos e classes.
Cabe destacar que a investigao dos problemas indicados, incluindo evo-
lues e desenvolvimento de ferramentas de teste (como, por exemplo, evo-
lues na ferramenta JaBUTi); e problemas relacionados com o teste de in-
tegrao de software OO e OA, so objetivos de trabalhos em andamento de
alguns grupos de pesquisa, incluindo o grupo de Engenharia de Software do
ICMC/USP.
Para finalizar, ressalta-se que o conhecimento e as contribuies na rea
de teste divididos basicamente em conhecimento terico, experimental e de
ferramentas de apoio devem ser constantemente atualizados, assim como

66
Teste de Software OO e OA: Teoria e Prtica

nas demais reas. Nessa perspectiva, a organizao de uma base histrica so-
bre o custo e a eficcia das tcnicas e critrios de teste, em diferentes domnios
de aplicao, em relao a diferentes classes de defeitos, certamente facilita-
ria o planejamento de futuros desenvolvimentos de software. Facilitaria, ainda,
o estabelecimento de estratgias de teste que explorem os aspectos comple-
mentares das tcnicas e critrios, viabilizando a deteco do maior nmero de
defeitos possvel e com o menor custo, o que contribuiria para a liberao de
produtos de software de maior qualidade a um menor custo [Rocha et al. 2001].

1.6. Agradecimentos
Os autores agradecem Fundao de Amparo Pesquisa do Estado de
So Paulo (FAPESP) pelo apoio financeiro e aos pesquisadores Ellen Fran-
cine Barbosa, Auri Marcelo Rizzo Vincenzi e Mrcio Eduardo Delamaro pelas
diversas contribuies neste trabalho.

Referncias
[Acree 1980] Acree, A. T. (1980). On Mutation. PhD thesis, Scholl of Infor-
mation and Computer Science, Georgia Institute of Technology, Atlanta/GA -
USA.
[Acree et al. 1979] Acree, A. T., Budd, T. A., DeMillo, R. A., Lipton, R. J., and
Sayward, F. G. (1979). Mutation analysis. Technical Report GIT-ICS-79/08,
School of Information and Computer Science, Georgia Institute of Techno-
logy, Atlanta/GA - USA.
[Adrion et al. 1982] Adrion, W. R., Branstad, M. A., and Cherniavsky, J. C.
(1982). Validation, Verification, and Testing of Computer Software. ACM
Computing Surveys, 14(2):159192.
[Agrawal et al. 1989] Agrawal, H., DeMillo, R. A., Hathaway, R., Hsu, W., Hsu,
W., Krauser, E. W., Martin, R. J., Mathur, A. P., and Spafford, E. H. (1989).
Design of mutant operators for the C programming language. Technical Re-
port SERC-TR41-P, Software Engineering Research Center, Purdue Univer-
sity, West Lafayette/IN - USA.
[Alexander 2003] Alexander, R. (2003). Aspect-oriented programming: the real
costs? IEEE Software, 20(6):9093.
[Alexander et al. 2004] Alexander, R. T., Bieman, J. M., and Andrews, A. A.
(2004). Towards the systematic testing of aspect-oriented programs. Techni-
cal report, Department of Computer Science, Colorado State University.
[Alexander and Offutt 2000] Alexander, R. T. and Offutt, A. J. (2000). Criteria
for testing polymorphic relationships. In Proceedings of the 11th International
Symposium on Software Reliability Engineering (ISSRE2000), pages 1523,
Sao Jose/CA - USA. IEEE Computer Society.
[AspectJ Team 2003] AspectJ Team (2003). The AspectJ programming guide.
Online. Disponvel em http://www.eclipse.org/aspectj/doc/
released/progguide/index.html - ltimo acesso em 20/01/2006.

67
Masiero, Lemos, Ferrari e Maldonado

[Beck and Gamma 2006] Beck, K. and Gamma, E. (2006). JUnit, testing re-
sources for extreme programming. Online. Disponvel em http://www.
junit.org/index.htm - ltimo acesso em 02/04/2006.
[Binder 1999] Binder, R. V. (1999). Testing Object-Oriented Systems Models,
Patterns, and Tools. Addison Wesley, 1st. edition.
[Booch 1994] Booch, G. (1994). Object-Oriented Analysis and Design with Ap-
plications. Addison Wesley, 2nd. edition.
[Budd 1981] Budd, T. A. (1981). Mutation analysis: Ideas, example, problems
and prospects. Computer Program Testing North-Holand Publishing Com-
pany.
[Chevalley and Thvenod-Fosse 2003] Chevalley, P. and Thvenod-Fosse, P.
(2003). A mutation analysis tool for java programs. International Journal on
Software Tools for Technology Transfer (STTT), 5(1):90103.
[Cox and Novobilski 1991] Cox, B. J. and Novobilski, A. J. (1991). Object-
Oriented Programming. Addison-Wesley, 2nd. edition.
[Delamaro 1997] Delamaro, M. E. (1997). Mutao de Interface: Um critrio
de adequao interprocedimental para o teste de integrao. PhD thesis,
IFSC/USP.
[Delamaro et al. 2001] Delamaro, M. E., Maldonado, J. C., and Mathur, A. P.
(2001). Interface Mutation: An approach for integration testing. IEEE Tran-
sactions os Software Engineering, 27(3):228247.
[DeMillo 1978] DeMillo, R. A. (1978). Hints on test data selection: Help for the
practicing programmer. IEEE Computer, 11(4):3443.
[Domingues 2002] Domingues, A. L. S. (2002). Avaliao de critrios e fer-
ramentas de teste para programas OO. Masters thesis, ICMC/USP, So
Carlos/SP - Brasil.
[Elrad et al. 2001] Elrad, T., Filman, R. E., and Bader, A. (2001). Aspect-
oriented programming: Introduction. Communications of the ACM,
44(10):2932.
[Filman and Friedman 2000] Filman, R. and Friedman, D. (2000). Aspect-
oriented programming is quantification and obliviousness. In Workshop on
Advanced Separation of Concerns, OOPSLA 2000, pages 2135, Minnea-
polis - USA.
[Frankl and Weyuker 2000] Frankl, P. G. and Weyuker, E. J. (2000). Testing
software to detect and reduce risk. Journal of Systems and Software,
53(3):275286.
[Friedman 1975] Friedman, A. D. (1975). Logical Design of Digital Systems.
Computer Science Press.
[Harrold 2000] Harrold, M. J. (2000). Testing: A roadmap. In 22th International
Conference on Software Engineering - Future of SE Track, pages 6172.

68
Teste de Software OO e OA: Teoria e Prtica

ACM Press.
[Harrold and Rothermel 1994] Harrold, M. J. and Rothermel, G. (1994). Per-
forming data flow testing on classes. In 2nd ACM SIGSOFT Symposium on
Foundations of Software Engineering, pages 154163, New York, NY. ACM
Press.
[Howden 1986] Howden, W. E. (1986). Functional Program Testing and Analy-
sis. McGraw-Hill, Inc., New York/NY - USA.
[IEEE 1990] IEEE (1990). IEEE standard glossary of software engineering ter-
minology. Standard 610.12, Institute of Electric and Electronic Engineers.
[Kiczales et al. 2001] Kiczales, G., Hilsdale, E., Hugunin, J., Kersten, M., Palm,
J., and Griswold, W. G. (2001). An overview of AspectJ. In ECOOP 01:
Proceedings of the 15th European Conference on Object-Oriented Program-
ming, pages 327353.
[Kiczales et al. 1997] Kiczales, G., Irwin, J., Lamping, J., Loingtier, J.-M., Lo-
pes, C., Maeda, C., and Menhdhekar, A. (1997). Aspect-oriented program-
ming. In Aksit, M. and Matsuoka, S., editors, Proceedings of the European
Conference on Object-Oriented Programming, volume 1241, pages 220
242, Berlin, Heidelberg, and New York. Springer-Verlag.
[Kiczales and Mezini 2005] Kiczales, G. and Mezini, M. (2005). Aspect-
oriented programming and modular reasoning. In Proceedings of the 27th
International Conference on Software Engineering (ICSE2005), pages 49
58. ACM Press.
[Kim et al. 2000] Kim, S., Clark, J., and McDermid, J. (2000). Class muta-
tion: Mutation testing for object-oriented programs. In Proceedings of the
FMES2000.
[Laddad 2003] Laddad, R. (2003). AspectJ In Action. Manning Publications.
[Lemos 2005] Lemos, O. A. L. (2005). Teste de programas orientados a aspec-
tos: Uma abordagem estrutural para AspectJ. Masters thesis, ICMC/USP,
So Carlos/SP - Brasil.
[Lemos et al. 2004] Lemos, O. A. L., Maldonado, J. C., and Masiero, P. C.
(2004). Data flow integration testing criteria for aspect-oriented programs.
In Anais do 1o Workshop Brasileiro de Desenvolvimento de Software Orien-
tado a Aspectos (WASP2004), Braslia/DF - Brasil.
[Lemos et al. 2005] Lemos, O. A. L., Maldonado, J. C., and Masiero, P. C.
(2005). Structural unit testing of AspectJ programs. In Proceedings of the
1st Workshop on Testing Aspect Oriented Programs in conjunction with
AOSD2005, Chicago/IL, USA.
[Linnenkugel and Mllerburg 1990] Linnenkugel, U. and Mllerburg, M. (1990).
Test data selection criteria for (software) integration testing. In First Interna-
tional Conference on Systems Integration, pages 709717, Morristown/NJ -

69
Masiero, Lemos, Ferrari e Maldonado

USA.
[Ma et al. 2002] Ma, Y. S., Kwon, Y. R., and Offutt, J. (2002). Inter-class muta-
tion operators for java. In Proceedings of the 13th International Symposium
on Software Reliability Engineering (ISSRE02), pages 352366, Annapolis,
MD. IEEE Computer Society Press.
[Maldonado 1991] Maldonado, J. C. (1991). Critrios Potenciais Usos: Uma
Contribuio ao Teste Estrutural de Software. PhD thesis, DCA/FEE/UNI-
CAMP, Campinas, SP - Brasil.
[Mathur and Wong 1993] Mathur, A. P. and Wong, W. E. (1993). Evaluation of
the cost of alternative mutation strategies. In Anais do 7o Simpsio Brasileiro
de Engenharia de Software (SBES1993), pages 320335, Joo Pessoa/PB
- Brasil.
[McDaniel and McGregor 1994] McDaniel, R. and McGregor, J. D. (1994). Tes-
ting polymorphic interactions between classes. Technical Report TR-94-103,
Clemson University.
[Mortensen and Alexander 2004] Mortensen, M. and Alexander, R. T. (2004).
Adequate testing of aspect-oriented programs. Technical Report CS 01-110,
Department of Computer Science, Colorado State University.
[Myers et al. 2004] Myers, G. J., Sandler, C., Badgett, T., and Thomas, T. M.
(2004). The Art of Software Testing. John Wiley & Sons, 2nd edition.
[Offutt et al. 1993] Offutt, A. J., Rothermel, G., and Zapf, C. (1993). An expe-
rimental evaluation of selective mutation. In Proceedings of the 15th Inter-
national Conference on Software Engineering (ICSE1993), pages 100107,
Baltimore/MD - USA. IEEE Computer Society Press.
[Offutt et al. 2001] Offutt, J., Alexander, R., Wu, Y., Xiao, Q., and Hutchinson,
C. (2001). A fault model for subtype inheritance and polymorphism. In Pro-
ceedings of the 12th International Symposium on Software Reliability Engine-
ering, pages 8493, Hong Kong - China. IEEE Computer Society Press.
[Pressman 2000] Pressman, R. S. (2000). Software engineering - A Practitio-
ners Approach. McGraw-Hill, 5th edition.
[Rapps and J.Weyuker 1982] Rapps, S. and J.Weyuker, E. (1982). Data flow
analysis techniques for program test data selection. In 6th International Con-
ference on Software Engineering, pages 272278, Tokio, Japan.
[Rapps and J.Weyuker 1985] Rapps, S. and J.Weyuker, E. (1985). Selecting
software test data using data flow information. IEEE Transactions on Soft-
ware Engineering, 11(4):367375.
[Rocha et al. 2001] Rocha, A. R. C., Maldonado, J. C., and Weber, K. C.
(2001). Qualidade de Software. Prentice Hall.
[Simo and Maldonado 2000] Simo, A. S. and Maldonado, J. C. (2000). Mu-
tation based test sequence generation for Petri Nets. In Proceedings of the

70
Teste de Software OO e OA: Teoria e Prtica

3rd Workshop of Formal Methods, pages 6879, Joo Pessoa/PB - Brasil.


[Sommerville 2001] Sommerville, I. (2001). Software Engineering. Addison-
Wesley, 6th edition.
[Stroustrup 1986] Stroustrup, B. (1986). The C++ Programming Language.
Addison-Wesley.
[Sun Microsystems 2006] Sun Microsystems (2006). Java Technology. Online.
Disponvel em http://java.sun.com/ - ltimo acesso em 02/04/2006.
[Vilela et al. 1999] Vilela, P. R. S., Maldonado, J. C., and Jino, M. (1999). Data
flow based integration testing. In Anais do 13o Simpsio Brasileiro de Enge-
nharia de Software (SBES1999), Florianpolis/SC - Brasil.
[Vincenzi 2004] Vincenzi, A. M. R. (2004). Orientao a Objeto: Definio,
Implementao e Anlise de Recursos de Teste e Validao. PhD thesis,
ICMC/USP, So Carlos, SP - Brasil.
[Vincenzi et al. 2005] Vincenzi, A. M. R., Maldonado, J. C., Wong, W. E., and
Delamaro, M. E. (2005). Coverage testing of java programs and components.
Science of Computer Programming, 56(1-2):211230.
[Vincenzi et al. 2002] Vincenzi, A. M. R., Nakagawa, E. Y., Maldonado, J. C.,
Delamaro, M. E., and Romero, R. A. R. (2002). Bayesian-learning based
guidelines to determine equivalent mutants. International Journal of Software
Engineering and Knowledge Engineering - IJSEKE, 12(6):675689.
[Weyuker 1982] Weyuker, E. J. (1982). On testing non-testable programs.
Computer Journal, 25(4):465470.
[Weyuker 1996] Weyuker, E. J. (1996). Using failure cost information for testing
and reliability assessment. ACM Transactions on Software Engineering and
Methodology, 5(2):8798.
[Wirfs-Brock et al. 1990] Wirfs-Brock, R., Wilkerson, B., and Wiener, L. (1990).
Designing Object-Oriented Software. Prentice-Hall.
[Wong and Mathur 1995] Wong, W. E. and Mathur, A. P. (1995). Fault detection
effectiveness of mutation and data flow testing. Software Quality Journal,
4(1):6983.
[Zhu et al. 1997] Zhu, H., Hall, P., and May, J. (1997). Software unit test cove-
rage and adequacy. ACM Computing Surveys, 29(4):366427.

71