|
Testes de Software Aplicados à
Orientação a Objetos
Autores: Jefferson Carlos Martins
e Helbert Luiz Tschannerl
1. Introdução
Este artigo apresenta um tema muito importante na Engenharia
de Software que são os Testes de Software aplicados à Orientação
a Objetos.
Um dos problemas, constantemente citados quando se discute
teste de software, é o alto custo. Segundo Pressman, a atividade
de teste é um elemento crítico da garantia de qualidade
de software e pode assumir até 40% do esforço despendido
no desenvolvimento de software [3]. Por este motivo, o teste de software
tornou-se, pouco a pouco, um tema de grande importância, com a necessidade
de adaptação de métodos práticos que assegurem
a qualidade dos produtos finais, a fim de torná-los confiáveis
e de fácil manutenção.
As técnicas e métodos baseados em Orientação
a Objetos surgiram trazendo um enfoque diferente dos métodos tradicionais.
Uma grande vantagem da abordagem Orientada a Objetos é que ela
adota formas mais próximas dos mecanismos humanos para gerenciar
a complexidade de um software, tal como a abstração, classificando
elementos (objetos) em grupos (classes), através de uma estrutura
hierárquica. Neste paradigma, o mundo real é visto como
sendo constituído de objetos autônomos, concorrentes, que
interagem entre si, e cada objeto tem seu próprio estado e comportamento,
semelhante ao seu correspondente no mundo real. O teste orientado a objetos
é essencialmente diferente do teste convencional, pois testa o
estado dos objetos e produz um menor número de casos de testes
devido a reutilização de alguns casos de testes derivados
da presença do conceito de herança, entretanto, não
é questionável que a realização de testes
de códigos Orientados a Objetos seja mais complexa, principalmente
em função da hierarquia de classes, do polimorfismo e da
herança.
2. Teste de software orientado a objetos
Embora a abordagem Orientada a Objetos apresente várias vantagens
em relação aos paradigmas procedimentais antigos, a realização
de testes é um dos maiores problemas encontrados no desenvolvimento
de códigos Orientados a Objetos, pois, ao mesmo tempo em que algumas
características próprias das linguagens orientadas a objetos
tentam reduzir alguns tipos de erros, podem favorecer a adição
de novos erros. Este paradigma nos proporciona algumas facilidades, como
por exemplo: redução no tamanho dos métodos através
da utilização de heranças; algoritmos menos complexos,
ou seja, algoritmos com poucas linhas de código, o que aumenta
a legibilidade e o entendimento do mesmo; facilidade na localização
e correção de defeitos; encapsulamento, que previne muitos
problemas causados pelo escopo de dados sem controle.
Uma diferença importante do teste de programas procedimentais
em relação aos modelos orientados a objetos encontra-se
no fato que as aplicações Orientadas a Objetos não
são executadas seqüencialmente. Como nenhuma ordem de invocação
de métodos é especificada, a análise de fluxo de
controle do fluxo de dados para o teste de classe é dificultada,
fazendo com que técnicas de teste estrutural não sejam diretamente
aplicáveis. Os problemas adicionais para o teste e a manutenção
de programas introduzidos por este paradigma podem ser resumidos no entendimento
dos conceitos de aplicações Orientadas a Objetos, devido
às características de encapsulamento e polimorfismo causados
pelos relacionamentos complexos que existem em programas Orientados a
Objetos, tais como: herança, agregação, associação,
criação dinâmica de objetos, polimorfismo, etc. Outro
problema que podemos considerar neste paradigma é o teste de comportamento
dependente de estado, onde os objetos possuem comportamentos dependentes
de seu estado, isto é, o efeito de uma operação em
um objeto depende de seu estado e pode alterar este estado, sendo que
este problema também está altamente ligado à carência
no desenvolvimento de ferramentas de suporte ao teste Orientado a Objetos
ou total inexistência das mesmas no mercado e o uso de técnicas
convencionais não atenderem plenamente aos problemas específicos
de teste Orientado a Objetos.
A menor unidade de teste para sistemas Orientados a Objetos é
a classe, pois é onde encontramos uma coleção de
declarações de variáveis e funções.
Vários autores recomendam que seja realizado, inicialmente, o teste
das classes que não possuem dependência e o teste das classe/objetos
que usam seus serviços, juntando desta forma os testes de unidade/interação.
A estratégia de teste proposta por estes autores é denominada
Teste Baseado em Estados. Binder propõe que o comportamento de
uma classe é definido pelo conjunto de valores encapsulados que
a classe possui em determinado momento, e que seu comportamento é
controlado por valores encapsulados, seqüências de mensagens
ou ainda por ambos; o autor também descreve que um estado é
um subconjunto do conjunto de todas as combinações possíveis
dos valores de atributos da classe e através do monitoramento das
mudanças que ocorrem em valores dos atributos dos objetos. Neste
tipo de teste, é possível verificar as diversas interações
que ocorrem entre estes [1]. A ênfase do teste baseado em estados
está nos valores armazenados na representação dos
objetos, consistindo no teste das interações em uma classe
pela monitoração das alterações dos valores
dos atributos em um objeto, que conseqüentemente alteram seu estado.
Entre as propostas encontradas na área de testes Orientados a
Objetos, podemos também citar a proposta de Fiedler, onde foram
aplicadas técnicas de teste tradicionais para softwares escritos
em C++ e Java. As classes são validadas na ordem determinada por
um grafo de chamada, sendo que as classes base do grafo são validadas
primeiro [2]. Existem também frameworks para desenvolvimento de
casos de teste para softwares Orientados a Objetos, com uma técnica
baseada em estados, dirigindo-se a vários escopos de teste, tais
como: teste de classes baseado na implementação e baseado
na representação, teste de clusters, de subsistemas e de
sistemas.
3. Reflexão Computacional
Reflexão Computacional é definida como uma técnica
de programação que permite ao programador obter informações
a respeito do próprio programa, com o objetivo de monitorá-lo,
adicionar novas funcionalidades e mesmo fazer alterações
adaptativas em tempo de execução [4]. Sua utilização
no processo de teste possibilita realizar uma análise da aplicação
de forma dinâmica, sem a necessidade de instrumentar o código-fonte
da aplicação. Através da reflexão é
possível monitorar classes e objetos específicos, realizando
uma intervenção na computação da aplicação
em teste [4].
A Reflexão Computacional é a atividade executada por um
sistema computacional quando faz processamentos sobre suas próprias
ações e define uma arquitetura em níveis, denominada
arquitetura reflexiva [2]. Em uma arquitetura reflexiva, um sistema computacional
é visto como parte de dois componentes: um representando o objeto
e o outro a parte reflexiva. Os processamentos de um objeto, localizado
no nível base, têm por objetivo resolver problemas e retornam
informações sobre as computações do objetivo,
podendo adicionar funcionalidades extra a este objeto. A figura 1 permite
observar uma arquitetura reflexiva, composta por um metanível,
que contém a reflexão do sistema objeto, e um nível-base,
onde ficam os objetos do domínio da aplicação. Os
dados do nível base são usados no metanível para
a realização de computações reflexivas, que
podem interferir nas computações de nível-base.

