RESUMO
Este documento apresenta critérios específicos de teste de software, conceitos relevantes e ferramentas de suporte. São discutidos critérios de avaliação funcionais, estruturais – baseados em fluxo de controle e fluxo de dados – e baseados em flexibilidade. O foco está no teste de mutação. Apesar de sua eficácia em encontrar bugs, mesmo em programas pequenos, o teste de mutação tem problemas de custo relacionados ao grande número de mutações produzidas e à determinação da mesma mutação. A fim de reduzir o custo do uso do teste de transformação, muitas investigações teóricas e empíricas têm sido realizadas. Apresenta-se uma síntese dos estudos históricos mais importantes relacionados com a avaliação da reforma. Esses estudos visam estabelecer uma estratégia de teste que permita o uso de teste de mudança ao testar produtos de software comercial. Trabalho experimental e problemas relacionados são demonstrados usando ferramentas PokeTool, Proteum e PROTEUM=IM, que suportam processo estrutural, critérios de análise de mutantes e critérios de modificação de interface, respectivamente. Outras iniciativas da comunidade e esforços para automatizar esses processos também são identificados.
Palavras-chaves: Testes de software; interface; informática.
1 INTRODUÇÃO
A engenharia de software evoluiu significativamente nas últimas décadas, tentando estabelecer técnicas, critérios, métodos e ferramentas para a produção de software como resultado do crescente uso de sistemas informatizados em praticamente todas as áreas da atividade humana, resultando em uma crescente demanda por qualidade e produtividade ocasionada, tanto do ponto de vista do processo produtivo quanto do ponto de vista dos produtos fabricados. A engenharia de software pode ser definida como uma disciplina que aplica princípios de engenharia para produzir software de alta qualidade a baixo custo. Por meio de uma série de etapas que envolvem o desenvolvimento e aplicação de métodos, técnicas e ferramentas, a engenharia de software fornece um meio para atingir esses objetivos.
O processo de desenvolvimento de software inclui uma série de atividades onde, independente das técnicas, métodos e ferramentas utilizadas, ainda podem ocorrer erros no produto. As atividades agrupadas sob o nome Software Quality Assurance são introduzidas ao longo do processo de desenvolvimento, incluindo as operações.
A função de teste consiste na análise dinâmica do produto e é a tarefa certa para identificar e eliminar os erros remanescentes. O teste sistemático é uma atividade fundamental para subir para o Nível 3 do modelo do Software Engineering Institute – SEI CMM do ponto de vista da qualidade do processo. Além disso, o conjunto de conhecimento derivado da atividade de teste é importante para resolução de problemas, manutenção e tarefas de medição de confiabilidade de software. Cabe destacar que a atividade de teste tem sido apontada como uma das mais caras no desenvolvimento de software. Apesar disso, é evidente que se sabe muito menos sobre teste de software do que outros aspectos e/ou atividades de desenvolvimento de software.
Os produtos de software de teste consistem, na verdade, em quatro etapas: planejamento de teste, projeto de caso de teste, execução e avaliação dos resultados do teste. Essas atividades devem ser desenvolvidas durante o próprio processo de desenvolvimento de software e geralmente ocorrem em três etapas de teste: unidade, integração e sistema. O teste unitário foca em uma pequena unidade do projeto de software, ou seja, tenta identificar erros de compreensão e implementação em cada módulo de software separadamente. Teste de integração é uma atividade estruturada utilizada durante a compilação de uma estrutura de programa para detectar erros relacionados à integração entre módulos; O objetivo é criar uma estrutura de programa, que foi determinada pelo projeto, a partir dos módulos testados em nível de unidade. O teste do sistema, realizado após a integração do sistema, visa identificar falhas nas operações e no desempenho que não estejam de acordo com as especificações.
2 FUNDAMENTAÇÃO TEÓRICA
Em geral, os critérios de teste de software são determinados essencialmente a partir de três técnicas diferentes: funcional, estrutural e baseada em falhas. Na engenharia funcional, os critérios e requisitos de teste são determinados a partir da função de especificação de software; na engenharia estrutural, os critérios e requisitos são essencialmente derivados das propriedades de uma implementação específica a ser testada; e na técnica baseada em erros, os critérios e requisitos de teste são derivados do conhecimento de erros típicos cometidos no processo de desenvolvimento de software. Observa-se também o estabelecimento de critérios para geração de sequências de teste baseadas em máquinas de estados finitos. Estes últimos foram usados no contexto de validação e teste de sistemas reativos e orientados a objetos (BEIZER, 1995).
Os testes podem ser classificados de duas maneiras: testes baseados em especificações e testes baseados em programas. De acordo com essa classificação, os critérios técnico-funcionais são baseados em especificações e tanto os critérios estruturais quanto os baseados em falhas são considerados critérios baseados na implementação (BEIZER, 1995).
Nos testes baseados em especificações (ou testes de caixa preta), o objetivo é determinar se o programa atende aos requisitos funcionais e não funcionais especificados. O problema é que a especificação existente é geralmente informal e, portanto, a determinação da cobertura total da especificação obtida através de um determinado conjunto de casos de teste também é informal. No entanto, os critérios de teste baseados em especificações podem ser usados em qualquer contexto (procedural ou orientado a objetos) e em qualquer fase de teste sem a necessidade de customização. Exemplos desses critérios são: classificação de equivalência, análise de limiar, diagrama de causa e efeito e teste baseado em estado (HETZEL, 1988).
Em contraste com o teste baseado em especificação, o teste baseado em programa (ou teste de caixa branca) requer o exame do código-fonte e a seleção de casos de teste que testam partes do código em vez de sua especificação.
É importante enfatizar que as técnicas de teste devem ser vistas como complementares e surge a questão de como elas podem ser implantadas de forma a melhor utilizar os benefícios de cada uma em uma estratégia de teste que resulte em uma atividade de teste de alta qualidade, ou ser eficaz e barato. As técnicas e critérios de teste fornecem ao desenvolvedor uma abordagem sistemática e teoricamente sólida e fornecem um mecanismo que pode ajudar a avaliar a qualidade e a adequação da atividade de teste. Os critérios de teste podem ser usados para gerar um conjunto de casos de teste, bem como para avaliar a adequação desses conjuntos (HETZEL, 1988).
Dada a diversidade de critérios estabelecidos e a natureza complementar de técnicas e critérios de teste reconhecidos, um ponto crucial decorrente dessa perspectiva é a seleção e/ou determinação de uma estratégia de teste, que envolve, em última análise, a seleção de critérios de teste de modo que os benefícios de cada um desses critérios sejam combinados para uma atividade de teste de maior qualidade. Estudos teóricos e empíricos sobre critérios de teste são de grande importância para a formação desse conhecimento e fornecem subsídios para o estabelecimento de estratégias custo-efetivas e altamente eficazes. Existem vários esforços da comunidade científica nesse sentido (MYERS, 1979).
É fundamental desenvolver ferramentas de teste que suportem a atividade de teste real, pois esta atividade é muito propensa a erros e, além disso, é improdutiva quando aplicada manualmente, bem como apoiar estudos empíricos destinados a avaliar e apoiar a comparação dos vários critérios de teste. Assim, a disponibilidade de ferramentas de teste proporciona maior qualidade e produtividade para as atividades de teste. Esforços científicos nesse sentido podem ser observados na literatura (MYERS, 1979).
Observa-se que os critérios baseados na análise de fluxo de dados e o critério de análise de mutações têm sido intensamente estudados por diversos pesquisadores em diferentes aspectos. Os resultados desses estudos comprovam que esses critérios, que atualmente estão sendo investigados principalmente na ciência, em parte em cooperação com a indústria, podem representar o estado da prática em ambientes de produção de software a médio prazo. Uma forte evidência nesse sentido é o envolvimento da Telcordia Technologies (EUA) no desenvolvimento do xSuds, um ambiente que suporta a aplicação de critérios baseados em análise de fluxo de dados (CRESPO et al, 2002).
Os testes têm várias limitações. Em geral, os seguintes problemas são indecidíveis: dados dois programas, se são equivalentes; dadas duas sequências de instruções (caminhos) de um programa ou de programas diferentes se computarem a mesma função; e um determinado caminho, seja ele executável ou não, ou seja, se existe um conjunto de dados de entrada que levam à execução desse caminho. Outra limitação fundamental é a correção aleatória – o programa pode apresentar aleatoriamente um resultado correto para um determinado item de dados d 2D, ou seja, um item de dado específico é executado, satisfaz um requisito de teste e não indica a presença de um erro (CRESPO et al, 2002).
Diz-se que um programa P com faixa de entrada D está correto em relação a uma especificação S se S(d) = P(d) para cada elemento de dados d pertencente a D, ou seja, se o comportamento do programa estiver correto de acordo com o comportamento esperado para todos os dados de entrada. Dados dois programas P1 e P2 se P 1(d) = P 2(d), para qualquer d 2 D, P1 e P2 são equivalentes. O teste de software assume que existe um oráculo – o testador ou algum outro mecanismo – que pode determinar, dentro de limites de tempo, para cada item de dados d 2 D se S(d) = P(d) e esforço razoável, um oráculo simplesmente decide que os valores de saída estão corretos. É sabido que testes exaustivos são impraticáveis, ou seja, testar todos os elementos possíveis do domínio de entrada é geralmente caro e requer muito mais tempo do que o disponível. No entanto, deve-se notar que não existe um procedimento de teste universal que possa ser usado para provar a correção de um programa. Embora não seja possível provar por meio de testes que um programa está correto, se realizado de forma sistemática e cuidadosa, os testes ajudarão a criar confiança de que o software executará as funções especificadas, e algumas devem ser demonstradas com características mínimas do ponto de vista de qualidade (IEEE Computer Society, 1998).
Portanto, duas questões estão no centro da atividade de teste: Como os dados de teste devem ser selecionados? e como se pode decidir se um programa P foi suficientemente testado? Os critérios para a seleção e avaliação dos conjuntos de teste são cruciais para o sucesso da atividade de teste. Esses critérios devem fornecer uma indicação de quais casos de teste devem ser usados para aumentar a probabilidade de detecção de bugs ou, se os bugs não forem detectados, para construir um alto nível de confiança na correção do programa. Um caso de teste consiste em um par ordenado (d; S(d)) onde d 2 D e S(d) é a saída esperada (IEEE Computer Society, 1998).
Existe uma forte concordância entre procedimentos de seleção e critérios de adequação para casos de teste, pois dado um critério de adequação C existe um procedimento de seleção MC que afirma: Escolha T tal que T seja adequado para C. Da mesma forma, em um procedimento de seleção M, existe um critério de adequação CM que diz: T é adequado se foi selecionado após M. Portanto, o termo critério de adequação de caso de teste (ou simplesmente critério de teste) também é usado para procedimentos de seleção de designação. Dado P, T e um critério C, o conjunto de casos de teste T é considerado C adequado para testar P se T satisfizer os requisitos de teste especificados pelo critério C. Outra questão relevante neste contexto é dada uma sentença T C1-adequada, qual seria um critério de teste C2 que ajudaria a melhorar T? Essa questão foi examinada em estudos teóricos e empíricos (CRAIG; JASKIEL, 2002).
Em geral, pode-se dizer que as propriedades mínimas que um critério de teste C deve atender são:
- Garantir a cobertura de todos os ramos condicionais do ponto de vista do controle de fluxo;
- Exigir pelo menos um uso de cada resultado computacional do ponto de vista do fluxo de dados; e
- Requerem um conjunto finito de casos de teste (CRAIG; JASKIEL, 2002).
As vantagens e desvantagens dos critérios de teste de software podem ser avaliadas por meio de estudos teóricos e empíricos. Do ponto de vista teórico, esses estudos foram apoiados principalmente por uma relação de inclusão e o exame da complexidade dos critérios. A relação de inclusão cria uma ordem parcial entre os critérios e marca uma hierarquia entre eles. Um critério C1 deve conter um critério C2 se para qualquer programa P e qualquer conjunto de casos de teste T1 for elegível para C1, T1 também é elegível para C2 e existe um programa P e um conjunto T2 elegível para C2 exceto C1. A complexidade é definida como o número máximo de casos de teste exigidos por um critério no pior caso. No caso de critérios baseados em fluxo de dados, estes possuem uma complexidade exponencial, o que motiva a realização de estudos empíricos para determinar os custos de aplicação desses critérios do ponto de vista prático. Mais recentemente, alguns autores abordaram a questão da eficácia dos critérios de teste a partir de uma perspectiva teórica e definiram outras relações que capturam a capacidade de detectar falhas nos critérios de teste (CRAIG; JASKIEL, 2002).
Do ponto de vista dos estudos empíricos, normalmente são avaliados três aspectos: custos, eficácia e força (ou dificuldade de satisfação). O fator custo reflete o esforço necessário para que o critério seja aplicado; em geral, é medido pelo número de casos de teste necessários para atender ao critério (CRAIG; JASKIEL, 2002).
Uma atividade frequentemente citada na execução e avaliação da atividade de teste é a análise de cobertura, que consiste essencialmente em identificar o percentual de elementos requeridos por um determinado critério de teste que foi exercido pelo conjunto de casos de teste utilizado. Usando essas informações, o conjunto de casos de teste pode ser aprimorado adicionando novos casos de teste para praticar os elementos ainda não abordados. Nessa perspectiva, o conhecimento das restrições teóricas inerentes à atividade de teste é essencial, uma vez que os elementos requeridos podem não ser executáveis e, em geral, os testadores envolvidos na determinação da não-executabilidade de um determinado requisito de teste envolvem participação (ZALLAR, 2001).
Como já mencionado, técnicas de teste funcionais, estruturais e baseadas em erros são usadas para realizar e avaliar a qualidade da atividade de teste. Tais técnicas diferem na origem das informações utilizadas na avaliação e construção de conjuntos de casos de teste. Este texto apresenta as duas últimas técnicas com mais detalhes, mais especificamente os critérios para usos potenciais, o critério de análise de mutantes e o critério de mutação de interface, e as ferramentas de suporte PokeTool, Proteum e PROTEUM=IM. Esses critérios ilustram os principais aspectos relevantes para o teste de cobertura de software. Para dar uma visão mais abrangente, primeiro será dada uma visão geral da técnica funcional e os critérios mais conhecidos desta técnica (ZALLAR, 2001).
O teste funcional também é conhecido como teste de caixa preta porque trata o software como uma caixa cujo conteúdo é desconhecido e da qual apenas o lado externo, ou seja, os dados de entrada fornecidos, e as respostas geradas como saída podem ser vistas. Na técnica de teste funcional, as funções do sistema são verificadas sem se preocupar com detalhes de implementação (CENPRA, 2001).
O teste funcional consiste em duas etapas principais: identificar as funções que o software deve executar e criar casos de teste que possam ser usados para verificar se o software executa essas funções. Quais funções o software deve ter resulta de sua especificação. Portanto, uma especificação bem projetada de acordo com os requisitos do usuário é essencial para esse tipo de teste (CENPRA, 2001).
Figura 1 – Programa exemplo
Fonte: CENPRA, 2001.
Um dos problemas com os critérios funcionais é que a especificação do programa geralmente é feita de maneira descritiva e não formal. Os requisitos de teste derivados de tais especificações são, portanto, também um tanto imprecisos e informais. Consequentemente, é difícil automatizar a aplicação de tais critérios, que geralmente se limitam à aplicação manual. Por outro lado, para a aplicação desses critérios, é imprescindível apenas identificar as entradas, a função a ser calculada e a saída do programa, o que são em praticamente todas as fases de teste (unidade, integração e sistema) (CENPRA, 2001).
3 CONSIDERAÇÕES FINAIS
Neste texto, são apresentados alguns critérios de teste de software e conceitos relevantes, com foco naqueles considerados mais promissores a curto e médio prazo: o critério baseado em fluxo de dados, o critério de análise de mutantes e o critério de mutação de interface. Foram também apresentadas as ferramentas de teste PokeTool, Proteum e PROTEUM=IM, bem como várias outras iniciativas e esforços para automatizar estes critérios, dada a relevância deste aspecto para a qualidade e produtividade das próprias atividades de teste.
Deve-se notar que os conceitos e mecanismos desenvolvidos neste texto se aplicam no contexto do paradigma de desenvolvimento de software orientado a objetos, com as devidas adaptações. Em uma primeira etapa, será examinada a aplicação desses critérios ao testar programas C e Java. Tanto em testes intramétodos quanto intermétodos, a aplicação da análise de mutantes ou critérios de mutação de interface é praticamente direta. Posteriormente, quando outras interações forem consideradas, além de características específicas da linguagem orientada a objetos, como acoplamento dinâmico, herança, polimorfismo e encapsulamento, pode ser necessário desenvolver novos operadores de mutação que modelem os erros típicos encontrados nessa conexão.
Foi apontado que a atividade de teste desempenha um papel relevante no tema qualidade de software tanto do ponto de vista do processo quanto do produto. Por exemplo, do ponto de vista da qualidade do processo de desenvolvimento de software, o teste sistemático é uma atividade essencial para avançar ao nível 3 do modelo SEI CMM. Além disso, o conjunto de informações obtidas na atividade de teste é importante para atividades de depuração, estimativa de confiabilidade e manutenção de software.
REFERÊNCIAS
BEIZER, B. Black-Box Testing: techniques for funcional testing of software and system. New York. 1995.
HETZEL, B. The Complete Guide to Software Testing. 2nd Edition, John Wiley & Sons. 1988.
MYERS, G. J. The Art of Software Testing. Wiley, New York. 1979.
CRESPO, A. N.; MARTINEZ, M. R.; JINO, M.; ARGOLO, M. T. Application of the IEEE 829 Standard as a Basis for Structuring the Testing Process; The Journal of Software Testing Professionals. 2002.
IEEE COMPUTER SOCIETY. IEEE Std 829: Standard for Software Test Documentation. 1998.
CRAIG, R. D.; JASKIEL, S. P. Systematic Software Testing. Artech House Publishers. 2002.
ZALLAR, K. Are You Ready for Test Automation Game? STQE – Software Testing and Quality Engineering Magazine. 2001.
CENTRO DE PESQUISAS RENATO ARCHER – CENPRA. Divisão de Melhoria de Processos de Software – DMPS; RT – Guia para Elaboração de Documentos de Teste de Software. Relatório Técnico. 2001.