TESTE DE SOFTWARE SEMI-AUTOMÁTICO COM INTEGRIDADE COMPLEMENTAR

Por Cristian Luciano Custodio | 16/06/2015 | Tecnologia

O presente artigo apresenta um estudo de caso de uma alternativa de teste funcional semiautomático denominado Integridade Complementar, onde os requisitos de sistemas são convertidos em restrições de integridade inteligentes, direcionando os testes e auxiliando na exposição de falhas. O estudo teve por base o backlog da empresa Governança Brasil, pioneira em soluções de tecnologia para a modernização da gestão pública no Brasil.

INTRODUÇÃO

Uma equipe de uma empresa pressionado por cronogramas e chefes irritados, em raríssimos casos consegue lutar contra o ambiente e dizer: “Vou atrasar a entrega para especificar mais claramente os requisitos” e os detalhes da especificação ficam para os diálogos informais. O resultado são requisitos superficiais sujeitos a ambiguidade, incompletude e inconsistência, e de quem é a responsabilidade pela falha? O programador interpretou de sua maneira, o analista não detalhou o que era para fazer, mas também não disse o contrário.

A Integridade Complementar é uma proposta de uma abordagem de teste com base em um processo de gestão de integridade onde cada requisito se transforma em uma ou várias regras monitorando o fluxo de dados durante os testes e agindo sempre que uma regra é infringida. É um processo que através de uma metodologia de teste torna o sistema mais consistente.

Na Integridade Complementar os documentos de análise tais como diagrama de estado, diagrama de classes, documentos de especificação, tabela verdade ou mesmo documentos de caso de teste são convertidos em regras de integridade auxiliando a evidenciar erros e norteando os testes. Não é um teste automático pois depende do teste efetuado pelo testador,mas direciona o teste e expõe as falhas.

INTEGRIDADE DE DADOS


Ao longo de toda história do software o tratamento de erros de entradas de dados de campos textuais de usuários sempre foi, e ainda é, um grande problema na construção de um software. A capacidade de previsão das possibilidades de entradas é um valor desejável entre os programadores, assim como a modelagem de classes válidas para uma determinada entrada de dados. Mas definir o que é um erro ou falha num software não é uma tarefa simples. Podemos simplificar dizer que um erro é quando o software não se comporta conforme foi especificado. Isto pode ocorrer quando o software não realiza uma função esperada, fornece resultados não esperados, não consegue terminar quando esperado, etc. Diversos erros podem se manifestar em apenas uma falha ou mesmo nunca causarem uma falha. Um defeito em um sistema pode, por exemplo, armazenar o número treze onde era esperado o número do mês. Este erro poderia ficar oculto por anos até virar uma falha. E pelo fato de gerar uma inconsistência na base de dados a correção pode não apenas se limitar ao defeito, mas a correção dos dados inconsistentes, podendo até exigir a interferência manual de um usuário, alto nível de retrabalho e insatisfação do cliente

Integridade de dados sobre a ótica da aplicação não pode evitar defeitos assim, mas pode manter a consistência dos dados evitando que dados incoerentes sejam armazenados revelando as falhas prematuramente. Por conta desta característica que visa ao aumento da confiança de um produto através da exposição de suas falhas, a integridade de dados não poderia facilmente ser confundido com um tipo de teste de software “semiautomático”?

INTEGRIDADE COMPLEMENTAR

Ainda que seja uma característica, e também compartilhe o objetivo de melhorar a qualidade final de um produto. Expor falhas é apenas a consequência casual do que a integridade de dados se propõe que é preservar a consistência semântica dos dados, diferente do teste de software onde a proposta é preservar o atendimento aos requisitos. E embora as restrições de integridade tenham evoluído com a introdução do conceito de restrições explícitas aos sistemas de gerenciamento de banco de dados, a prática de utilizar regras de negócio no banco de dados foi desestimulada com o advento da engenharia de software por questões de manutenabilidade, sendo classificadas como “linguagens alienígenas” por muitos especialistas.

