<p><strong>Meta Description:</strong> Aprenda mutation testing: técnica avançada para avaliar e melhorar a qualidade dos testes unitários. Ferramentas e implementação prática.</p>

<hr>
<h2>O Que é Mutation Testing?</h2>

<p>Mutation testing é uma técnica que avalia a qualidade dos testes unitários introduzindo pequenas mudanças (mutações) no código-fonte e verificando se os testes detectam essas mudanças.</p>

<h3>Analogia</h3>

<pre><code>Código Original: if (age &gt;= 18) → permitido
Mutação 1: if (age &gt; 18) → ainda passa? Bug!
Mutação 2: if (age &gt;= 0) → ainda passa? Bug!
</code></pre>

<p>Se seus testes passam mesmo com mutações, eles não estão realmente testando o código.</p>

<hr>
<h2>Por Que Mutation Testing?</h2>

<figure class="wp-block-table"><table>
<tr><th>Métrica</th><th>Com Coverage Tradicional</th><th>Com Mutation Testing</th></tr>
<tr><td><strong>O que mede</strong></td><td>Linhas executadas</td><td>Testes que detectam bugs</td></tr>
<tr><td><strong>Confiança</strong></td><td>Baixa</td><td>Alta</td></tr>
<tr><td><strong>Bug detection</strong></td><td>Não verifica</td><td>Verifica</td></tr>
</table></figure>

<h3>Como Funciona</h3>
<ol><li><strong>Generate Mutations</strong>: Criar variantes do código</li>
<li><strong>Run Tests</strong>: Executar suite contra cada mutante</li>
<li><strong>Classify Results</strong>: Identificar se mutante foi "matado"</li>
<li><strong>Calculate Score</strong>: {6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} de mutantes mortos</li>
</ol>
<hr>
<h2>Tipos de Mutações</h2>

<h3>Arithmetic Mutations</h3>

<pre><code># Original
result = a + b

<p># Mutations<br>result = a - b    # +<br>result = a * b    # +<br>result = a / b    # +<br>result = a ** b   # +<br>result = a {6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} b    # +<br></code></pre></p>

<h3>Relational Mutations</h3>

<pre><code># Original
if (x &gt; 10)

<p># Mutations<br>if (x &gt;= 10)    # &gt;<br>if (x <br>if (x <br>if (x == 10)    # &gt;<br>if (x != 10)    # &gt;<br></code></pre></p>

<h3>Logical Mutations</h3>

<pre><code># Original
if (is_valid and has_permission)

<p># Mutations<br>if (is_valid or has_permission)      # and → or<br>if (not is_valid and has_permission) # negação<br>if (is_valid and not has_permission) # negação<br></code></pre></p>

<h3>Conditional Boundary</h3>

<pre><code># Original
while (count &lt; 100)

<p># Mutations<br>while (count &lt;= 100)    # &lt; → &lt;=<br>while (count &gt; 100)     # <br></code></pre></p>

<hr>
<h2>Ferramentas de Mutation Testing</h2>

<h3>Para Diferentes Linguagens</h3>

<figure class="wp-block-table"><table>
<tr><th>Linguagem</th><th>Ferramentas</th></tr>
<tr><td><strong>Python</strong></td><td>mutmut, Cosmic Ray, mutatest</td></tr>
<tr><td><strong>Java</strong></td><td>PITest (pitest)</td></tr>
<tr><td><strong>JavaScript</strong></td><td>Stryker Mutator</td></tr>
<tr><td><strong>C#</strong></td><td>NinjaTurtles, Pitest.NET</td></tr>
<tr><td><strong>Ruby</strong></td><td>Mutant</td></tr>
</table></figure>

<hr>
<h2>Implementação Prática</h2>

<h3>Python com mutmut</h3>

<pre><code># Instalação
pip install mutmut

<p># Configuração (pyproject.toml ou .mutmut.toml)<br>[mutmut]<br>paths_to_mutate = src/<br>test_command = pytest -x<br>backup_command = git checkout<br></code></pre></p>

<pre><code># Executar mutation testing
mutmut run

<p># Ver resultados<br>mutmut results</p>

<p># Mostrar mutants sobrevientes<br>mutmut show survived<br></code></pre></p>

<pre><code># Exemplo: Código a ser testado
# src/calculator.py
def calcular_desconto(valor: float, percentual: float) -&gt; float:
    """Aplica desconto percentual a um valor."""
    if percentual  100:
        raise ValueError("Percentual não pode exceder 100")

<p>desconto = valor * (percentual / 100)<br>    return valor - desconto</p>

<p># src/test_calculator.py<br>import pytest<br>from calculator import calcular_desconto</p>

<p>def test_desconto_basico():<br>    """Testa desconto simples de 10{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}"""<br>    assert calcular_desconto(100, 10) == 90.0</p>

<p>def test_desconto_zero():<br>    """Testa que desconto de 0{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} mantém valor"""<br>    assert calcular_desconto(100, 0) == 100.0</p>

<p>def test_desconto_100_porcento():<br>    """Testa que desconto de 100{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} retorna 0"""<br>    assert calcular_desconto(100, 100) == 0.0</p>

<p>def test_desconto_negativo_deve_falhar():<br>    """Desconto negativo deve lançar erro"""<br>    with pytest.raises(ValueError):<br>        calcular_desconto(100, -10)</p>

