Teste de Mutação C++: como tornar o código inquebrável

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Teste de Mutação em C++: quando 100% de cobertura de código é uma mentira

\n\n

Você se orgulha dos seus 95% de code coverage? Talvez esteja enganado. Cobertura de código é como uma fechadura que verificam apenas puxando a maçaneta. Já o teste de mutação é um arrombador que realmente tenta abrir o cofre. Neste artigo, vamos explorar como o teste de mutação C++ transforma seus testes de uma formalidade em uma verdadeira arma. E sim, não vamos copiar e colar definições chatas da wikipedia.

\n\n

Imagine: você escreveu uma função, cobriu-a com testes, o CI está verde. E então um bug vai para produção. Dor familiar? Na maioria das vezes, o problema não está no código, mas nos testes que não verificam o que deveriam. Mutation testing para C++ resolve exatamente esse problema — ele mostra o quão perigosos seus testes realmente são para os bugs.

\n\n

O que é teste de mutação e por que ele é importante para o desenvolvedor C++?

\n\n

Teste de mutação (ou mutation testing) é uma metodologia para avaliar a qualidade dos testes através da introdução de pequenas alterações (mutações) no código fonte. Se após a mutação os testes ainda passam — significa que eles são fracos. O mutante sobreviveu. Se os testes falham — o mutante foi morto, o teste funciona.

\n\n

Para C++, isso é especialmente relevante porque:

\n
    \n
  • O código C++ frequentemente contém lógica complexa com ponteiros, templates e RAII.
  • \n
  • Métricas padrão de cobertura (line coverage, branch coverage) são fáceis de enganar.
  • \n
  • O custo de um bug em C++ (especialmente em embedded, finance, game engines) pode ser catastrófico.
  • \n
\n\n

Um exemplo simples: você tem uma função de verificação de idade:

\n\n
bool is_adult(int age) {\n    return age >= 18;\n}
\n\n

Teste:

\n\n
TEST(AdultTest, Positive) {\n    EXPECT_TRUE(is_adult(20));\n}
\n\n

Cobertura: 100% das linhas. Mas a mutação age >= 18 → age > 18 não será detectada, porque 20 ainda passa. O mutante sobreviveu. E se você tivesse um teste para is_adult(18) e is_adult(17) — você teria pego o bug. Teste de mutação C++ força você a escrever esses testes de limite.

\n\n

Principais operadores de mutação em C++

\n\n

As ferramentas de teste de mutação aplicam um conjunto de operadores (mutators). Aqui estão os mais comuns para C++:

\n\n
    \n
  • Substituição de operadores aritméticos: + → -, * → /
  • \n
  • Substituição de operadores lógicos: && → ||, == → !=
  • \n
  • Alteração de condições de limite: >= → >, < → <=
  • \n
  • Remoção de expressões: chamada de função substituída por uma constante
  • \n
  • Alteração do valor de retorno: return true → return false
  • \n
  • Mutação de loops: alteração da condição de saída ou do passo
  • \n
\n\n

Exemplo com código real:

\n\n
int factorial(int n) {\n    if (n <= 1) return 1;\n    return n * factorial(n - 1);\n}
\n\n

Mutação #1: n <= 1 → n < 1. Se o teste chama factorial(1) e espera 1, mas a mutação remove o caso base — o teste falhará apenas se você verificar factorial(0) ou factorial(1) separadamente.

\n\n

Mutação #2: return n * factorial(n - 1) → return n + factorial(n - 1). Se os testes são apenas para números positivos, eles podem não perceber a substituição da multiplicação pela adição.

\n\n

São exatamente esses casos que o mutation testing em C++ revela.

\n\n

Ferramentas para teste de mutação C++

\n\n

Nem todas as ferramentas são igualmente úteis. Aqui estão três principais players no mercado C++:

\n\n

1. Mull

\n

Projeto moderno e ativo. Funciona com base em LLVM pass. Suporta C++17/20, integra-se com Google Test, Catch2, doctest

Blogs

Book Recommendations