Por esta razão, na Integridade Complementar, diferente da integridade de dados, as regras devem pertencer ao domínio de ferramentas de testes, sendo executadas fora da fronteira da aplicação, desacoplada e totalmente independente da mesma e vice-versa. Sua natureza é destrutiva, já que seu objetivo é revelar falhas em um produto para que as causas dessas falhas sejam identificadas e possam ser corrigidas pela equipe de desenvolvimento antes ou depois da entrega ao usuário final com o mínimo de impacto possível às informações. As regras devem se limitar apenas ao fluxo de entrada de dados sem consistir dados já persistidos em momentos anteriores, exceto se a informação inserida depender desta informação. Uma regra deve ser declarativa e acessíveis aos analistas de sistemas, analista de negócios e analistas de testes. Durante a análise modelos são construídos principalmente para melhor entender o sistema, descrever a estrutura e comportamento desejados, visualizar a arquitetura e documentar as decisões tomadas durante o seu desenvolvimento. Na Integridade Complementar estas informações viram regras que se violadas geram uma exceção. E estas regras estarão lá presente durante todo o ciclo de vida do requisito.

Embora a modelagem colabore em muito na redução de falhas não existe um critério definido para medir a completude de uma especificação, então por mais detalhados que sejam as informações ainda são sujeitas a ambiguidade, incompletude e inconsistência. Na Integridade Complementar este risco é reduzido, pois o analista é responsável por desenvolver as regras que irão validar a consistência das informações inseridas. A modelagem deixa de ser um documento estático e vira uma informação ativa, um compromisso. O objetivo final da Integridade Complementar é tornar o sistema mais consistente, quanto mais evolução o sistema sofrer mais regras serão criadas e mais consistente o sistema se torna.

Durante a evolução ou manutenção do sistema o analista cria as regras para garantir a integridade do requisito; 2) O analista aponta as áreas de impacto onde as regras serão inicializadas (Áreas instáveis); 3) Conforme os testes vão ocorrendo durante a programação ou o desenvolvimento as regras vão se tornando estáveis; 4) Dentro do ciclo de testes o testador poderá acompanhar o grau de estabilidade das regras que poderá servir de apoio para direcionar os testes.

https://www.imageupload.co.uk/image/ZjV1

A Integridade Complementar não é uma alternativa de teste, mas um complemento, seu objetivo não é identificar todos os erros, mas focar nos erros com maior custo de retrabalho. Se pensarmos, por exemplo, em diagrama de sequência de uma autenticação de usuário, quantos casos de testes seriam necessários para cobrir todas as possibilidades de erro? No entanto nenhuma destas possibilidades poderia ser automatizada pela integridade complementar. Na GOVBR, 20% da quantidade de erros são responsáveis por 50% do custo em retrabalho. Destes 20%, 85% referem-se a erros de integridade de dados (qualquer defeito que além da intervenção no código fonte, precise também de ajustes na base de dados), e 13% são referentes a problemas de desempenho. Se considerarmos apenas o ganho em retrabalho, a prática da Integridade Complementar na GOVBR, segundo análise, poderia reduzir até 40% do custo total da manutenção. Sem considerar nesta análise por exemplo, sua vocação natural em evitar ambiguidades ou mesmo a redução de custo em testes pela automação de partes dos processos. Integridade complementar é um jogo, onde o analista cria as regras para garantir a integridade dos requisitos. Cada vez que uma regra expõe uma falha, o analista ganha. Mas se um único erro gerar um dado inconsistente na base de dados, o analista perde.

Resumindo tudo que já foi apresentado, a Integridade Complementar é uma proposta de uma abordagem de teste com base em um processo de gestão de integridade onde cada requisito se transforma em uma ou várias regras monitorando o fluxo de dados durante os testes e agindo sempre que uma regra é violada. Ela é constituída por três classes de regras. A primeira é as Regras de Domínio, onde nela são catalogadas as regras que por si mesmas fornecem conhecimento sobre o sistema, em segundo são registradas as Regras de Causa e Efeito e em terceiro as Asserções. Foi visto também que uma regra precisa ser desacoplada, estar fora da fronteira da aplicação, ser independente, usar linguagem declarativa, estar vinculadas aos requisitos e validar somente a entrada de dados sem se preocupar com dados já salvos em momentos anteriores. Além destas características as regras precisam ser inteligentes, sugerir testes e informar o grau de estabilidade.

Para facilitar o entendimento do problema que a técnica se propõe a resolver, e para servir de padrão na criação das regras nos projetos, a seguir são apresentadas as regras da Integridade Complementar.

1) REGRAS DE DOMÍNIO

