Skip to content

[CHORE]: Add mutation testing with mutmut for test quality validationΒ #280

@crivetimihai

Description

@crivetimihai

🧭 Chore Summary β€” Add mutation testing with mutmut for test quality validation

Implement mutation testing using mutmut to measure and improve test suite quality beyond traditional code coverage. Add Makefile targets and GitHub Actions integration to automatically detect weak assertions, missing edge cases, and untested logic paths through systematic code mutations.


🧱 Areas Affected

  • Makefile β€” new mutation testing targets
  • GitHub Actions β€” test quality validation workflow
  • Test suite quality β€” improved assertion coverage
  • CI/CD pipeline β€” mutation score quality gates
  • Documentation β€” mutation testing guide
  • pyproject.toml β€” mutmut configuration

βš™οΈ Context / Rationale

What is Mutation Testing?

Traditional code coverage tells you which lines executed, but not whether your tests would catch bugs on those lines. Mutation testing solves this by automatically creating tiny, systematic code changes ("mutants") and re-running your test suite:

# Original code
def calculate_discount(price, percentage):
    if percentage > 0:                    # Mutant: change > to >=
        return price * (1 - percentage)   # Mutant: change - to +
    return price                          # Mutant: return 0

# Example mutations mutmut creates:
# 1. `percentage > 0` β†’ `percentage >= 0` 
# 2. `1 - percentage` β†’ `1 + percentage`
# 3. `return price` β†’ `return 0`

Mutation Results:

  • Killed mutant = Tests failed βœ… (your tests caught the bug)
  • Survived mutant = Tests passed ❌ (potential gap in test coverage)

Why mutmut?

mutmut is a fast, Python-native mutation testing tool that:

  • Integrates seamlessly with pytest (our existing test runner)
  • Provides incremental testing (only re-runs tests for changed files)
  • Supports coverage-guided mutations (only mutate covered lines)
  • Offers rich CLI with detailed reporting (mutmut results, mutmut html)
  • Easily configurable via pyproject.toml for CI integration

Example workflow:

# Run mutation testing
mutmut run --paths-to-mutate=mcpgateway

# View results
mutmut results  # Show summary: 47/50 killed (94% mutation score)

# Examine survivors
mutmut show 3   # Inspect specific surviving mutant

# Generate HTML report  
mutmut html     # Browse detailed results in browser

A high mutation score (>80%) indicates robust tests that catch real bugs, while survivors reveal weak assertions and missing edge cases.


πŸ“¦ New & Updated Make Targets

Target Purpose
make mutmut-install Install mutmut in development virtualenv
make mutmut-run Run mutation testing on mcpgateway package with coverage guidance
make mutmut-results Display mutation testing summary and surviving mutants
make mutmut-html Generate browsable HTML report of mutation results
make mutmut-ci CI-friendly mutation testing with score threshold enforcement

Existing test targets remain: test, coverage, pytest-examples.


πŸ“‹ Acceptance Criteria

  • make mutmut-run executes mutation testing on mcpgateway/ package
  • Mutation score baseline established (aim for >75% initially, >85% target)
  • make mutmut-html generates browsable HTML report showing survivors
  • GitHub Actions runs mutation testing and fails if score drops below threshold
  • Configuration in pyproject.toml excludes test files and migrations
  • All existing tests (make test, make coverage) stay green
  • Documentation explains mutation testing workflow and interpreting results

πŸ› οΈ Task List

  1. Add mutmut configuration

    # pyproject.toml
    [tool.mutmut]
    paths_to_mutate = "mcpgateway/"
    backup = false
    runner = "python -m pytest"
    tests_dir = "tests/"
    cache_only = true
    coverage = true
    mutation_score_threshold = 75
    
    # Exclude patterns
    exclude = [
        "mcpgateway/migrations/*",
        "mcpgateway/__init__.py",
        "mcpgateway/version.py"
    ]
  2. Add Makefile targets

    .PHONY: mutmut-install mutmut-run mutmut-results mutmut-html mutmut-ci
    
    mutmut-install:
    	@echo "πŸ“₯ Installing mutmut..."
    	@$(VENV_DIR)/bin/pip install mutmut
    
    mutmut-run: mutmut-install
    	@echo "🧬 Running mutation testing..."
    	@$(VENV_DIR)/bin/mutmut run --paths-to-mutate mcpgateway
    
    mutmut-results:
    	@echo "πŸ“Š Mutation testing results:"
    	@$(VENV_DIR)/bin/mutmut results
    
    mutmut-html:
    	@echo "πŸ“„ Generating HTML mutation report..."
    	@$(VENV_DIR)/bin/mutmut html
    	@echo "Report available at: file://$(PWD)/html/index.html"
    
    mutmut-ci:
    	@echo "πŸ” CI mutation testing with threshold check..."
    	@$(VENV_DIR)/bin/mutmut run --ci --paths-to-mutate mcpgateway
  3. GitHub Actions integration

    • Add mutation testing job to existing test workflow
    • Cache mutmut results between runs for faster CI
    • Configure failure threshold (75% minimum mutation score)
    • Generate mutation report artifact for download
  4. Baseline establishment

    • Run initial make mutmut-run to establish current mutation score
    • Identify and fix obvious surviving mutants (weak assertions)
    • Set realistic initial threshold based on current score
  5. Test suite improvements

    • Add missing edge case tests for surviving mutants
    • Strengthen assertions (e.g., assert result β†’ assert result == expected)
    • Add boundary condition tests revealed by mutations
  6. Documentation

    • Add mutation testing section to testing documentation
    • Explain how to interpret mutation results and fix survivors
    • Document workflow for investigating failing mutants
  7. Performance optimization

    • Configure coverage-guided mutations to reduce runtime
    • Set up incremental mutation testing for faster development
    • Cache mutmut database for CI performance
  8. Final validation

    • make mutmut-run && make mutmut-results
    • Verify HTML report generation and browsability
    • Test GitHub Actions workflow with mutation score threshold

πŸ“– References


🧩 Additional Notes

  • Start conservative: Begin with 75% threshold and gradually increase to 85%+
  • Incremental adoption: Focus on core business logic first (tools, resources, prompts)
  • Pragmatic exemptions: Use # pragma: no mutate for intentionally untested code
  • Performance consideration: Mutation testing is slower than unit tests - optimize with coverage guidance
  • CI integration: Run on PRs but consider making it a non-blocking check initially
  • Common mutations: > to >=, and to or, + to -, method calls removed, return values changed
  • Interpreting survivors: Each surviving mutant represents a potential bug your tests wouldn't catch

Metadata

Metadata

Assignees

Labels

choreLinting, formatting, dependency hygiene, or project maintenance chorescicdIssue with CI/CD process (GitHub Actions, scaffolding)devopsDevOps activities (containers, automation, deployment, makefiles, etc)help wantedExtra attention is neededtestingTesting (unit, e2e, manual, automated, etc)triageIssues / Features awaiting triage

Type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions