0Pricing
PHP Academy · Aula

Testes de mutação com Infection

Avalie o quanto seus testes são realmente bons.

Testes de mutação com Infection é uma aula grátis de PHP Academy no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de PHP Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de PHP Academy inclui 4 aulas no total.

A cobertura engana

A cobertura de 100% das linhas parece reconfortante, mas apenas comprova que seus testes executaram o código — não que eles detectariam um erro nele. Um teste pode executar uma linha sem verificar nada relevante. Os testes de mutação medem o que realmente importa: seus testes falhariam se o código tivesse um pequeno defeito? O Infection é a ferramenta padrão do PHP para isso.

composer require --dev infection/infection

A ideia central: mutantes

O Infection pega o código coberto e introduz pequenas falhas — mutantes. Ele troca > por >=, + por -, && por ||, remove um return e assim por diante. Em seguida, executa novamente seus testes contra cada mutante:

  • Se um teste falhar → o mutante será eliminado (ótimo — seus testes detectaram a falha).
  • Se todos os testes passarem → o mutante sobreviveu (ruim — um erro real nesse ponto passaria despercebido).

Um sobrevivente em ação

Considere esta função e um teste fraco. O Infection transformaria >= em >. Se nenhum teste verificar o limite exato (quando o valor é igual ao limite), esse mutante sobreviverá — revelando um caso extremo não testado.

<?php
function qualifiesForFreeShipping(float $total): bool
{
    return $total >= 50.0;   // Infection mutates >= to >
}

// Weak test only checks 100 and 10 -> never tests exactly 50.0
var_dump(qualifiesForFreeShipping(100.0)); // true
var_dump(qualifiesForFreeShipping(10.0));  // false
var_dump(qualifiesForFreeShipping(50.0));  // true  <-- the boundary the mutant exposes

Eliminando o mutante

Adicione a verificação do limite e o mutante de >= para > morrerá: no código mutado, 50.0 > 50.0 resulta em false, portanto o teste falha — exatamente o que queremos. Os testes de mutação informam literalmente quais verificações estão faltando.

<?php
use PHPUnit\Framework\TestCase;

final class ShippingTest extends TestCase
{
    public function test_threshold_is_inclusive(): void
    {
        // Kills the >= -> > mutant
        self::assertTrue(qualifiesForFreeShipping(50.0));
    }
}

Configuração: infection.json

O Infection é controlado por infection.json5. Você declara quais diretórios devem ser mutados, onde os registros serão armazenados e os limiares mínimos de pontuação para a integração contínua ser aprovada. Aponte source.directories apenas para o seu código de produção — nunca para os seus testes.

{
  "source": {
    "directories": ["src"]
  },
  "logs": {
    "text": "build/infection.log",
    "html": "build/infection.html"
  },
  "mutators": {
    "@default": true
  },
  "minMsi": 80,
  "minCoveredMsi": 90
}

As métricas de MSI

O Infection informa o Indicador de pontuação de mutação:

  • MSI = eliminados / total de mutantes. É penalizado pelo código não coberto (esses mutantes não podem ser eliminados).
  • MSI da cobertura = eliminados / mutantes em linhas cobertas. Mede a qualidade das suas asserções nas partes que você testa.
  • Cobertura de código por mutação = quanto código o Infection conseguiu mutar.

Uma cobertura de linhas alta, mas um MSI da cobertura baixo, é o sinal clássico de testes com poucas asserções.

Executando o Infection com eficiência

Os testes de mutação são custosos — a suíte é executada novamente uma vez para cada mutante. Duas grandes otimizações de velocidade são: executar os testes em paralelo com --threads e mutar apenas o código alterado pelo ramo atual usando a filtragem das diferenças do Git, o que é ideal para a integração contínua em solicitações de mesclagem.

vendor/bin/infection --threads=max --git-diff-lines --git-diff-base=origin/main

Lendo os sobreviventes

O valor está nas diferenças que o Infection exibe para cada mutante sobrevivente. Elas mostram a linha exata e a alteração que seus testes não conseguiram detectar. Trate os sobreviventes como uma lista de tarefas: adicione a verificação que falta ou reconheça que o mutante é inofensivo (um mutante equivalente).

- return $total >= 50.0;
+ return $total > 50.0;

# Mutant survived: no test asserts the inclusive boundary (total === 50.0)

Mutantes equivalentes e como ignorá-los

Alguns mutantes são equivalentes — alteram o código, mas não o seu comportamento observável, portanto nenhum teste poderia eliminá-los. Eles não podem ser eliminados e reduzem o MSI injustamente. Suprima mutadores conhecidos por gerar falsos positivos em trechos específicos do código, em vez de manipular os testes para persegui-los.

{
  "mutators": {
    "@default": true,
    "Plus": {
      "ignore": ["App\\Math\\Statistics::variance"]
    }
  }
}

Onde os testes de mutação compensam

Como são lentos, escolha bem onde aplicá-los:

  • Aplique-os à lógica central do domínio — definição de preços, permissões e cálculos — onde erros silenciosos são dispendiosos.
  • Condicione as solicitações de mesclagem ao MSI da cobertura das linhas alteradas, não ao repositório inteiro.
  • Não busque 100% globalmente; os ganhos decrescentes e os mutantes equivalentes tornam isso um desperdício.
  • Use-os para encontrar asserções fracas e então corrija os testes — a pontuação é um meio, não o objetivo.

É preciso ter dados de cobertura para ganhar velocidade

O Infection só muta as linhas que seus testes realmente cobrem, portanto reutiliza os dados de cobertura do executor de testes. Com o Xdebug, isso é lento; o pcov é muito mais rápido para a cobertura de linhas e é o mecanismo recomendado para executar testes de mutação. O Infection também pode gerar a cobertura por conta própria ou usar um relatório de cobertura que você já tenha produzido na integração contínua.

# Faster mutation runs: use pcov instead of Xdebug for coverage
php -d pcov.enabled=1 vendor/bin/infection --threads=max

# Or reuse coverage already generated by your PHPUnit step:
vendor/bin/infection --coverage=build/coverage --skip-initial-tests

Verificação rápida

O que um mutante sobrevivente informa?

Recapitulação

Você aprendeu a medir a qualidade dos testes, não apenas a quantidade:

  • Os testes de mutação injetam pequenas falhas (mutantes); eliminado = detectado, sobrevivente = uma lacuna.
  • A cobertura mostra a execução; o MSI da cobertura mostra a força das asserções.
  • Configure por meio de infection.json5 com limites de MSI; execute com --threads e filtragem pelas diferenças do Git para ganhar velocidade.
  • Os sobreviventes são uma lista de tarefas; fique atento aos mutantes equivalentes e ignore-os deliberadamente.
  • Priorize a lógica central e condicione as solicitações de mesclagem ao MSI das linhas alteradas, em vez de buscar 100% globalmente.

Perguntas Frequentes

A aula “Testes de mutação com Infection” é grátis?

Sim — o texto completo de “Testes de mutação com Infection” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de PHP Academy, atualize para CoddyKit PRO. O curso de PHP Academy inclui 4 aulas no total.

O que vou aprender em “Testes de mutação com Infection”?

Avalie o quanto seus testes são realmente bons. Você pratica PHP Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar PHP Academy?

Nenhuma experiência prévia é necessária. PHP Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.

Quanto tempo leva a aula “Testes de mutação com Infection”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de PHP Academy?

Sim. Cada aula de PHP Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. O fluxo de trabalho do desenvolvimento orientado por testes
  2. Simulação e criação de dublês com Mockery
  3. Testes de integração e funcionais
  4. Testes de mutação com Infection
← Voltar para PHP Academy