Garante a integridade dos dados limitando os valores ou as causas possíveis, não define, o que o sistema deve fazer, mas o que ele pode ou não fazer. Formam a base de conhecimento do sistema sendo fundamentais para que as regras possam auxiliar com precisão no critério de cobertura de testes com o intuito de tornar as regras estáveis. É importante entender que não somente os atributos devem ser documentados, mas principalmente as causas. Por exemplo, se uma classe contém um atributo que mantém o tipo de empresa, é necessário restringir os tipos possíveis de empresa para garantir que não seja inserido um tipo de empresa inválido, e é relativamente óbvio. Mas não é este o único motivo, a questão é que existem muitas regras de negócios que são específicas para cada tipo de empresa, ou em outras palavras, cada tipo de empresa é uma possível causa para diversas regras de negócios. Já por exemplo, o salário de um funcionário, não tem uma lista de valores possíveis, pode ser qualquer valor, então dificilmente teríamos regras de negócio diferente para cada possibilidade de salário. Mas supomos que uma empresa conceda uma gratificação aos seus empregados que ganhem até dois salários mínimos, neste caso temos duas causas: Menor ou igual a dois salários mínimos, e maior que dois salários mínimos. Estas causas devem ser cadastradas na forma de um atributo calculado com dois valores possíveis, por exemplo, “Faixa Salarial 1” e “Faixa Salarial 2”, ou na forma de dois atributos. A responsabilidade pela consistência destas regras é do analista de negócios ou analista de sistema.

1.1) Regra Primária

Baseado nas diretrizes para identificar as Classes de Equivalência do Critério Funcional, Particionamento em Classes de Equivalência e do Teste de Validação de Entrada, proposto por Harrold e Offutt (1993), que identifica os dados de teste que tentam mostrar à presença ou a ausência de falhas específicas, pertinentes a “tolerância a entradas”. Esse tipo de regra preocupa-se com a consistência dos dados, como: tamanho, valor (mínimo e máximo), tipo de dado, existência de valor único, garantia da existência do valor de chave estrangeira na entidade forte, valor do atributo dentro do intervalo válido estabelecido, valor nulo (ou zero) para o atributo, tamanho do atributo dentro do limite determinado e leiaute dos dados armazenados. Na GOVBR estas regras são extraídas principalmente do documento de especificação ou do diagrama de classes. É denominada Regra Primária pela forte ligação que tem com a estrutura dos dados. Algumas características próprias das linguagens orientadas a objetos, linguagens de modelagem, e padrões de projetos tendem a erradicar este tipo mais básico de erro, no entanto, a orientação a objetos ainda não está acessível a todos os sistemas. E na Integridade Complementar as regras são criadas pelo analista, que servirá como um denominador comum entre analista e desenvolvedor.

1.2) Tabela Verdade

“Tabela verdade, tabela de verdade ou tabela veritativa é um tipo de tabela matemática usada em Lógica para determinar se uma fórmula é válida ou se um sequente é correto.” (TABELA VERDADE, 2015). É o conjunto de todas as possibilidades combinatórias entre valores de diversas variáveis lógicas (binários), as quais se encontram em apenas duas situações (V)erdadeiro ou (F)also, e um conjunto de operadores lógicos.

https://www.imageupload.co.uk/image/ZjVH

1.3) Transição de Estados

Durante o tempo em que um objeto permanece instanciado, assume-se que este objeto esteja em algum estado que satisfaça uma determinada condição, e esteja executando alguma atividade ou aguardando a ocorrência de algum evento. Esta condição reflete o resultado dos eventos caracterizados pela reação. Para Larman (2004) o objetivo é validar todas as transições atingíveis do diagrama de estado. Um estado representa a situação em que um objeto se encontra em um determinado momento durante o período que este participa de um processo. Um estado pode demonstrar: A espera pela ocorrência de um evento; A reação a um estímulo; A execução de uma atividade; A satisfação de alguma condição. De acordo com Korson e McGregor (1994), utilizando a lista de verificação como referência para o teste, associada a correta aplicação dos critérios de cobertura, a aplicação estará, na maioria das vezes, isenta de erros.

https://www.imageupload.co.uk/image/ZjVp

1.4) Associação e Cardinalidade