A computação reflexiva pode atuar tanto sobre a estrutura
do sistema objeto, ocorrendo em nível de classes, quanto sobre
o comportamento, quando ocorre em nível de objetos. Quando a computação
reflexiva ocorre em nível de classes, o metanível é
composto por metaclasses que contêm informações sobre
os aspectos estruturais de nível-base. Se a computação
reflexiva ocorre em nível de objetos, o metanível é
composto de metaobjetos, os quais contêm informações
sobre o comportamento dos objetos (instância de classes) do nível-base.
A principal diferença entre a reflexão estrutural e a
comportamental é que a primeira realiza a associação
de classes a classes de objetos (metaclasses), enquanto a segunda realiza
a associação de objetos a objetos do metanível (metaobjetos).

O conceito de metaobjetos foi introduzido como um mecanismo para suportar
comportamento reflexivo em linguagens orientadas a objetos. O comportamento
computacional de cada objeto que faz parte de uma aplicação
é determinado por um metaobjeto que controla e define a operação
deste objeto.
Novos comportamentos podem ser adicionados, ou na forma como os métodos
são executados podem ser modificados. A reflexão computacional
permite o controle do comportamento do objeto ao receber a mensagem, possibilitando
a verificação de informações sobre o processo
de execução, com o objetivo de monitorá-lo, podendo
modificar o curso do mesmo, se necessário. A conexão é
realizada ligando-se um objeto a um metaobjeto. Sempre que o objeto receber
uma mensagem, o metaobjeto associado intercepta e passa a realizar o tratamento
da mensagem, dependendo de informações obtidas durante a
computação. O metaobjeto realiza a transformação
de atributos do programa em dados disponíveis ao próprio
programa e realiza as computações no metanível. Os
objetos notificados constituem as metainformações sobre
as quais são realizadas computações reflexivas [4].
4. Ferramentas de Apoio
Para utilizar os conceitos comentados acima e, ao mesmo tempo, automatizar
o processo de teste de software, podemos realizar a construção
de uma ferramenta que nos ajude a executar essas tarefas. Ao realizar
testes baseados em estados podemos avaliar as várias mudanças
de estados pelas quais passam os objetos de determinada classe, baseando-se
no modelo dinâmico da classe (diagrama/máquina de estados);
desta forma é possível verificar a integridade dos estados
de um objeto durante a execução do programa com a interceptação
de mensagens entre objetos, e também é possível,
com a reflexão destes, a verificação através
de consultas aos valores dos atributos dos objetos.
Uma ferramenta que contempla estes conceitos é o compilador Guaraná
[4] onde a interface para interação do usuário com
a ferramenta possibilita escolher a aplicação para teste.
Logo após é apresentada a hierarquia de classes da aplicação,
sendo relacionados, também, os métodos e atributos de cada
classe. Em seguida, o usuário especifica quais classes e/ou métodos
serão selecionados para serem monitorados. Para cada classe escolhida
poderá ser especificada uma variante associada a esta classe e,
para cada método, poderá ser especificada a pré e
a pós-condição para avaliação, não
sendo, entretanto, obrigatória a especificação de
asserções.
A próxima etapa desta ferramenta é a de reconfiguração
do metanível, com o intuito de se instanciar metaobjetos e associá-los
às classes/métodos escolhidos para teste. Executando-se
a aplicação, esta seria interrompida quando mensagens fossem
encaminhadas a estas classes, sendo transferido o controle da aplicação
para o metanível, onde os métodos dos metaobjetos associados
fariam os processamentos necessários para a verificação
das asserções e, conseqüentemente, a validação
dos estados esperados.
Existe também uma outra ferramenta chamada ATeste que auxilia
o teste de programas Orientados a Objetos, desenvolvido para uso em aplicações
Smalltalk, com a finalidade de prover facilidades ao desenvolvedor de
software nas atividades relacionadas à análise de códigos
Orientados a Objetos. ATeste implementa uma estratégia de teste,
denominada teste dinâmico de caminho, a qual aplica conceitos de
teste baseado em estados, aliados às vantagens da Reflexão
Computacional [2].
5. Conclusão
Neste artigo foram apresentadas questões relativas às
estratégias de testes Orientados a Objetos. Foi mostrado também
que estas técnicas e estratégias ainda são imaturas
e a atividade de teste ainda se encontra em fase de muitas pesquisas em
desenvolvimento por todos os cantos do mundo.
Também foram apresentados, como principal contribuição,
esclarecimentos sobre a atividade de teste de software aplicado à
Orientação a Objetos, que fornece uma infra-estrutura para
capturar informações, realizar verificações
e monitorar a execução das aplicações de forma
dinâmica sem a necessidade de alteração do código
fonte. Isto é possível graças à composição
de um conjunto de metaobjetos, coordenados por um gerenciador, que monitora
a execução da aplicação, dinamicamente, realizando
a análise e a visualização dos resultados sem interferir
no seu código, como foi discutido no tópico de reflexão
computacional.
O mecanismo de Reflexão Computacional possibilita que interceptações
de métodos sejam estabelecidas e supridas de forma dinâmica,
sem afetar o funcionamento próprio das classes interceptadas, eliminando,
assim, a possibilidade de deixar erros nas aplicações durante
o processo de teste. A implementação da estratégia
de teste dinâmico de caminho, aplicando conceitos de teste baseado
em estado, fornece ao testador uma visão do estado da classe sob
teste, antes e após a execução dos métodos
requeridos para monitoração, bem como uma visão textual
de todo o caminho executado pela aplicação, mostrando todos
os métodos executados e os respectivos estados, de maneira ordenada.
Concluímos com este artigo que é necessário estimular,
não somente o meio acadêmico praticante, mas todas as pessoas
interessadas no tema Testes de Software aplicados à Orientação
a Objetos, a proposição de debates em listas de discussão
e novos artigos a fim de obter um maior entendimento do assunto em ambas
as partes.
6. Referências
1. BINDER, R. V. "The FREE approach to testing
object - oriented software: an overview. Chicago: RBSC Corporation.,
1994. Disponível em: <http://www.rbsc.com/pages//onlineix.html>.
Acesso em: 07 out. 2003.
2. PINTO, I. M.; PRICE, A. A. Um sistema de apoio ao teste de programas
orientados a objetos . In: SBES - XII SIMPÓSIO BRASILEIRO DE ENGENHARIA
DE SOFTWARE, 1998, Maringá. Anais. Maringá, XII SIMPÓSIO
BRASILEIRO DE ENGENHARIA DE SOFTWARE, 1998. v.1, p.87-102.
3. PRESSMAN, R. S. Engenharia de software . São Paulo: Makron Books
do Brasil, 1995. p.786.
4. SILVEIRA, F. F. Ferramenta de apoio ao teste
de aplicações java baseada em reflexão computacional
. Disponível em: <http://www.inf.ufrgs.br/pos/SemanaAcademica/
Semana2000/FabioSilveira>. Acesso em: 20 set. 2003.
5. WERLANG, D. Ferramenta de teste de software
implementada em ambiente multiparadigma . Disponível em:
<http://www.inf.ufrgs.br/pos/
SemanaAcademica/
Semana99/denisemw/denisemw.html>. Acesso em: 13 set. 2003.
jeffcm@celepar.gov.br
Helbert.Tschannerl@vivo.com.br

|