<p>def test_desconto_acima_100_deve_falhar():<br>    """Desconto acima de 100{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} deve lançar erro"""<br>    with pytest.raises(ValueError):<br>        calcular_desconto(100, 110)<br></code></pre></p>

<h3>Java com PITest</h3>

<pre><code><!-- pom.xml -->

    org.pitest
    pitest-maven
    1.15.8
    
        
            org.pitest
            pitest-junit5-plugin
            1.15.8
        
    
    
        
            com.example.*
        
        
            com.example.*Test
        
    

</code></pre>

<pre><code># Executar
mvn org.pitest:pitest-maven:mutationCoverage
</code></pre>

<h3>JavaScript com Stryker</h3>

<pre><code># Instalação
npm install -D @stryker-mutator/core

<p># Configuração (stryker.conf.js)<br>module.exports = {<br>  testRunner: 'jest',<br>  mutate: ['src/<em>*/</em>.js'],<br>  reporters: ['html', 'clear-text'],<br>  jest: {<br>    projectType: 'react'<br>  }<br>}<br></code></pre></p>

<pre><code># Executar
npx stryker run
</code></pre>

<hr>
<h2>Interpretando Resultados</h2>

<h3>Score de Mutação</h3>

<pre><code>Mutation Score = (Mutantes Mortos / Total de Mutantes) × 100

<p>Interpretação:<br><ul><li>90-100{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}: Excelente (muitos bugs detectados)</li><ol><li>80-90{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}: Bom</li><br><li>60-80{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}: Precisa melhorar</li><br><li>&lt;60{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}: Suite fraca</li><br></ol></code></pre></p>

<h3>Exemplo de Relatório</h3>

<pre><code>=============== MUTATION TESTING ===============

<p>Total Mutants: 25<br>Killed: 23<br>Survived: 2<br>Timeout: 0<br>Skipped: 0</p>

<p>Score: 92{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}</p>

<p>=============== SURVIVING MUTANTS ===============<br><ol><li>src/calculator.py:32</li><br></ol>   - Changed &gt; to &gt;=<br>   - Still passes: test_desconto_100_porcento<br>   <ol><li>src/validator.py:45</li><br></ol>   - Changed &amp;&amp; to ||<br>   - Still passes: test_validate_multiple_conditions</p>

<p>=============== RECOMMENDATIONS ===============<br><ol><li>Adicione teste para valor exatamente 18</li><br><li>Teste edge case para validação AND/OR</li></ol></ul><br></code></pre></p>

<hr>
<h2>Melhores Práticas</h2>

<h3>1. Combine com Code Coverage</h3>

<pre><code># Mutation testing complementa coverage
# Coverage 100{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} não significa testes bons
# Mutation testing revela gaps
</code></pre>

<h3>2. Priorize Módulos Críticos</h3>

<pre><code># Execute mutation testing em módulos críticos
mutmut run --paths src/payment/,src/auth/
</code></pre>

<h3>3. Corrija Mutantes Sobrevientes</h3>

<pre><code># Mutante sobreviente indica teste fraco
def test_critical_path():
    # Este teste não detecta mudança de &gt; para &gt;=
    result = processar_idade(18)
    assert result == "adulto"  # Passa mesmo com &gt;=

<p># Adicione edge case<br>def test_critical_path_18_anos():<br>    result = processar_idade(18)<br>    assert result == "adulto"<br>    assert processar_idade(17) != "adulto"  # Detecta mudança &gt; para &gt;=<br></code></pre></p>

<h3>4. Automatize no CI</h3>

<pre><code># GitHub Actions
name: Mutation Testing

<p>on:<br>  schedule:<br>    - cron: '0 2 <em> </em> 0'  # Semanalmente</p>

<p>jobs:<br>  mutation:<br>    runs-on: ubuntu-latest<br>    steps:<br>      - uses: actions/checkout@v4</p>

<p>- name: Run mutation tests<br>        run: |<br>          pip install mutmut<br>          mutmut run --paths-to-mutate src/<br>          mutmut results</p>

<p>- name: Check score<br>        run: |<br>          SCORE=$(mutmut results --only-result)<br>          if [ "$SCORE" -lt 80 ]; then<br>            echo "Mutation score below 80{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}: $SCORE"<br>            exit 1<br>          fi<br></code></pre></p>

<hr>
<h2>Conclusão</h2>

<p>Mutation testing é uma técnica poderosa para avaliar qualidade real dos testes. As chaves são:<br><ol><li><strong>Entender conceito</strong> - Muta código, verifica se testes detectam</li><br><li><strong>Usar ferramentas</strong> - mutmut, PITest, Stryker</li><br><li><strong>Interpretar resultados</strong> - Score alto = testes fortes</li><br><li><strong>Criar testes para mutantes sobrevientes</strong> - Melhoria contínua</li><br><li><strong>Automatizar</strong> - Execute regularmente no CI</li><br></ol><br><hr><br><h3>FAQ</h3></p>

<p><strong>P: Mutation testing substitui coverage?</strong>  <br>R: Não. Coverage mostra linhas executadas; mutation mostra se testes detectam bugs.</p>

<p><strong>P: É lento?</strong>  <br>R: Sim! Pode ser 10-100x mais lento que testes normais. Use CI/discrete.</p>

<p><strong>P: Qual score é bom?</strong>  <br>R: 80{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}+ é bom, 90{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}+ é excelente.</p>

<p><strong>P: Vale o esforço?</strong>  <br>R: Para código crítico, sim. Para código simples, talvez não.</p>