Binder (1999) afirma que, mesmo nos casos em que a associação seja simples, a implementação pode ser feita de diversas maneiras. Isto apresenta oportunidades diferentes para a ocorrência de erros, requerendo testes estruturais diferenciados para atender às características de cada uma delas. Ainda segundo o mesmo autor, alguns dos prováveis erros em associações são: Multiplicidade Incorreta: a implementação da associação permite a rejeição ou aceitação de uma combinação de instâncias ilegal. Anomalias na Alteração: a ligação que associa diversas instâncias de uma classe com uma única instância de outra classe possui alguma informação redundante. Quando alguma mudança for feita em uma instância de classe, as instâncias associadas também devem ser modificadas. Anomalias na Eliminação: O que acontece aos objetos associados à uma classe caso esta seja eliminada? Deve-se eliminá-los automaticamente? Dependendo da forma com que o sistema foi projetado, a implementação deverá encontrar, remover ou alterar cada uma das associações. Não deve ser confundida com a Regra Primária que garante a existência do valor de chave estrangeira na entidade forte. A Associação e Cardinalidade é voltada ao negócio, uma tabela de parâmetro que sempre deveria conter dados é uma violação de integridade se estiver vazia. Um cadastro que é persistido sem endereço é uma violação de integridade se o requisito definir que todo cadastro deve ter no mínimo um endereço. Um rateio que é feito entre os departamentos de uma empresa em uma determinada aquisição será inconsistente se neste rateio for incluído um departamento de outra empresa.

1.5) Dependência

Como explicado anteriormente, uma tabela de parâmetro que sempre deveria conter dados viola a integridade se estiver vazia. Mas quando esta integridade seria violada se uma tabela obrigatoriamente é criada vazia? A resposta é simples, quando algum processo precisar, por exemplo: Vamos supor que exista um parâmetro que indique a quantidade máxima de parcela de acordo com o valor de uma venda e ao efetuar a venda não exista parâmetros algum informado. Nesta regra são catalogadas todas as entidades dependentes, pode ser uma dependência de algum atributo específico, de vários atributos ou nenhum atributo, pode simplesmente depender que ela esteja consistente. Uma guia de pagamento para ser efetuada pode depender, por exemplo, de uma tabela de feriados. Não existe relação física entre uma guia de pagamento e uma tabela de feriados, mas pode existir um requisito que determine dependência entre as duas já que se os feriados não forem cadastrados para o ano corrente ou, se os feriados cadastrados não estiverem consistentes, existe um grande risco da guia de pagamento gerar dados inconsistentes. Esta regra é dependente de todas as demais regras apresentadas anteriormente.

2) REGRAS DE CAUSA E EFEITO

Dado que a realização do teste exaustivo (testar todas as entradas e saídas do domínio) não é factível, então é necessário selecionar um pequeno subconjunto que tenha a capacidade de representar todas as entradas possíveis, se possível um subconjunto que tenha alta probabilidade de revelar a maioria dos potenciais defeitos existentes (KANER e FALK, 1999). A estes critérios dá-se o nome de critérios de cobertura ou critérios de seleção. Trata-se de condições que devem ser preenchidas pelo teste, as quais selecionam determinados caminhos que visam cobrir o código implementado ou representação gráfica deste. Grafo de Causa e efeito é uma técnica que pode ser usada para combinar as condições e obter um conjunto eficaz de casos de teste que pode revelar inconsistências na especificação. No entanto, a especificação deve ser transformada em um gráfico que se assemelha a um circuito de lógica digital. O gráfico deve ser convertido em uma tabela de decisão que o testador utiliza para desenvolver casos de teste (CORAZZA, 1999). Este método é bastante pois faz uma análise completa à especificação do software. Os problemas podem surgir quando o número de causas é elevado, visto que o número de casos de teste gerados é também muito elevado. A técnica segue quatro passos: Causas (condições de entrada) e efeitos (ações) são relacionados para um módulo e um identificador é atribuído a cada um. Um grafo de causa-efeito (descrito a seguir) é desenvolvido. O grafo é convertido numa tabela de decisão. As regras da tabela são convertidas em casos de teste.

Na Integridade Complementar as Regras de Causa/Efeito garante a integridade de toda a informação gerada pelo sistema de forma automática. Um simples registro de pagamento pode gerar dezenas de informações tais como rateios, históricos, extrato, saldo, bônus, estatísticas, resumos, e etc. Diferente da categoria anterior, esta não limita os valores possíveis, não alimentam a base de conhecimento sobre a estrutura de armazenamento, mas restringe o exato valor que é esperado como resultado de uma operação. Quantas vezes durante o ciclo de vida de um sistema, defeitos de ordem diversa corrompem os dados e os mesmos são reconstruídos na manutenção do sistema. Como isso é possível? Quase sempre é possível porque geralmente os dados corrompidos são os dados automáticos gerados por algum processo do sistema, mas a entrada de dados do usuário geralmente é preservada, e é com estas informações de entradas consistentes que todos os demais dados são reconstruídos. Todas as informações para reconstruir geralmente estão armazenadas no banco de dados, e quase sempre de forma redundante, em históricos, rateios, logs, etc. Da mesma forma podemos consistir cada informação gerada pelo sistema. A responsabilidade da consistência destas regras é do Analista de Sistemas.

