Teste de Software - Início | Faculdade de Computaçãobacala/ES/Teste de Software.pdf · maneiras...

15
Teste de Software A última etapa do desenvolvimento de um software é a fase de testes. A fase de testes é de fundamental importância, pois através dela é possível detectar e solucionar erros no software. No decorrer de todo o desenvolvimento, atividades de garantia de qualidade do software são executadas, porém, a possibilidade de continuar encontrando erros é enorme, mesmo depois de concluído o desenvolvimento do software. Segundo Pressman (1995), na fase de testes, os engenheiros executam uma série de atividades que consistem em varrer o software criado a procura de qualquer tipo de erro ou falha na codificação, que possam vir a interferir no correto funcionamento do aplicativo. O teste é responsável por detectar o maior número possível de erros, pois encontrar todos é praticamente impossível. Os testes de software são responsáveis por executar o software utilizando valores reais, com a finalidade de encontrar erros. Caso os testes sejam realizados e nenhuma falha seja descoberta, provavelmente, os casos de testes não foram bem elaborados. Seguindo o raciocínio de Pressman (1995), os casos de testes devem elevar a probabilidade de detecção de erros, caso contrário, os testes não serão bem sucedidos. Pressman (1995) defende ainda que o teste bem sucedido, além de apontar falhas ainda não constatadas, deve fazer isso com o mínimo tempo e esforço. Os testes são realizados com a inserção de dados atuais para que se possam obter os resultados esperados de acordo com os requisitos e especificações previamente estabelecidos. Se os dados de saída são os esperados, significa que as informações geradas pelo software são legítimas e totalmente confiáveis. Apesar de todos os esforços exigidos na fase de teste, é comum que o software não funcione completamente sem a ausência de erros. Falhas fazem parte do código de programação, isso muitas vezes acontece devido à complexidade do desenvolvimento de software e da negligência dos desenvolvedores nas fases iniciais da elaboração de um sistema. Mesmo que os testes, por mais eficazes que sejam, não consigam detectar e remover todos os erros contidos no software, estes são indispensáveis pois aumentam o grau de segurança, e consequentemente, a confiança no produto pelo desenvolvedor e pelo cliente. Inthurn (2001) afirma que há um gasto frequente muito grande de tempo e dinheiro em correções de software, em que o desenvolvimento não foi adequado e a fase de testes não foi satisfatória. Assim, entende-se que os testes são importantes, também, para evitar surpresas desagradáveis no futuro. Além disso, os testes são responsáveis por mostrar que o software possui erros e que os mesmos devem ser corrigidos, mas isso não significa que a partir das correções, o software estará imune a possíveis falhas posteriores. Novos erros podem ser inseridos ao software no momento em que outros erros são corrigidos, através de alterações realizadas no código a fim de corrigir os erros descobertos até o momento. De acordo com Inthurn (2001), os testes bem sucedidos conseguem, em média, corrigir aproximadamente 60% das falhas contidas no software. O custo dos testes realizados dentro do processo de desenvolvimento é relativamente pequeno se comparado ao gasto com manutenção corretiva do software pronto, sem mencionar que para, um software ter qualidade, é necessário que haja uma rotina exaustiva de testes, que se estende por todo o desenvolvimento do projeto. Jamais a atividade de teste deve trabalhar de maneira isolada, mas sim de maneira conjunta com as demais atividades e de forma iterativa. Os casos de teste devem testar as partes produzidas em cada etapa do projeto e o produto completo ao final do projeto. Só assim a qualidade do produto final é garantida. A atividade de testes é dividida de diferentes

Transcript of Teste de Software - Início | Faculdade de Computaçãobacala/ES/Teste de Software.pdf · maneiras...

Teste de Software

A última etapa do desenvolvimento de um software é a fase de testes. A fase de testes é de fundamental importância, pois através dela é possível detectar e solucionar erros no software. No decorrer de todo o desenvolvimento, atividades de garantia de qualidade do software são executadas, porém, a possibilidade de continuar encontrando erros é enorme, mesmo depois de concluído o desenvolvimento do software.

Segundo Pressman (1995), na fase de testes, os engenheiros executam uma série de atividades que consistem em varrer o software criado a procura de qualquer tipo de erro ou falha na codificação, que possam vir a interferir no correto funcionamento do aplicativo. O teste é responsável por detectar o maior número possível de erros, pois encontrar todos é praticamente impossível. Os testes de software são responsáveis por executar o software utilizando valores reais, com a finalidade de encontrar erros. Caso os testes sejam realizados e nenhuma falha seja descoberta, provavelmente, os casos de testes não foram bem elaborados. Seguindo o raciocínio de Pressman (1995), os casos de testes devem elevar a probabilidade de detecção de erros, caso contrário, os testes não serão bem sucedidos. Pressman (1995) defende ainda que o teste bem sucedido, além de apontar falhas ainda não constatadas, deve fazer isso com o mínimo tempo e esforço.

Os testes são realizados com a inserção de dados atuais para que se possam obter os resultados esperados de acordo com os requisitos e especificações previamente estabelecidos. Se os dados de saída são os esperados, significa que as informações geradas pelo software são legítimas e totalmente confiáveis.

Apesar de todos os esforços exigidos na fase de teste, é comum que o software não funcione completamente sem a ausência de erros. Falhas fazem parte do código de programação, isso muitas vezes acontece devido à complexidade do desenvolvimento de software e da negligência dos desenvolvedores nas fases iniciais da elaboração de um sistema.

Mesmo que os testes, por mais eficazes que sejam, não consigam detectar e remover todos os erros contidos no software, estes são indispensáveis pois aumentam o grau de segurança, e consequentemente, a confiança no produto pelo desenvolvedor e pelo cliente.

Inthurn (2001) afirma que há um gasto frequente muito grande de tempo e dinheiro em correções de software, em que o desenvolvimento não foi adequado e a fase de testes não foi satisfatória. Assim, entende-se que os testes são importantes, também, para evitar surpresas desagradáveis no futuro. Além disso, os testes são responsáveis por mostrar que o software possui erros e que os mesmos devem ser corrigidos, mas isso não significa que a partir das correções, o software estará imune a possíveis falhas posteriores. Novos erros podem ser inseridos ao software no momento em que outros erros são corrigidos, através de alterações realizadas no código a fim de corrigir os erros descobertos até o momento.

De acordo com Inthurn (2001), os testes bem sucedidos conseguem, em média, corrigir aproximadamente 60% das falhas contidas no software. O custo dos testes realizados dentro do processo de desenvolvimento é relativamente pequeno se comparado ao gasto com manutenção corretiva do software pronto, sem mencionar que para, um software ter qualidade, é necessário que haja uma rotina exaustiva de testes, que se estende por todo o desenvolvimento do projeto.

Jamais a atividade de teste deve trabalhar de maneira isolada, mas sim de maneira conjunta com as demais atividades e de forma iterativa. Os casos de teste devem testar as partes produzidas em cada etapa do projeto e o produto completo ao final do projeto. Só assim a qualidade do produto final é garantida. A atividade de testes é dividida de diferentes

maneiras por diversos autores. Por exemplo, segundo Peters (2001), a atividade de testes é constituída das atividades chaves, planos de teste, projetos de teste, casos de teste, procedimentos de teste, execução de teste e relatório de teste.

Já Pressman (1995) divide como técnicas de teste de software e estratégias de teste de software. Segue os estudos das atividades de teste de software focando as definições deste último autor.

Técnicas de teste de software

Segundo Pressman (1995), técnicas de teste de software consistem em elaborar casos de teste capazes de varrer o software a procura de erros ainda não constatados. As atividades de testes não visam culpar alguém por falhas ou, ainda, testar o software com finalidade destrutiva. Os testes são realizados com o objetivo de encontrar as falhas e, posteriormente, corrigi-las, garantindo assim a qualidade do mesmo.

Dentro das atividades de testes todos os resultados obtidos são avaliados, essa avaliação é realizada comparando-se os resultados obtidos com os esperados. Caso sejam encontrados erros, é feita a depuração.

Projeto de casos de teste

Um projeto de teste requer uma atenção especial dos engenheiros, pois os testes a serem realizados devem possuir uma alta probabilidade de descobrir os erros ainda não detectados, em um prazo relativamente curto e com esforços irrelevantes. Outro fato que exige que o projeto seja bem elaborado é a questão dos valores, pois o custo de manutenção para correção de erros após o término do desenvolvimento pode ser de 60 a 100 vezes mais do o custo da manutenção realizada durante o desenvolvimento (PRESSMAN, 1995).

Um software pode ser testado de duas formas. A primeira, quando se conhecem as suas funções e quais as saídas esperadas quando se recebem tais entradas, é popularmente conhecida como teste de caixa preta. E a segunda, quando se conhece a estrutura e o funcionamento interno, a maneira que os métodos estão interligados, quais as responsabilidades de cada um deles, dentre outros detalhes, é chamada de teste de caixa branca.

Segundo Inthurn (2001), um projeto de teste é responsável por gerenciar a fase de teste identificando e descrevendo qual tipo de teste será aplicado em determinado momento. O projeto de teste é dependente de um plano de teste, esse plano mostra as estratégias para a execução do teste com base numa lista de casos de teste.

Plano de teste

Dentre outros objetivos, o plano de teste deve identificar os componentes do software que serão testados e os recursos necessários para a correta execução dos mesmos, recomendando e descrevendo as estratégias de teste a serem aplicadas. O plano de teste deve conter e disponibilizar a documentação referente ao projeto em desenvolvimento, seus requisitos funcionais e não funcionais, a fim de entender o que será testado no software. O plano de teste deve conter as estratégias de teste, pois nela encontra-se a maneira como o teste será realizado e quais técnicas e critérios serão utilizados. Listas contendo os tipos de testes a serem aplicados, ferramentas, recursos de hardware e de pessoas disponíveis também são parte do plano de teste. A cada teste realizado, informações sobre o que foi realizado, data e hora de inicio e fim da atividade, nome do responsável pela mesma e resultados obtidos são registrados (INTHURN, 2001).

Caso de teste

Um caso de teste pode ser definido como um documento que descreve as etapas a serem seguidas para realização de um teste. Desde os dados de entrada, a atividade em execução e o resultado de saída. É utilizado para observar se o resultado de saída é realmente o esperado. Em caso positivo o teste foi realizado com êxito (INTHURN, 2001).

O caso de teste serve para verificar se o sistema segue as definições impostas no projeto e se o mesmo foi devidamente construído. Segundo Bartié (2002), o caso de teste é o documento que registra todo o planejamento dos testes, nele devem ser abordados os seguintes itens:

ƒ identificação das condições de testes;

ƒ identificação do que será testado;

ƒ definição de cada caso de teste identificado;

ƒ detalhamento das classes de dados de entrada;

ƒ detalhamento da saída gerada;

ƒ responsáveis pela atividade de teste;

ƒ definição de como será realizada a bateria de testes;

ƒ cronograma das atividades.

Suíte de teste

É o documento que faz o detalhamento final dos testes, nele é identificado o comportamento de cada caso de teste durante a execução. A suíte de teste estabelece a ordem de execução e a maneira que cada caso de teste irá proceder (BARTIÉ, 2002).

O objetivo do conjunto de teste é auxiliar no exercício de verificar as especificações dos requisitos funcionais e não funcionais do sistema, ou seja, constatar se o sistema procede normalmente durante a execução das funções.

Teste estrutural ou teste de caixa branca

Pressman (1995) define o teste de caixa branca como um método de projeto de casos de testes voltado a testar a estrutura interna do software. O teste de caixa branca, ao contrário de teste de caixa preta, se preocupa em como o código fonte foi construído e a lógica de programação utilizada no desenvolvimento dos métodos. O teste é totalmente realizado na estrutura interna do software (INTHURN, 2001).

O teste estrutural visa confirmar ou se certificar de que a estrutura interna do software esteja correta. Para isso, é preciso que o caso de teste percorra todos os caminhos internos possíveis. A atividade de teste estrutural pode ser considerada complexa porque deve abranger todos os níveis de hierarquia, no caso de classes com herança. O fato de um método funcionar corretamente em uma classe não garante que o mesmo não apresente erros na classe que a herde (INTHURN, 2001).

Teoricamente, um teste de caixa branca seria capaz de avaliar e classificar um software como 100% correto, isso porque o teste de caixa branca percorre todos os caminhos lógicos possíveis, o que resulta num teste exaustivo e complexo, pois mesmo em um programa pequeno, os caminhos lógicos são muitos (PRESSMAN, 1995). O teste de caixa branca, também, pode ser conhecido como testes de caixa de vidro, ou ainda, testes de caixa clara (SOMMERVILLE, 2003).

Bartié (2002) aponta dificuldades em aplicar o teste de caixa branca em alguns casos. O teste de caixa branca deve ser realizado por um profissional competente e extremamente experiente, pois o responsável por aplicar o teste deve conhecer minuciosamente a estrutura do software. O teste será executado pelos próprios desenvolvedores, e como os

desenvolvedores normalmente trabalham sob pressão, o software tem que ficar pronto rapidamente. Este fato faz com que a preocupação do desenvolvedor seja maior com a implementação, de forma que os testes acabam ficam em segundo plano.

Teste funcional ou teste de caixa preta

Segundo Inthurn (2001), o teste de caixa preta consiste em verificar na interface do software se todas as funcionalidades estão operando corretamente. Este teste é aplicado com a finalidade de encontrar: funções incorretas ou ausentes, erros de interface, erros nas estruturas de dados ou no acesso ao banco de dados, erros de desempenho e, ainda, erros de inicialização e término.

O teste funcional, como o próprio nome já diz, é realizado com base nos requisitos funcionais do software, assim, é possível analisar as entradas e saídas de todas as unidades. Para isso os dados de entrada devem ser normalmente aceitos pelo sistema e a saída deve ser a esperada. Caso a saída não seja a esperada, o erro é constatado. Esse tipo de teste não se preocupa em saber como o código fonte foi produzido e sim se o mesmo faz o que lhe foi

especificado.

As técnicas de caixa preta são responsáveis por garantir que todos os requisitos do sistema funcionem de acordo com o especificado durante a elaboração do projeto. Cabe aos testes de caixa preta averiguar que o sistema forneça todos os resultados esperados.

Uma vantagem do teste de caixa preta em relação ao teste de caixa branca é que nesse não é necessário que a equipe de testes conheça ou entenda a estrutura interna, a tecnologia utilizada e a maneira como foi implementado, e sim, que verifique se faz o que foi proposto e se atenderá as necessidades do futuro usuário. No teste de caixa preta o profissional responsável pela execução do teste necessita apenas entender os requisitos e analisar os resultados produzidos (BARTIÉ, 2002).

O teste de caixa preta consiste em validar os requisitos funcionais do sistema, o objetivo é encontrar erros de interface, erros relacionados ao desempenho, ao acesso ao banco de dados, erros de inicialização e término, falha ou ausência de funções (PRESSMAN, 1995).

Este último autor define alguns tipos de teste de caixa preta, entre eles o particionamento da equivalência e análise do valor limite. No primeiro, os dados de entrada são divididos em classes de forma que os casos de teste possam ser derivados. O particionamento de equivalência permite que seja definido um caso de teste capaz de encontrar uma ou mais classes de erros. Um exemplo poderia ser um caso de teste que identifique problemas sempre que um tipo específico de dado é utilizado. O particionamento

de equivalência é normalmente representado por um conjunto de dados de entrada, válidos ou inválidos para o sistema.

Na segunda, análise do valor limite, a intenção do teste é colocar em prova os valores fronteiriços, ou seja, analisar as extremidades do sistema. Difere-se um pouco do particionamento de equivalência porque além de testar os dados de entrada, analisa também os dados de saída. O teste pode ser feito da seguinte forma: se os parâmetros de entrada devem respeitar o intervalo entre 0 e 4, inserir números normais, ou seja, entre 0 e 4, depois um número abaixo do especificado e em seguida um número acima do especificado. Assim, é possível testar se as condições de entrada estão sendo validadas. O mesmo critério deve ser utilizado para analisar dos dados obtidos na saída.

Teste de caminho básico

O teste de caminho básico é conhecido como uma técnica de teste de caixa branca. Através do teste de caminho básico é possível definir os diversos caminhos de execução do software e garantir que cada um deles seja executado ao menos uma vez (PRESSMAN, 1995). O número de caminhos é proporcional ao tamanho e complexidade do software. Devido aos módulos não trabalharem sozinhos, ou seja, são apenas partes de um sistema, fica inviável a utilização dos testes de estrutura. Dessa forma, testes de caminho básico são mais utilizados nos testes de unidade (SOMMERVILLE, 2003).

Antes de executar o teste de caminho básico é importante criar o modelo de representação do trecho de código a ser testado, para facilitar o entendimento do fluxo de controle. Nessa representação são utilizados fluxogramas e grafos. A figura 01 mostra um fluxograma simplificado de um teste de caminho básico.

Fluxograma de um teste do caminho básico

O fluxograma acima pode ser facilmente representado em forma de grafos de fluxo, como mostrado a seguir.

Grafo de fluxo do fluxograma da figura 1.

As linhas do grafo traçam os possíveis caminhos. É importante que a cada laço o teste utilize um caminho independente até que todos os caminhos sejam percorridos. Caminhos independentes são aqueles que executam instruções que ainda não foram executadas (PRESSMAN, 1995).

Para encontrar o número de caminhos independentes é necessário realizar o cálculo da complexidade ciclomática do grafo de fluxo do programa, esse cálculo é feito através da fórmula (SOMMERVILLE, 2003):

CC(G) = Número (ramos) – Número (nós) + 2

sendo as setas correspondentes aos ramos e os círculos correspondentes aos nós, para o grafo de fluxo na figura 02, CC(G) = 11 – 9 + 2 = 4. Quatro é o número de caminhos independentes.

Caminhos independentes:

Caminho 1: 1-11

Caminho 2: 1-2-3-4-5-10-1-11

Caminho 3: 1-2-4-6-8-9-10-1-11

Caminho 4: 1-2-3-6-7-9-10-1-11

Caminho não independente:

Caminho 5: 1-2-3-4-5-10-1-2-3-6-8-9-10-1-11

O caminho 5 não é independente porque todas as suas instruções já foram executadas anteriormente, ou seja, não encontrou instruções ainda não executadas.

Pressman (1995) mostra duas outras maneiras de encontrar o número de caminhos independentes, além da fórmula apresentada por Sommerville (2003). Uma é encontrando o número de regiões (fechamento dos nós), que corresponde ao número de caminhos. A outra, o número de nós predicativos (nó que apresenta condicional) mais um corresponde ao número de caminhos independentes. De acordo com o grafo de fluxo:

CC(G) = Ramos – Nós + 2 = 11 – 9 + 2 = 4

CC(G) = Nós predicativos + 1 = 3 + 1 = 4

CC(G) = Regiões = 4

Genericamente, o teste de caminho básico não testa todas as combinações possíveis de todos os caminhos do software, pois, devido ao grande número de laços de repetições existentes, a quantidade de combinações de caminhos é infinita (SOMMERVILLE, 2003).

O teste de caminho básico é simples e eficaz, e ainda pode ser complementado por outros tipos de testes, para, assim, encontrar e corrigir o maior número possível de falhas, são eles o teste de condição, teste de fluxo de dados e o teste de laços (PRESSMAN, 1995).

Teste de condição

O teste de condição é um método de projeto de casos de testes responsável por certificar que todas as condições lógicas de um módulo do programa funcionem corretamente. Uma condição simples pode ser definida como duas expressões aritméticas separadas por um operador relacional (PRESSMAN, 1995):

E1 <operador relacional> E2,

em que E1 e E2 são as expressões aritméticas e o operador relacional sendo qualquer um desses (<, ≤, =, ≠, >, ≥) ou ainda operadores booleanos (OR, AND e NOT). Uma condição composta é definida com a união de duas ou mais condições simples.

O teste de condição consiste em testar cada condição existente no programa à procura de erros. Uma condição é considerada incorreta quando pelo menos um componente da condição está incorreto, ou seja, operadores lógicos ou booleanos ausentes ou a mais. O mesmo acontece com os parênteses, além de erros na própria expressão aritmética ou operador relacional.

Para encontrar erros nos operadores relacionais, três testes são realizados, considerando que as expressões aritméticas estejam corretas, a E1 deve receber valores, maior, menor e igual a E2.

Teste de laços

Normalmente o número de estruturas de repetição, laços ou loops, como são conhecidos, utilizados na implementação de sistemas é muito grande, mesmo em pequenos softwares, isso porque essas estruturas são extremamente necessárias, ou melhor, é inviável a construção de um sistema sem a utilização de estruturas de repetição.

O teste de laços consiste em validar a estrutura dos laços. Existem quatro classes de laços: laços simples, laços concatenados, laços aninhados e laços não-estruturados (PRESSMAN, 1995):

ƒ Laços simples: cinco testes são realizados, 1) não entrando no laço; 2) somente uma passagem pelo laço; 3) duas passagens pelo laço; 4) enquanto m<n passagens pelo laço; e 5) n-1, n, n+1 passagens pelo laço.

Laços aninhados: deve-se testar primeiro o laço interno e iniciar com valores mínimos todos os laços; execute os testes de laços simples no laço interno sem alterar os valores do laço externo; continue realizando testes com valores inaceitáveis. Repita até que todos os laços sejam testados.

Laços concatenados: se os laços foram implementados de maneira individual, um independe do outro, o teste realizado é o mesmo do mostrado anteriormente no laço simples. Se os laços foram implementados de forma que um interaja com outro, ou seja, se o contador do primeiro laço for utilizado como valor inicial para o segundo laço, o teste a ser realizado é o mesmo mostrado anteriormente no laço concatenado.

Laços não-estruturados: para facilitar o teste é necessário reprojetar os grupos de laços de forma que os mesmos se assemelhem à programação estruturada.

Tipos de laços – retirada de (MARIATH, 2004).

Teste unitário

O teste unitário consiste em validar a menor unidade do projeto, uma classe de métodos, funções isoladas e unidades lógicas. A partir disso, testam-se módulos integrados a outros e outros, até que se tenha o sistema completo. O mesmo deve ser realizado diversas

vezes, dia a dia, isso porque as falhas sempre aparecem e fica mais fácil corrigir pequenas falhas do que corrigir o sistema inteiro depois de construído (MEDEIROS, 2005).

Medeiros (2005) afirma que a importância do teste unitário se dá na prevenção de futuros erros no sistema. A única maneira de saber se o código é realmente bom é testando sua reação diante de uma bateria de testes exaustivos, esses testes validam situações normais, que deveriam ser bem sucedidas e situações de erro.

O mesmo autor ainda cita um exemplo do mundo real: pensando na fundamental importância do teste unitário, imagine o resultado dos testes em um avião ou mesmo em um navio apenas após o término de sua construção. Se algo sair errado, os danos podem ser irreparáveis. Nada mais apropriado para descrever o resultado, do que uma tragédia.

Testes de verificação e validação de software

Toda a fase de teste de um software refere-se ao (V&V) ou verificação e validação. A verificação consiste em atividades que garantem que as funções do sistema tenham sido implementadas corretamente, e a validação em verificar que o software corresponde às expectativas do cliente (PRESSMAN, 1995). Segundo Sommerville (2003), os testes de validação ou verificação são responsáveis por constatar se o sistema desenvolvido está realmente de acordo com as especificações fornecidas pelo cliente e se satisfaz as suas necessidades.

Os testes de validação devem evoluir de acordo com o desenvolvimento do software, não sendo executados de maneira isolada, ou seja, sempre que um módulo ou uma classe é desenvolvido, testes são realizados. Os testes são incrementados a cada etapa de desenvolvimento, mais classes e funções implementadas, mais testes realizados.

Para que os erros sejam encontrados no início do processo, resumidamente Sommerville (2003) divide os testes de validação em 5 (cinco) estágios, sendo eles teste de unidade, teste de módulo, teste de subsistema, teste de sistema e teste de aceitação.

Teste de unidade: tem como objetivo averiguar que um componente do sistema está funcionando corretamente, para isso o teste é realizado em cada componente separadamente.

Teste de módulo: num sistema, um módulo corresponde a uma classe, um conjunto de métodos ou funções interligadas, ou seja, dependentes uma da outra. O teste é realizado visando verificar que o módulo todo está funcionando corretamente, se as conexões entre os métodos estão corretas e produzindo o esperado. O teste de módulo, assim como o teste de unidade, é normalmente executado por seus próprios desenvolvedores.

Teste de subsistemas: responsabiliza-se basicamente por testar pequenos conjuntos de módulos integrados, o objetivo é encontrar erros de interface de módulos e suas ligações.

Teste de sistema: o sistema consiste na união coerente dos subsistemas, o teste de sistema, por sua vez, consiste em descobrir possíveis falhas nas interações desses módulos e, ainda, em verificar que todos os requisitos funcionais ou não, estejam presentes.

Teste de aceitação: o teste de aceitação é o último realizado antes da entregado do software ao cliente. O teste é realizado utilizando valores reais vindos dos próprios clientes. O teste de aceitação pode trazer à tona diversos tipos de erros anteriormente não constatados, pois os dados reais criam situações não pensadas pelos desenvolvedores. Através do teste de validação é possível perceber se o sistema é estável e se possui um desempenho que corresponda às expectativas do cliente.

Segundo Inthurn (2001), o teste de sistema se subdivide em quatro outros tipos envolvendo todas as partes do software: Teste de recuperação; teste de segurança; teste de stress; e, por último, teste de desempenho.

Teste de recuperação: consiste em provocar diversos tipos de falhas, o sistema, porém, deve ser capaz de tolerar as mesmas, ou seja, um sistema tolerante a falhas é aquele consegue se recuperar de falhas sem que essas atrapalhem o seu funcionamento. O sistema deve se recuperar das falhas completamente num tempo relativamente pequeno e com o mínimo de intervenção humana. A geração de um log detalhando as atividades realizadas antes das falhas é interessante. Um dos objetivos do teste de recuperação é averiguar a maneira como o sistema se recupera dos erros, os mais comuns são, problemas no disco rígido, erros de interface e falhas referentes à falta de memória.

Teste de segurança: é responsável por verificar se todos os recursos de defesa do sistema realmente impedem os possíveis acessos indevidos. Esse tipo de teste deve ser realizado por uma equipe que não tenha participado do desenvolvimento. O seu objetivo é garantir que o sistema continue funcionando normalmente sob tentativas de acessos não permitidos. O correto é que as políticas de segurança do próprio sistema se encarreguem de protegê-lo desses acessos. Durante a execução dos testes, os responsáveis por ele devem utilizar todos os métodos disponíveis para tentar, de alguma forma, acessar o sistema indevidamente, neste caso, vale conseguir senhas ilegalmente, tentativas de acesso durante o processo de recuperação do sistema, entre outras ocasiões de falhas provocadas pelos próprios testadores.

Teste de stress: é realizado com o objetivo de forçar o sistema, por exemplo, executar várias buscas de dados no disco, abrir o maior número de janelas possível a fim de causar falta de memória. Enquanto isso, deve-se analisar a queda de desempenho do sistema e a maneira como ele se recupera, em caso de parada do sistema durante o processo, mais testes de recuperação devem ser executados.

Teste de desempenho: como o próprio nome já diz, é responsável por testar o desempenho do sistema, pode ser realizado em conjunto com o teste de stress. O objetivo desse tipo de teste é garantir que os requisitos de desempenho relatados durante o planejamento sejam alcançados. O teste de desempenho analisa o tempo de resposta das atividades, a capacidade do banco de dados, os momentos em que o sistema perde mais desempenho em função de um grande número de processos executando, dentre outros. Esse teste pode ser realizado executando alguma instrução inúmeras vezes, assim, é possível observar se o desempenho cai ou não.

Teste de integração

Durante o desenvolvimento do sistema os gerentes decidem quem ficará responsável por cada fase de teste, normalmente cada programador se encarrega de testar seu próprio código, ao final, as partes desenvolvidas por cada programador são passadas a outra equipe que irá unificar os códigos. Essa equipe realiza a integração do software e mais testes são feitos. Os testes são realizados em partes separadas ou subsistemas e no sistema como um todo, por fim o teste é detalhadamente documentado e arquivado (SOMMERVILLE, 2003).

Um dos objetivos do teste de integração é detectar problemas junto às interfaces, ou seja, erros que aparecem com a junção das partes do sistema. Antes da junção são realizados testes nos pedaços individuais do sistema, os erros encontrados são corrigidos, outros erros aparentemente “menores”, nem são notados. Mais tarde, com as partes do sistema integradas, aqueles erros “menores” podem se apresentar não tão pequenos assim, e causar falhas inaceitáveis no sistema (PRESSMAN, 1995).

Basicamente, o teste de integração consiste em verificar se as partes testadas individualmente funcionam também unidas umas as outras, (INTHURN, 2001).

Pressman (1995) define dois tipos de integração de sistemas: a não incremental e a incremental. A primeira consiste em desenvolver todos os módulos do sistema, realizar a junção dos mesmos, e só depois iniciar a fase de testes. Normalmente os erros são tantos e a dificuldade de correção é tamanha que o resultado é um sistema completamente inaceitável. O teste de integração incremental tende a assegurar que o sistema possua uma quantidade menor de erros, isso se faz possível pelo fato de que cada módulo do sistema é testado individualmente antes da junção com os demais módulos, com isso fica mais fácil detectar e corrigir os erros existentes. Após a junção novos testes são realizados para detectar outros erros que possam aparecer. Um módulo pode funcionar corretamente quando testado sozinho, e não funcionar normalmente quando integrado a outros módulos, por isso a importância dos testes antes e depois da integração.

Integração Top-down

É uma abordagem da integração incremental. Segue uma ordem hierárquica, de cima para baixo. Os módulos mais importantes do sistema são desenvolvidos primeiro, depois os menos importantes. Após desenvolvido, cada módulo é testado individualmente, integrado aos outros módulos e testado novamente, assim, é possível conferir se a interface com os demais módulos continua compatível.

Integração Bottom-up

A ordem de teste dos módulos é inversa à top-down, os módulos menos importantes, ou de níveis mais baixos da hierarquia são desenvolvidos e testados primeiro, depois os próximos níveis a cima na hierarquia até que o último módulo seja testado.

Depuração de software

A depuração ou debugging ocorre quando um caso de teste encontra e mostra erros do sistema, ou seja, para que se faça a depuração é necessário que os testes realizados tenham obtido êxito.

A depuração consiste em analisar os resultados obtidos com os esperados, e, no caso de diferença entre eles, encontrar a causa, ou seja, encontrar o motivo da não correspondência entre os dados reais e os esperados, e, por fim, corrigir o problema (PRESSMAN, 1995). Em resumo, a depuração objetiva encontrar e corrigir a causa, ou causas, dos erros no sistema.

Executando Testes de Software

A primeira classe possui três métodos a serem testados: fatorial(), maiorNumero() e par(). O processo de teste utilizando a técnica do teste do caminho básico no primeiro método é o seguinte: primeiro deve-se numerar o programa, como pode-se observar a seguir:

Código numerado:

O próximo passo consiste em desenhar o grafo para visualização dos

caminhos a serem executados:

Na sequência, deve-se calcular a complexidade ciclomática para se certificar que o número de caminhos está correto. Ele pode ser feito de três maneiras:

CC(G) = Ramos – Nós + 2 = 12 – 9 + 2 = 5

CC(G) = Nós predicativos + 1 = 4 + 1 = 5

CC(G) = Regiões = 5

O resultado comum aos três cálculos indica maior probabilidade do grafo

estar correto.

Por último, deve-se descrever os possíveis caminhos e valores de entrada, como é mostrado a seguir:

Caminhos Básicos

1. 1, 2, 9 2. 1, 3, 5, 9 3. 1, 3, 4, 5, 9 4. 1, 3, 4, 6, 9 5. 1, 3, 4, 6, 7, 8, ..., 6, 9

Entradas

1. valor = -2 -> -1 "Valor Negativo!!! Não é válido!!!" 2. valor = 0 -> 1 3. valor = 1 -> 1 4. Inválido. Deveria entrar no “while” 5. valor = 5 -> 120

Dessa forma, encontram-se e percorrem-se todos os possíveis caminhos do método. A próxima etapa consiste em automatizar os testes, por exemplo, utilizando o JUnit.

Os métodos de asserções consistem em afirmar que suas instruções são verdadeiras, como se observa nas linhas de 16 a 19, ou seja, se o valor inserido no método for negativo o retorno é “-1”, se for 0 ou 1, o retorno é “1”, e se for um número positivo maior que 1 o retorno é seu fatorial. Neste caso, o fatorial de 5 é 120, então o resultado do teste deve ser positivo, caso não seja, o método possui erros.

O próximo método maiorNumero() foi implementado e numerado:

O grafo referente código exibido anteriormente é:

CC(G) = Ramos – Nós + 2 = 11 – 9 + 2 = 4

CC(G) = Nós predicativos + 1 = 3 + 1 = 4

CC(G) = Regiões = 4

Caminhos Básicos

1. 1, 4, 7, 8, 9 2. 1, 2, 3, 8, 9 3. 1, 4, 5, 6, 8, 9 4. 1, 2, 4, 5, 6, 8, 9

Entradas

1. v1 = 33, v2 = 33, v3 = 99 -> 99 2. v1 = 99, v2 = 33, v3 = 51 -> 99 3. v1 = 33, v2 = 99, v3 = 51-> 99 4. v1 = 51, v2 = 99, v3 = 33 ->99