QA · Leitura de 9 min

Cobertura de linhas, ramos e condições: nem todas valem o mesmo

Cobrir linhas é fácil e enganoso. Cobrir ramos e condições é onde os bugs reais se escondem. A diferença técnica que muda o quanto você confia no seu número.

Não, nem todas valem o mesmo. A cobertura de linhas diz quantas instruções foram executadas; a de ramos, quantas decisões tomaram os dois caminhos; a de condições, quantas subexpressões booleanas foram testadas em verdadeiro e em falso. São três réguas distintas que costumam chegar à mesma porcentagem, mas medem coisas bem diferentes, e confundi las é a razão pela qual um "90 % de cobertura" tranquiliza uma equipe enquanto os bugs continuam passando. Este artigo separa as três, mostra com código por que a mais fácil de subir é a que menos protege, e explica qual observar quando você quer confiar no seu número.

A palavra "cobertura" soa como uma coisa só, e é aí que começa o mal entendido. É uma família de métricas de caixa branca: todas medem que parte da estrutura interna do código as suas provas tocaram, mas cada uma define "tocar" de forma mais exigente que a anterior. O padrão ISO/IEC/IEEE 29119-4 as cataloga como critérios de cobertura estrutural, e a ementa do ISTQB as trata como o termômetro de quão a fundo entrou a sua suíte [1][2]. O problema não é a métrica: é acreditar que um número alto na mais barata equivale a um software bem testado.

01 · a régua fácilCobertura de linhas: conta instruções, não lógica

A cobertura de linhas (ou de instruções) responde a uma pergunta simples: de todas as linhas executáveis do código, quantas rodou ao menos uma prova? Se você tem cem linhas e as suas provas executaram noventa, você tem 90 % de cobertura de linhas. É a métrica que quase todas as ferramentas mostram por padrão, e também a mais fácil de inflar.

O defeito é de fundo, não de calibração. Uma linha "coberta" só significa que o interpretador passou por cima dela, não que se tenha comprovado que ela faz o certo nem que os seus dois desfechos possíveis foram testados. Uma condição sem bloco else pode marcar 100 % de linhas sem nunca ter testado o que ocorre quando essa condição é falsa, porque não há nenhuma linha para executar no caso falso. A linha existiu, foi executada uma vez pelo lado verdadeiro, e a régua ficou satisfeita.

Cobrir uma linha prova que o código passou por ali. Não prova que passou por ali direito, nem que você testou o caminho que ele não tomou.

Figura 1 · una prueba, 100 % de líneas, media rama sin tocar
aplicarDescuento(monto, esVip) precio = monto si esVip: ← decisión (sin bloque "si no") precio = monto * 0.9 devolver precio Prueba única: esVip = verdadero Líneas ejecutadas: 4 de 4 → 100 % de líneas. Rama "esVip = falso": nunca recorrida → 50 % de ramas.
O mesmo caso que satura a cobertura de linhas deixa intacta metade da decisão. Se um cliente não VIP disparar um erro, esta suíte jamais o detecta e o número segue dizendo "100 %".

02 · a régua honestaCobertura de ramos: cada decisão, nas suas duas saídas

A cobertura de ramos (ou de decisões) eleva o nível. Já não conta linhas: conta as saídas de cada ponto de decisão. Um if tem dois ramos, verdadeiro e falso; um laço tem o ramo que entra e o que não entra; um switch tem um por caso. Para chegar a 100 % de ramos, as suas provas precisam ter feito com que cada decisão tomasse os dois caminhos ao menos uma vez.

Essa mudança de foco é exatamente o que faltava à Figura 1. A mesma função com a mesma prova única marca 100 % de linhas e só 50 % de ramos, porque o ramo "não é VIP" nunca foi executado. A cobertura de ramos obriga a acrescentar o segundo caso, e com ele aparece o cenário onde os erros de fato se escondem: o caminho que o programador deu por trivial e não testou. Por isso o ISTQB aponta que a cobertura de decisões é mais forte que a de instruções, e que 100 % da primeira garante 100 % da segunda, mas não o contrário [2].

Uma hierarquia, não uma lista

Esses critérios estão aninhados: cobrir todos os ramos implica cobrir todas as linhas, mas não o contrário. Por isso comparar "90 % de linhas" contra "90 % de ramos" entre dois projetos é enganoso: o segundo 90 % custou mais e protege mais. Quando alguém te dá uma porcentagem de cobertura, a primeira pergunta não é quanto, mas de quê.

