Testes pairwise

Como os testes pairwise reduzem combinações de parâmetros e onde economizam esforço mantendo uma cobertura útil.

Atualizado:

Sumário

Muitos parâmetros e valores tornam caros os testes exaustivos de combinações. Os testes pairwise reduzem a quantidade de testes e cobrem cada par de valores de parâmetros. Frequentemente equilibram o custo dos testes com a probabilidade de encontrar defeitos.

Por que os testes pairwise ajudam

Muitos defeitos surgem de interações entre dois fatores, e não de combinações raras de cinco ou seis. Cobrir cada par pode, portanto, encontrar uma parcela substancial de problemas com muito menos testes.

Onde aplicar

  • →Formulários com vários campos e valores independentes.
  • →Combinações de dispositivos, navegadores, funções, planos, países e idiomas.
  • →APIs com muitos parâmetros e modos de invocação.
  • →Matrizes de compatibilidade onde testes exaustivos são muito caros.

O que lembrar

  • →Pairwise não substitui testes de riscos críticos de negócio ou combinações perigosas conhecidas.
  • →Os parâmetros dependentes não devem ser misturados cegamente como independentes.
  • →Exclua antecipadamente combinações logicamente impossíveis.
  • →Acrescente cenários críticos ao conjunto pairwise gerado.

Orientação prática

Use pairwise para otimizar a cobertura, em vez de justificar a menor suíte possível. Identifique manualmente os casos de alto risco, acrescente pairwise para ampliar a cobertura e reforce-a com cenários negativos e de limite.

🧩

Pairwise ajuda quando as combinações de parâmetros são o problema real. Não é uma solução universal para sequências, estados ou cálculos complexos.

Exemplo resolvido: quatro testes cobrindo todos os doze pares

Este modelo fictício tem três fatores: navegador (Chrome ou Firefox), localidade da interface (ru ou en) e papel da conta (viewer ou editor). Todas as oito combinações são permitidas. Versões dos navegadores, sistema operacional, massa de dados e feature flags permanecem fixos durante o exercício; registre os valores exatos ao executar um teste real no navegador. Este é um modelo de seleção de entradas, não uma aplicação web executável.

A cobertura completa das combinações precisa de 2 × 2 × 2 = 8 linhas. Pairwise exige cada par de valores de dois fatores diferentes: quatro pares navegador–localidade, quatro navegador–papel e quatro localidade–papel. As quatro linhas a seguir cobrem esses doze pares.

plain text
ID	Navegador	Localidade	Papel
PW1	Chrome	ru	viewer
PW2	Chrome	en	editor
PW3	Firefox	ru	editor
PW4	Firefox	en	viewer

Audite a cobertura em vez de confiar na contagem de linhas

plain text
Fator A	Fator B	Coberto por
Navegador=Chrome	Localidade=ru	PW1
Navegador=Chrome	Localidade=en	PW2
Navegador=Firefox	Localidade=ru	PW3
Navegador=Firefox	Localidade=en	PW4
Navegador=Chrome	Papel=viewer	PW1
Navegador=Chrome	Papel=editor	PW2
Navegador=Firefox	Papel=viewer	PW4
Navegador=Firefox	Papel=editor	PW3
Localidade=ru	Papel=viewer	PW1
Localidade=ru	Papel=editor	PW3
Localidade=en	Papel=viewer	PW4
Localidade=en	Papel=editor	PW2

Cada linha da tabela nomeia um par obrigatório e o teste que o contém. A tabela cobre cada par uma vez. Quatro testes são mínimos para este modelo binário irrestrito: apenas os quatro pares navegador-localidade requerem pelo menos quatro linhas. Essa conclusão aplica-se apenas a este modelo específico, não a conjuntos arbitrários de pares.

Verifique a matriz com Python 3

Copie este código para pairwise_coverage.py e execute python3 pairwise_coverage.py. Ele usa apenas a biblioteca padrão e não faz requisições de rede. Saída esperada: Pairs: 12/12; triples: 4/8.

plain text
from itertools import product, combinations
levels = [("Chrome", "Firefox"), ("ru", "en"), ("viewer", "editor")]
rows = [
    ("Chrome", "ru", "viewer"),
    ("Chrome", "en", "editor"),
    ("Firefox", "ru", "editor"),
    ("Firefox", "en", "viewer"),
]
required = {(i, a, j, b) for i, j in combinations(range(3), 2)
            for a, b in product(levels[i], levels[j])}
covered = {(i, row[i], j, row[j]) for row in rows
           for i, j in combinations(range(3), 2)}
assert all(row in set(product(*levels)) for row in rows)
assert covered == required
assert ("Chrome", "en", "viewer") not in rows
print(f"Pairs: {len(covered)}/{len(required)}; triples: {len(set(rows))}/8")

Dê a cada configuração um oráculo comportamental

Para uma funcionalidade fictícia de documentos, defina a regra antes da execução: viewer pode ler, mas uma tentativa de edição mantém o conteúdo armazenado inalterado; editor pode salvar uma edição válida exatamente uma vez. Em cada linha da matriz, verifique a localidade escolhida, o resultado específico do papel e os dados salvos. A cobertura de pares sozinha não comprova esses resultados; uma configuração aprovada não é evidência sem asserções.

Um defeito desencadeado apenas por Chrome + en + viewer é ignorado por esta matriz: esse triplo está ausente mesmo que todos os seus pares ocorram em outro lugar. Adicione essa combinação quando o risco ou um defeito anterior justificar. As verificações de sequência, limite, permissão e desempenho ainda precisam de um design separado. Nenhuma porcentagem de defeitos encontrados segue dos “pares 12/12”.

Se uma restrição do produto torna uma combinação impossível, gere primeiro as combinações completas permitidas, derive os pares alcançáveis nelas e depois regenere e verifique a suíte reduzida. Simplesmente excluir uma linha inválida pode remover outros pares válidos. Exercício: remova PW4; os pares não cobertos passam a ser Firefox–en, Firefox–viewer e en–viewer. Restaure uma linha válida que cubra esses pares, em vez de reduzir silenciosamente o denominador.

Continuar aprendendo

Escolha casos adicionais por risco

Planeje verificações entre navegadores

NIST: testes combinatórios e cobertura de interação