Incremental Testing
Test only mutations in files that have changed - perfect for PR checks and fast feedback.
Basic Usage
# Test only files changed since main
dart_mutant --incremental --base-ref main
How It Works
- Git Diff: dart_mutant runs
git diff --name-only base_ref HEAD - Filter: Only
.dartfiles inlib/are considered - Mutate: Mutations are generated only for changed files
- Test: Standard mutation testing on the subset
Options
Base Reference
Compare against any git ref:
# Compare against main branch
dart_mutant --incremental --base-ref main
# Compare against specific branch
dart_mutant --incremental --base-ref origin/develop
# Compare against tag
dart_mutant --incremental --base-ref v1.2.0
# Compare against specific commit
dart_mutant --incremental --base-ref abc1234
# Compare against previous commit
dart_mutant --incremental --base-ref HEAD~1
Default Base
If --base-ref is not specified, dart_mutant uses:
mainif it existsmasterif main doesn't exist- Error if neither exists
CI Integration
GitHub Actions
name: Mutation Test (Incremental)
on:
pull_request:
branches: [main]
jobs:
mutation-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history for git diff
- name: Setup Dart
uses: dart-lang/setup-dart@v1
- name: Install dart_mutant
run: |
curl -L https://github.com/user/dart_mutant/releases/latest/download/dart_mutant-x86_64-unknown-linux-gnu.tar.gz | tar xz
sudo mv dart_mutant /usr/local/bin/
- name: Run incremental mutation tests
run: |
dart pub get
dart_mutant --incremental --base-ref origin/main --threshold 70
Important: Use
fetch-depth: 0to get full git history for accurate diffs.
GitLab CI
mutation-test:
script:
- dart_mutant --incremental --base-ref origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
Strategies
PR Checks: Incremental Only
Fast feedback on changed code:
# On PR
dart_mutant --incremental --threshold 70
Main Branch: Full Run
Comprehensive testing on merge:
# On push to main
dart_mutant --threshold 80
Hybrid Approach
Incremental for quick feedback, full run nightly:
# PR workflow
name: PR Mutation Test
on: pull_request
jobs:
mutation:
runs-on: ubuntu-latest
steps:
- run: dart_mutant --incremental --threshold 60
# Nightly workflow
name: Nightly Mutation Test
on:
schedule:
- cron: '0 2 * * *'
jobs:
mutation:
runs-on: ubuntu-latest
steps:
- run: dart_mutant --threshold 80 --html
Performance Comparison
| Mode | Files | Mutations | Time |
|---|---|---|---|
| Full | 50 | 2,000 | 15 min |
| Incremental (3 files) | 3 | 120 | 1 min |
| Incremental (10 files) | 10 | 400 | 4 min |
Limitations
- New bugs in unchanged code: Incremental mode won't catch regressions in files you didn't change
- Cross-file dependencies: Changing a function signature might break tests for unchanged files
- Git required: Must be in a git repository
Best Practices
1. Use Full Runs Regularly
Don't rely solely on incremental mode:
# Weekly full mutation test
dart_mutant --threshold 80
2. Lower Threshold for Incremental
Be lenient on incremental (new code) but strict on full runs:
# Incremental - 70% threshold
dart_mutant --incremental --threshold 70
# Full - 80% threshold
dart_mutant --threshold 80
3. Fetch Full History in CI
Shallow clones break incremental mode:
# GitHub Actions
- uses: actions/checkout@v4
with:
fetch-depth: 0
Troubleshooting
"No changed files found"
# Check what git sees
git diff --name-only main HEAD
# Ensure base ref exists
git branch -a | grep main
"fatal: bad revision"
# Fetch the base branch
git fetch origin main:main
# Or use origin/main
dart_mutant --incremental --base-ref origin/main
Next Steps
- CI/CD Integration - Full CI setup guide
- Filtering - Additional file filtering options