Consistir cada informação gerada pelo sistema pode muitas vezes exigir cálculos sofisticados e lógica de programação. Isto ocorre principalmente por causa da complexidade do requisito, ou muitas vezes pela própria estrutura de dados do modelo relacional, que não privilegia a simplicidade de acesso às informações. Como mencionado anteriormente, as regras da integridade complementar devem ser declarativas, e existe uma razão para isto, as regras além de proteger os requisitos validando as entradas de dados, também precisam atender outros propósitos tais como, indicar a estabilidade, medir sua própria eficácia, medir seu custo benefício e sugerir critérios de testes. Para isso as Regras de Causa e Efeito precisam ser formadas pela seguinte estrutura: A regra precisa estar associada a uma entidade base, que quando alterada, incluída, excluída irá executar a regra. A causa ou condição que fará com que uma regra seja disparada deve ser uma expressão simples formada pelo operador lógico igual “=” e o operador booleano “And”, nenhum outro operador deve ser utilizado. Uma regra precisa atender a um efeito, que é uma expressão que forma um resultado, um atributo ou uma expressão. Ela deve atender a somente uma causa/efeito. E cada regra precisa estar associada a uma área do sistema.

Esta categoria torna possível identificar o nível de estabilidade do sistema, pois da ao sistema o conhecimento das causas e os efeitos por área.

https://www.imageupload.co.uk/image/ZjVq

3) ASSERÇÕES

Na Integridade Complementar, que pode ser classificada como um teste funcional, as asserções são avisos, advertências, mensagens inseridas pelo analista de testes como um diagnóstico para o testador, realizando um checklist automático sempre que uma informação é submetida ao banco de dados. Pode ser um checklist de um rateio complexo num processo de pagamento, ou também para validar um requisito funcional. Se por exemplo, um requisito definir que o salário de um empregado nunca pode diminuir, uma asserção pode ser criada para alertar sempre que esta regra for violada.

As Asserções se diferenciam das regras de Causa e Efeito por não serem restrições, mas apenas advertências ou avisos e principalmente por serem de responsabilidade do Analista de Teste, pois as regras são extraídas exclusivamente de casos de testes ou, por assim dizer, é o próprio caso de teste.

4) REFERÊNCIAS BIBLIOGRÁFICAS

BINDER, R. V. Testing object-oriented systems: Models, patterns, and tools. 1. ed. Boston, AddisonWesley, 1999.

BRUCE, P.; PENDERSON, S. The software development project. New York: John Wiley & Sons, 1982.

CORAZZA, E. A. M. Critérios de cobertura para o teste de software orientado a objetos. Porto Alegre: PGCC da UFRGS, 1999.

CRISPIN, L; House, T. Testing extreme programming. The XP Series. 1. ed. Boston: Addison-Wesley, 2003.

CROSBY, P.B. Quality is Free: the Art of Making Quality Certain. São Paulo, SP: Mentor Books, 1992.

GARTNER GROUP. The project office: Teams, processes, and tools. 01 ago. 2000. Disponível em: https://www.gartner.com/doc/308328/project-office-teams-processes-tools. Acesso em: 23 fev. 2015.

KANER, C.; FALK, J.;NGUYEN, H. Q. Testing computer software. 2. ed. New York: John Wiley & Sons, 1999.

LARMAN, C. Applying UML and patterns: An introduction to object-oriented analysis and design. 3. ed. Prentice-Hall: Englewood Cliffs, 2004.

McGREGOR, J. D.; KORSON, T. D. Integrated Object-Oriented Testing and Development Processes. Communications of the ACM, New York, v.37, n.9, p.59-77, Set. 1994.

MYERS, G.J. The art of software testing. New York: John Willey & Sons: 1979.

OFFUTT, A. J.; HARROLD, M. J. A software metric system for module coupling. The Journal of Systems and Software, New York, v.20, n.3, p. 295-308, mar. 1993.

TABELA VERDADE. WIKIPÉDIA, a enciclopédia livre. Flórida: Wikimedia Foundation, 2015. Disponível em: <http://pt.wikipedia.org/w/index.php?title=Tabela_verdade&oldid=41243675>. Acesso em: 8 fev. 2015.

Artigo completo: