Verificação, validação e testes
Evidência estática e dinâmica, revisões, níveis de teste, casos, fronteiras, cobertura e defeitos.
A aplicação confirma reservas conforme a especificação, mas Ana engana-se no horário e descobre que não pode cancelar. Passar os cenários escritos não resolve uma necessidade que ficou fora do documento.
Verificação e validação
Verificação avalia a conformidade de um artefacto com a sua especificação. Validação avalia se o sistema responde ao uso e às necessidades pretendidas.
Podemos verificar código, modelos e requisitos. Também podemos validar requisitos ou um protótipo com utilizadores antes de existir o produto final. A distinção está no objetivo da avaliação, não numa divisão rígida entre “revisão” e “teste”.
Outra distinção diz respeito à execução:
- As técnicas estáticas analisam representações sem executar o sistema: revisões, inspeções, análise estática e verificação formal.
- As técnicas dinâmicas executam o sistema ou um modelo: testes e simulações.
As duas complementam-se. Uma revisão pode encontrar uma regra contraditória; um teste pode mostrar como a implementação reage a um caso concreto.
Revisões e inspeções
Uma revisão analisa um artefacto para descobrir problemas e avaliar qualidade. Uma inspeção é uma revisão mais estruturada, com preparação, papéis, critérios e registo de defeitos. Um walkthrough percorre o artefacto ou cenário com outras pessoas.
Para rever um caso de uso de reservas, podemos perguntar:
- Estão definidos ator, pré-condições e resultado?
- O sistema trata sala ocupada, intervalo inválido e indisponibilidade?
- A regra contradiz outro requisito?
- Conseguimos derivar exemplos de aceitação?
A checklist deve nascer de problemas relevantes e do histórico da equipa. Não substitui o raciocínio. Preparar a revisão e permitir leitura individual pode encontrar defeitos que uma apresentação rápida não revela.
Ferramentas de análise estática detetam certas classes de problemas, como código inatingível ou usos suspeitos de APIs. Podem ter falsos positivos e não conhecem automaticamente todas as regras do domínio. Compilar e passar o linter não valida o produto.
Caso de teste e oráculo
Um caso de teste define entradas, condições de execução e resultados esperados para um objetivo. O oráculo permite decidir se o comportamento observado é aceitável: pode ser uma regra, um resultado calculado independentemente ou uma expectativa acordada.
O resultado esperado precisa de uma justificação independente do código sob teste. Copiar a resposta da implementação para o teste pode conservar o mesmo defeito nos dois.
No caso de sobreposição, começamos com uma sala reservada das 14h às 15h. Pedimos das 14h30 às 15h30. Esperamos uma recusa e nenhuma nova reserva. Ver só uma mensagem de erro não chega se o sistema tiver criado a reserva na mesma.
Um script é a concretização dos passos, manual ou automatizada. O caso explica o que verificar; o script diz como fazê-lo no ambiente.
Níveis e objetivos
| Nível | O que avaliamos | Exemplo |
|---|---|---|
| Unidade ou componente | Uma unidade isolada ou pequeno grupo relacionado | Regra de duração da reserva |
| Integração | Interações entre componentes ou sistemas | Serviço de reservas com armazenamento real |
| Sistema | Sistema completo contra requisitos | Fluxo móvel e servidor com falha de rede |
| Aceitação | Critérios que permitem ao cliente aceitar o resultado | Estudante reserva uma sala segundo o cenário acordado |
O nível não determina a característica de qualidade. Podemos testar desempenho ou segurança em vários níveis. Também não determina uma pessoa obrigatória em todas as equipas; a independência e as responsabilidades dependem do contexto.
Em Flutter, um unit test avalia lógica; um widget test avalia um widget e a sua interação num ambiente de teste; um integration test percorre a aplicação completa ou uma parte ampla. Estes nomes de ferramentas não substituem o objetivo de aceitação: um cenário do cliente pode ser parcialmente exercitado num widget test, mas serviços simulados não provam a integração real.
Dependências reais e simuladas
Um test double substitui uma dependência durante o teste. Por exemplo, um serviço simulado devolve sempre «reserva confirmada» ao ecrã. Isso permite observar se o ecrã apresenta a confirmação e termina o estado de espera, sem depender de rede ou dados. Não demonstra que o servidor verifica disponibilidade nem que os dois lados concordam no formato das mensagens.
Se o servidor passa a devolver conflito onde o ecrã espera ocupada, ambos podem passar os testes isolados com os seus próprios substitutos e falhar quando são ligados. Um teste de integração tem de exercitar essa fronteira com os componentes relevantes reais ou verificar explicitamente o contrato partilhado. Escolhe a substituição pela dúvida que queres isolar e regista a parte que ficou por verificar. Os participantes e as mensagens desse cenário seguem um diagrama de sequência.
Uma experiência com utilizadores pergunta se a pessoa compreende «pedido enviado» e «reserva confirmada». A integração pode estar correta e a comunicação continuar inadequada. Aumentar a quantidade de testes isolados não responde automaticamente a essa pergunta de validação.
Caixa preta e caixa branca
No teste de caixa preta, derivamos casos da especificação externa; no teste de caixa branca, usamos a estrutura interna, como ramos e caminhos, para escolher casos. Não é a mesma distinção que manual e automático: um teste automatizado de uma função pode ser de caixa preta se as entradas vierem da regra, sem olhar para o código.
Uma sequência prática é começar pelos casos derivados da especificação e acrescentar depois casos a partir da estrutura do código. Os primeiros verificam exemplos do comportamento esperado. A cobertura ajuda a identificar instruções ou ramos que esses exemplos ainda não exercitaram.
As partições de equivalência agrupam entradas que esperamos tratar de modo semelhante. Para duração inteira em minutos, válida entre 30 e 120 inclusive, temos menos de 30, de 30 a 120 e mais de 120.
Os valores de fronteira procuram diferenças junto dos limites. Testamos 29, 30, 31, 119, 120 e 121. Se a entrada puder ser decimal, precisamos de adaptar os valores à precisão permitida; não podemos assumir que um minuto é sempre o menor passo.
Um exemplo com intervalos
Adotamos intervalos semiabertos: a reserva inclui o início e exclui o fim. Assim, 14h às 15h e 15h às 16h são adjacentes e não se sobrepõem.
Nesta comparação avaliamos apenas a sobreposição entre intervalos com duração positiva; a regra dos 30 a 120 minutos é testada separadamente, e o intervalo contido de 15 minutos serve aqui para isolar a relação temporal. Dois intervalos válidos, com inícios e fins , sobrepõem-se quando
Testamos reserva anterior, seguinte, parcialmente sobreposta, totalmente contida e igual. Uma reserva 14h30 às 14h45 está contida e deve ser recusada. Uma reserva 15h às 16h não satisfaz a segunda desigualdade relativamente a 14h às 15h, porque é falso.
Na figura, o círculo aberto exclui o fim e o círculo cheio inclui o início. As reservas adjacentes não partilham nenhum instante; a reserva contida partilha tempo mesmo sem atravessar as pontas da primeira.
Também testamos duas criações concorrentes. Dois testes sequenciais não demonstram que a operação atómica impede uma corrida.
Cobertura calculada num exemplo
function aceitarDuracao(minutos: number): boolean {
if (minutos < 30) return false;
if (minutos > 120) return false;
return true;
}
Cobertura de instruções conta que instruções foram executadas. Cobertura de ramos conta as saídas verdadeiro e falso de cada decisão. A função tem duas decisões, por isso quatro ramos: verdadeiro e falso do primeiro if, verdadeiro e falso do segundo if.
Com os testes 29, 60 e 121, cobrimos os quatro ramos:
- O teste 29 segue o ramo verdadeiro do primeiro
ife regressa sem chegar ao segundo. - O teste 60 segue o ramo falso do primeiro e o ramo falso do segundo, até ao retorno final.
- O teste 121 segue o ramo falso do primeiro e o ramo verdadeiro do segundo.
A cobertura de instruções é total e a cobertura de ramos é 4/4.
Com apenas o teste 60, só vemos os dois ramos falsos, por isso a cobertura de ramos é 2/4. Ficam por executar os dois retornos de recusa. Mesmo com 4/4, um oráculo copiado do código não deteta nada. O resultado esperado vem da regra: 29 recusa, 30 aceita, 31 aceita, 119 aceita, 120 aceita, 121 recusa. Cobertura mede execução, não correção do oráculo.
Cobertura e limites
Mesmo os testes 29, 60 e 121, que percorrem todos os ramos, não distinguem o limite correto minutos > 120 do defeito minutos >= 120. Nenhum deles testa 120. Acrescentar esse caso, com aceitação esperada, deteta a diferença. Cobertura mede execução; as fronteiras e os oráculos continuam a vir do contrato.
Testes mostram falhas em situações exercitadas e aumentam a confiança. Em geral, não provam a ausência de defeitos. A automação é útil para repetir verificações estáveis; testes instáveis precisam de diagnóstico, porque um sinal que muda sem alteração do produto deixa de orientar decisões.
Defeitos e regressão
Um defeito é um problema num artefacto. Uma falha é um comportamento observado que viola o esperado. Um defeito pode existir sem se manifestar em todas as execuções.
Um registo de defeito deve permitir reproduzir.
| Campo | Exemplo |
|---|---|
| Versão e ambiente | build 1.4.2, Android 14, dados de teste salas-2026 |
| Estado inicial | sala A livre 14h30-15h30 |
| Passos | dois pedidos 14h30-15h30 em simultâneo |
| Esperado | uma confirmação e uma recusa, uma reserva nos dados |
| Observado | duas confirmações, duas reservas sobrepostas |
Distingue severidade, impacto da falha, de prioridade, urgência de resolução. Depois da correção, executamos o caso que demonstrava a falha e os testes relevantes para efeitos colaterais; os testes de regressão procuram comportamentos que antes funcionavam e deixaram de funcionar. O processo de teste inclui planear, analisar condições, desenhar casos, preparar execução, correr, acompanhar resultados e fechar com evidência.
Exercícios
Casos junto dos limites
Adota a convenção de três pontos por fronteira inteira: o limite e os inteiros imediatamente ao lado. A duração é um inteiro em minutos entre 30 e 120 inclusive. Propõe valores de fronteira e resultados esperados.
Pista
Olha para cada limite e para os valores inteiros imediatamente ao lado.
Solução
29 é recusado; 30 e 31 são aceites. 119 e 120 são aceites; 121 é recusado. A checklist pede estes seis valores porque segue a convenção de três pontos por fronteira. Também podemos testar um valor interior e entradas de outro tipo conforme o contrato.
Confere a tua resposta:
- Incluí 29, 30 e 31.
- Incluí 119, 120 e 121.
- Recusei 29 e 121, aceitando os restantes.
Erros frequentes
Não recuses 30 ou 120. Não uses a mesma distância de fronteira se a entrada admitir outra precisão.
Adjacência, contenção e intervalo inválido
A sala tem uma reserva das 14h às 15h. Os intervalos são semiabertos e uma reserva válida exige início anterior ao fim. Avalia os pedidos 15h–16h, 14h30–15h30, 14h30–14h45 e 15h–15h. Para cada um, justifica aceitação ou recusa pela validade e pela sobreposição. Ignora outras restrições de duração.
Pista
Aplica as duas desigualdades ao mesmo par de intervalos.
Solução
Para 15h–16h, 14 < 16 é verdadeiro mas 15 < 15 é falso: aceita-se. Para 14h30–15h30, ambas as desigualdades são verdadeiras: recusa-se. Para 14h30–14h45 também são verdadeiras, pois 14 < 14,75 e 14,5 < 15: estar contido é uma forma de sobreposição. Para 15h–15h, a duração é zero, logo o intervalo é inválido antes de testar conflitos. A condição de sobreposição pressupõe intervalos válidos.
Confere a tua resposta:
- Aceitei 15h–16h por adjacência.
- Recusei 14h30–15h30 e 14h30–14h45 por sobreposição.
- Recusei 15h–15h por não ter início anterior ao fim.
- Apliquei as duas desigualdades apenas a intervalos válidos.
Erros frequentes
Não uses menor ou igual para este contrato. Essa alteração faria recusar intervalos adjacentes.
Cobertura total e um limite errado
A regra aceita minutos inteiros entre 30 e 120 inclusive. A função recusa primeiro valores menores que 30, depois valores maiores que 120, e aceita os restantes. Os testes 29, 60 e 121 verificam, respetivamente, recusa, aceitação e recusa. Que ramos percorrem? Detetam trocar a segunda condição por minutos maiores ou iguais a 120? Propõe um caso que detete esse defeito.
Pista
Compara os resultados nos limites, além dos ramos percorridos.
Solução
29 percorre o primeiro ramo verdadeiro e termina. 60 percorre os dois ramos falsos. 121 percorre o primeiro falso e o segundo verdadeiro. A união cobre os quatro ramos, 4/4. A condição alterada devolve os mesmos resultados nestas três entradas, por isso o defeito passa. O teste 120 deve esperar aceitação, derivada do limite inclusivo, e falha na versão com maior ou igual. Cobertura total não substitui casos derivados da especificação.
Confere a tua resposta:
- Segui os ramos dos testes 29, 60 e 121 e obtive 4/4.
- Expliquei por que trocar > 120 por >= 120 não é detetado por esses testes.
- Acrescentei o caso 120 com aceitação esperada pela especificação.
Erros frequentes
Não apresentes 100% de cobertura como prova de correção. Não derives a expectativa copiando o resultado do código atual.
Conforme, mas inadequado
O sistema passa todos os cenários de uma especificação que não inclui cancelamento. Numa revisão desse documento com estudantes, descobre-se que precisam de corrigir reservas feitas por engano. Que parte é verificação e que parte é validação? Esta revisão deixa de validar por não executar código?
Pista
Classifica pelo objetivo da avaliação, não pela ferramenta.
Mais uma pista
Um documento pode ser validado contra necessidades antes de haver implementação.
Solução
Comparar os resultados com a especificação dá evidência de verificação nos cenários executados. Descobrir com estudantes que falta cancelamento é validação dos requisitos contra as necessidades. A revisão é uma técnica estática e pode validar; não precisa de executar código. Passar os cenários escritos não demonstra que o produto resolve necessidades omitidas.
Confere a tua resposta:
- Usei a comparação entre implementação e especificação como verificação.
- Usei a necessidade de cancelamento como questão de validação.
- Reconheci validação numa revisão de requisitos sem execução.
Erros frequentes
Não reduzas verificação a revisão e validação a execução. Não concluas que todas as necessidades estão satisfeitas porque todos os testes existentes passaram.
Quatro experiências, quatro perguntas
Numa aplicação de bilhetes, A testa apenas a função que calcula o preço. B liga o componente de vendas ao serviço de pagamentos real num ambiente de teste. C mede o tempo de resposta da aplicação completa com 200 clientes. D percorre, com o cliente, os cenários acordados para decidir se aceita a entrega. Classifica o nível de cada experiência. Se B for substituída por um teste do ecrã com um serviço que devolve sempre sucesso, que risco deixa de ser observado? C torna-se teste de unidade por medir desempenho?
Solução
A é unidade: isola a regra de preço. B é integração: avalia a fronteira entre componentes reais. C é sistema: o objeto é a aplicação completa, embora a característica avaliada seja desempenho. D é aceitação: o objetivo é apoiar a decisão acordada de aceitar a entrega.
O substituto permite avaliar a apresentação do sucesso, mas pode esconder incompatibilidades de mensagens, autenticação e respostas de falha do serviço real. A medição de desempenho não fixa o nível de teste: podemos medir uma função isolada ou o sistema inteiro. O nível depende do objeto; a finalidade e a característica são outras dimensões.
Confere a tua resposta:
- Classifiquei a regra isolada como unidade e a fronteira real como integração.
- Classifiquei a medição do sistema completo como sistema.
- Liguei o ensaio acordado com o cliente à aceitação.
- Expliquei por que o teste do ecrã com serviço simulado não prova a fronteira real.