Ainda assim, a cobertura de ramos tem um ponto cego próprio, e é sutil. Trata cada decisão como uma caixa fechada: basta que a condição inteira resulte verdadeira uma vez e falsa outra. Não olha o que há dentro dessa condição. E quando a condição combina várias verificações com e / ou, é aí que a régua honesta ainda fica aquém.

03 · a régua finaCobertura de condições: dentro do booleano

Considere uma decisão composta: se (idade >= 18 e temPermissão). A cobertura de ramos se contenta com dois casos que tornem a expressão completa verdadeira e falsa. Você pode conseguir isso testando apenas (20, verdadeiro) e (15, falso). Em ambos os casos a variável temPermissão se moveu junto com a idade: você nunca verificou o que acontece com um maior de idade sem permissão, nem com um menor com permissão. O ramo ficou "coberto" e metade da lógica interna, sem ser tocada.

A cobertura de condições ataca justamente isso: exige que cada subexpressão booleana seja avaliada em verdadeiro e em falso separadamente. A sua variante rigorosa, a MC/DC (Modified Condition/Decision Coverage), vai além: pede demonstrar que cada condição, por si só, pode mudar o resultado da decisão completa. Não é um capricho acadêmico. A aviônica crítica o exige por norma: o padrão DO-178C obriga a MC/DC para o software de nível A, aquele cuja falha pode custar vidas [3]. Quando o bug não se paga com uma nova tentativa e sim com um acidente, a régua fina deixa de ser opcional.

Figura 2 · la misma decisión, tres exigencias distintas
Decisión: edad >= 18 Y tienePermiso LÍNEAS RAMAS CONDICIONES basta 1 paso V y F del total cada parte, V y F (20, sí) → V (20, sí) → V (15, no) → F (20, sí) → V (20, no) → F (15, sí) → F (15, no) → F no ve el "Y" no aísla partes aísla cada una 1 caso 2 casos hasta 4 casos
A mesma linha de código exige um esforço bem diferente conforme a régua. Com dois casos ("ramos") você jamais separa o efeito da idade do da permissão; só ao isolar cada condição você descobre se um maior de idade sem permissão quebra a lógica.

04 · o número que realmente serveO que observar e o que não perseguir

Daqui sai uma conclusão incômoda para quem coleciona porcentagens: a cobertura alta é necessária mas não suficiente. 100 % de linhas convive com lógica sem testar; 100 % de ramos é muito mais difícil de fingir; a MC/DC é quase impossível sem ter pensado cada decisão. Mas nenhuma verifica se a saída é correta: medem que código foi executado, não se o resultado foi o esperado. Uma suíte pode percorrer 100 % dos ramos com asserts vazios e não pegar um único defeito.

Por isso perseguir "os 100 %" como meta costuma piorar o software: escrevem se provas de enchimento que tocam linhas sem verificar nada, só para mexer no número. A cobertura funciona ao contrário, como detector de lacunas: você a lê para achar que partes ninguém testou ainda, e decide se essa lacuna importa. Um caminho de tratamento de erro sem cobrir é um alarme; um ramo de logging sem cobrir, quase nunca. O que cobrir a fundo é o risco que define, não a vaidade da porcentagem.

A cobertura não diz se o seu software está bem testado. Diz onde com certeza não está. Esse é o seu verdadeiro poder.

Então, da próxima vez que alguém comemorar um número de cobertura, faça as duas perguntas que o desmontam: cobertura de quê, linhas ou ramos? E as lacunas que restam são de código que não importa, ou justamente do que importa? A resposta separa uma equipe que entende a sua métrica de uma que só a vê subir. Na Qirava tratamos a cobertura pelo que ela é: um mapa do que falta, não um troféu do que sobra.

Fontes

  1. ISO/IEC/IEEE 29119-4:2021. Software and systems engineering. Software testing. Part 4: Test techniques. International Organization for Standardization. (Define os critérios de cobertura estrutural: instrução, decisão/ramo e condição.)
  2. ISTQB (2018). Certified Tester Foundation Level Syllabus, v3.1. International Software Testing Qualifications Board. Seção sobre técnicas de caixa branca e cobertura de instruções e decisões.
  3. RTCA DO-178C / EUROCAE ED-12C (2011). Software Considerations in Airborne Systems and Equipment Certification. RTCA Inc. (Exige Modified Condition/Decision Coverage, MC/DC, para software de nível de garantia A.)
  4. Myers, G. J., Sandler, C. & Badgett, T. (2011). The Art of Software Testing, 3ª ed. John Wiley & Sons. Capítulo sobre provas de caixa branca e cobertura lógica.

Aprenda mais sobre IA

Ver tudo Aprenda IA