dotnet-stryker
Use the open-source free `Stryker.NET` mutation testing tool for .NET. Use when a repo needs to measure whether tests actually catch faults, especially in critical libraries or domains.
Install
npx skills add https://github.com/Postpartum-genushyacinthus29/dotnet-skills/tree/main/skills/dotnet-stryker
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install postpartum-genushyacinthus29-dotnet-skills@llmmart
git clone https://github.com/Postpartum-genushyacinthus29/dotnet-skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole postpartum-genushyacinthus29/dotnet-skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Stryker.NET
Trigger On
- the repo uses or wants
Stryker.NET - mutation testing is needed for high-risk code
Value
- produce a concrete project delta: code, docs, config, tests, CI, or review artifact
- reduce ambiguity through explicit planning, verification, and final validation skills
- leave reusable project context so future tasks are faster and safer
Do Not Use For
- every PR path by default in a large repo
- simple coverage collection
Inputs
- the nearest
AGENTS.md - target projects and critical paths
- time budget for mutation runs
Quick Start
- Read the nearest
AGENTS.mdand confirm scope and constraints. - Run this skill's
Workflowthrough theRalph Loopuntil outcomes are acceptable. - Return the
Required Result Formatwith concrete artifacts and verification evidence.
Workflow
- Run mutation testing on critical projects, not blindly on the whole mono-repo.
- Keep it out of the fastest PR path unless the repo explicitly accepts the runtime cost.
- Stabilize tests first; mutation testing amplifies flaky or slow suites.
Bootstrap When Missing
If Stryker.NET is not configured yet:
- Detect current state:
rg --files -g '.config/dotnet-tools.json'dotnet tool list --localdotnet tool list --global
- Prefer local tool installation for reproducible CI:
dotnet new tool-manifest(if missing)dotnet tool install dotnet-stryker
- Choose a focused target scope and mutation budget before enabling CI.
- Add a dedicated mutation command in
AGENTS.mdand CI (not in the fastest PR path by default). - Run
dotnet strykeron the target project and returnstatus: configuredorstatus: improved. - If mutation testing is explicitly out of scope, return
status: not_applicable.
Deliver
- explicit mutation-test scope
- reproducible Stryker commands
Validate
- the selected scope is affordable in CI
- mutation score is interpreted with test quality, not as a vanity number
Ralph Loop
Use the Ralph Loop for every task, including docs, architecture, testing, and tooling work.
- Plan first (mandatory):
- analyze current state
- define target outcome, constraints, and risks
- write a detailed execution plan
- list final validation skills to run at the end, with order and reason
- Execute one planned step and produce a concrete delta.
- Review the result and capture findings with actionable next fixes.
- Apply fixes in small batches and rerun the relevant checks or review steps.
- Update the plan after each iteration.
- Repeat until outcomes are acceptable or only explicit exceptions remain.
- If a dependency is missing, bootstrap it or return
status: not_applicablewith explicit reason and fallback path.
Required Result Format
status:complete|clean|improved|configured|not_applicable|blockedplan: concise plan and current iteration stepactions_taken: concrete changes madevalidation_skills: final skills run, or skipped with reasonsverification: commands, checks, or review evidence summaryremaining: top unresolved items ornone
For setup-only requests with no execution, return status: configured and exact next commands.
Load References
references/stryker.mdreferences/commands.mdreferences/patterns.md
Example Requests
- "Add Stryker for this library."
- "Use mutation testing on our critical domain layer."
Files (dotnet-skills)
-
references
-
commands.md 4.9 KB
# Stryker CLI Commands and Configuration ## CLI Commands ### Basic Run ```bash dotnet stryker ``` ### Run with Project Specification ```bash dotnet stryker --project MyProject.csproj ``` ### Run with Test Project ```bash dotnet stryker --project MyProject.csproj --test-project MyProject.Tests.csproj ``` ### Run with Solution ```bash dotnet stryker --solution MySolution.sln ``` ### Run with Mutation Level ```bash dotnet stryker --mutation-level Basic dotnet stryker --mutation-level Standard dotnet stryker --mutation-level Advanced dotnet stryker --mutation-level Complete ``` ### Run with Concurrency ```bash dotnet stryker --concurrency 4 ``` ### Run with Reporters ```bash dotnet stryker --reporter html dotnet stryker --reporter json dotnet stryker --reporter markdown dotnet stryker --reporter progress dotnet stryker --reporter cleartext dotnet stryker --reporter dashboard ``` ### Run with Thresholds ```bash dotnet stryker --threshold-high 80 --threshold-low 60 --threshold-break 40 ``` ### Dry Run (No Mutations) ```bash dotnet stryker --dry-run ``` ### Filter Files ```bash dotnet stryker --mutate "**/*.cs" --mutate "!**/Migrations/**" ``` ### Filter Mutations ```bash dotnet stryker --ignore-mutations Linq dotnet stryker --ignore-mutations String dotnet stryker --ignore-mutations Arithmetic ``` ## Configuration File Stryker uses `stryker-config.json` in the project root. ### Minimal Configuration ```json { "stryker-config": { "project": "MyProject.csproj" } } ``` ### Standard Configuration ```json { "stryker-config": { "project": "MyProject.csproj", "test-projects": ["MyProject.Tests.csproj"], "mutation-level": "Standard", "thresholds": { "high": 80, "low": 60, "break": 40 }, "reporters": ["progress", "html"], "concurrency": 4 } } ``` ### Full Configuration ```json { "stryker-config": { "project": "MyProject.csproj", "test-projects": ["MyProject.Tests.csproj", "MyProject.IntegrationTests.csproj"], "solution": "MySolution.sln", "mutation-level": "Advanced", "mutate": [ "**/*.cs", "!**/Migrations/**", "!**/Generated/**" ], "ignore-mutations": [ "Linq" ], "thresholds": { "high": 80, "low": 60, "break": 40 }, "reporters": ["progress", "html", "json"], "report-file-name": "mutation-report", "concurrency": 4, "log-level": "info", "coverage-analysis": "perTest", "disable-bail": false, "since": { "enabled": true, "target": "main" } } } ``` ## Key Options Reference ### Mutation Levels | Level | Mutators Included | |----------|------------------------------------------------------| | Basic | Core arithmetic, boolean, comparison | | Standard | Basic + string, equality, logical operators | | Advanced | Standard + linq, method calls, block statements | | Complete | All available mutators | ### Reporters | Reporter | Output | |------------|------------------------------------------------------| | html | Interactive HTML report | | json | Machine-readable JSON | | markdown | Markdown summary | | progress | Console progress bar | | cleartext | Plain text console output | | dashboard | Stryker Dashboard upload | | dots | Minimal dot progress | ### Coverage Analysis Modes | Mode | Description | |---------------|------------------------------------------------------| | off | Run all tests for each mutant | | perTest | Track which tests cover which mutants | | perTestInIsolation | Same as perTest but with process isolation | ### Incremental Mutation Testing Enable incremental mutation testing to only test changed code: ```json { "stryker-config": { "since": { "enabled": true, "target": "main" } } } ``` CLI equivalent: ```bash dotnet stryker --since --since-target main ``` ## CI Integration ### GitHub Actions ```yaml - name: Run Stryker run: dotnet stryker --reporter json --reporter html continue-on-error: true - name: Upload Mutation Report uses: actions/upload-artifact@v4 with: name: mutation-report path: StrykerOutput/ ``` ### Azure Pipelines ```yaml - script: dotnet stryker --reporter json --reporter html displayName: 'Run Mutation Tests' continueOnError: true - task: PublishBuildArtifacts@1 inputs: pathToPublish: 'StrykerOutput' artifactName: 'MutationReport' ``` ## Output Directories Default output: `StrykerOutput/<timestamp>/` Custom output: ```bash dotnet stryker --output ./reports/mutations ``` -
patterns.md 5.5 KB
# Mutation Testing Patterns and Thresholds ## Threshold Guidelines ### Threshold Levels | Threshold | Purpose | |-----------|------------------------------------------------------| | high | Score above this is green/excellent | | low | Score below this is yellow/warning | | break | Score below this fails the build | ### Recommended Thresholds by Context #### New Critical Code ```json { "thresholds": { "high": 90, "low": 80, "break": 70 } } ``` #### Established Production Code ```json { "thresholds": { "high": 80, "low": 60, "break": 50 } } ``` #### Legacy Code Under Improvement ```json { "thresholds": { "high": 70, "low": 50, "break": 30 } } ``` #### High-Risk Domain Logic ```json { "thresholds": { "high": 95, "low": 90, "break": 85 } } ``` ## Mutation Score Interpretation ### What Mutation Score Means - **100%**: All mutants killed - every code mutation was detected by tests - **80-99%**: Strong test suite - most mutations detected - **60-79%**: Adequate coverage - significant gaps may exist - **40-59%**: Weak coverage - many logic errors could go undetected - **Below 40%**: Poor coverage - tests provide minimal fault detection ### Survived Mutants A survived mutant means: 1. A code mutation was made 2. All tests still passed 3. The test suite did not detect the change Common causes: - Missing assertions - Weak assertions (checking only part of behavior) - Untested edge cases - Dead code - Equivalent mutants (mutation produces same behavior) ## Scoping Patterns ### Focus on Critical Paths Target high-value code first: ```json { "mutate": [ "**/Domain/**/*.cs", "**/Core/**/*.cs", "!**/*Dto.cs", "!**/*Config.cs" ] } ``` ### Exclude Generated and Trivial Code ```json { "mutate": [ "**/*.cs", "!**/Migrations/**", "!**/Generated/**", "!**/obj/**", "!**/*.Designer.cs", "!**/GlobalUsings.cs" ] } ``` ### Ignore Low-Value Mutations ```json { "ignore-mutations": [ "Linq", "StringMethod" ] } ``` ## Mutation Categories ### Arithmetic Mutations Original: `a + b` Mutated: `a - b`, `a * b`, `a / b` ### Comparison Mutations Original: `a > b` Mutated: `a >= b`, `a < b`, `a == b` ### Boolean Mutations Original: `true` Mutated: `false` Original: `a && b` Mutated: `a || b` ### Equality Mutations Original: `a == b` Mutated: `a != b` ### Negation Mutations Original: `!condition` Mutated: `condition` ### Block Statement Mutations Original: `if (x) { DoSomething(); }` Mutated: `if (x) { }` ### Return Value Mutations Original: `return value;` Mutated: `return default;` ## Patterns for Surviving Mutants ### Pattern: Missing Boundary Tests Mutation that survives: ```csharp // Original: if (x >= 10) // Mutated: if (x > 10) ``` Fix: Add boundary test for `x = 10`. ### Pattern: Missing Null Checks Mutation that survives: ```csharp // Original: return item ?? default; // Mutated: return item; ``` Fix: Add test for null input. ### Pattern: Unchecked Error Paths Mutation that survives: ```csharp // Original: throw new ArgumentException(); // Mutated: (removed) ``` Fix: Add test that expects the exception. ### Pattern: Side Effect Not Verified Mutation that survives: ```csharp // Original: _logger.Log(message); // Mutated: (removed) ``` Fix: Verify logger was called in test. ## Incremental Mutation Testing ### Run Only on Changed Code ```bash dotnet stryker --since --since-target main ``` ### Configuration for CI ```json { "stryker-config": { "since": { "enabled": true, "target": "main" } } } ``` ### When to Use Full Mutation Runs - Before major releases - After significant refactoring - When establishing baseline scores - On scheduled nightly or weekly builds ## Performance Optimization ### Use Coverage Analysis ```json { "coverage-analysis": "perTest" } ``` This tracks which tests cover which code, running only relevant tests per mutant. ### Limit Concurrency Based on Resources ```json { "concurrency": 4 } ``` Higher values use more memory and CPU. ### Use Baseline for Large Codebases ```json { "baseline": { "enabled": true, "provider": "disk", "path": ".stryker-baseline" } } ``` This caches results and only re-runs mutations for changed code. ## Anti-Patterns ### Do Not Chase 100% Everywhere Diminishing returns on low-value code. Focus effort on: - Domain logic - Business rules - Critical calculations - Security-sensitive code ### Do Not Ignore Survived Mutants Blindly Each survived mutant is a potential bug that tests would miss. Investigate before ignoring. ### Do Not Run Full Mutation Testing on Every PR Too slow for large codebases. Use incremental mode or schedule full runs separately. ### Do Not Set Break Threshold Too High Initially Start conservative and increase as test quality improves. A failing mutation gate on every PR creates frustration without value. ## Workflow Integration ### Recommended PR Workflow 1. Run incremental mutation testing on changed files 2. Report results without failing the build 3. Track trends over time ### Recommended Release Workflow 1. Run full mutation testing before release branches 2. Use break threshold to enforce quality gate 3. Generate reports for team review ### Recommended Nightly Workflow 1. Run full mutation testing on main branch 2. Generate trend reports 3. Open issues for significant score drops -
stryker.md 880 B
# Stryker.NET ## Open/Free Status - open source - free to use ## Install ```bash dotnet tool install -g dotnet-stryker ``` Or as a local tool: ```bash dotnet new tool-manifest dotnet tool install dotnet-stryker ``` ## Verify First Before installing, check whether the repo already has a local or global Stryker tool: ```bash rg --files -g '.config/dotnet-tools.json' dotnet tool list --local dotnet tool list --global command -v dotnet-stryker ``` ## Common Usage ```bash dotnet stryker ``` ## CI Fit - best for critical libraries, domain logic, and less frequently changing hotspots - usually too expensive for the fastest PR gate in large solutions ## When Not To Use - when the test suite is already flaky or too slow - when simple build, test, and coverage gates are still not stable ## Sources - [Stryker.NET](https://github.com/stryker-mutator/stryker-net)
-
-
SKILL.md 3.8 KB
--- name: dotnet-stryker version: "1.0.0" category: "Testing" description: "Use the open-source free `Stryker.NET` mutation testing tool for .NET. Use when a repo needs to measure whether tests actually catch faults, especially in critical libraries or domains." compatibility: "Requires a .NET test project or solution; respects the repo's `AGENTS.md` commands first." --- # Stryker.NET ## Trigger On - the repo uses or wants `Stryker.NET` - mutation testing is needed for high-risk code ## Value - produce a concrete project delta: code, docs, config, tests, CI, or review artifact - reduce ambiguity through explicit planning, verification, and final validation skills - leave reusable project context so future tasks are faster and safer ## Do Not Use For - every PR path by default in a large repo - simple coverage collection ## Inputs - the nearest `AGENTS.md` - target projects and critical paths - time budget for mutation runs ## Quick Start 1. Read the nearest `AGENTS.md` and confirm scope and constraints. 2. Run this skill's `Workflow` through the `Ralph Loop` until outcomes are acceptable. 3. Return the `Required Result Format` with concrete artifacts and verification evidence. ## Workflow 1. Run mutation testing on critical projects, not blindly on the whole mono-repo. 2. Keep it out of the fastest PR path unless the repo explicitly accepts the runtime cost. 3. Stabilize tests first; mutation testing amplifies flaky or slow suites. ## Bootstrap When Missing If `Stryker.NET` is not configured yet: 1. Detect current state: - `rg --files -g '.config/dotnet-tools.json'` - `dotnet tool list --local` - `dotnet tool list --global` 2. Prefer local tool installation for reproducible CI: - `dotnet new tool-manifest` (if missing) - `dotnet tool install dotnet-stryker` 3. Choose a focused target scope and mutation budget before enabling CI. 4. Add a dedicated mutation command in `AGENTS.md` and CI (not in the fastest PR path by default). 5. Run `dotnet stryker` on the target project and return `status: configured` or `status: improved`. 6. If mutation testing is explicitly out of scope, return `status: not_applicable`. ## Deliver - explicit mutation-test scope - reproducible Stryker commands ## Validate - the selected scope is affordable in CI - mutation score is interpreted with test quality, not as a vanity number ## Ralph Loop Use the Ralph Loop for every task, including docs, architecture, testing, and tooling work. 1. Plan first (mandatory): - analyze current state - define target outcome, constraints, and risks - write a detailed execution plan - list final validation skills to run at the end, with order and reason 2. Execute one planned step and produce a concrete delta. 3. Review the result and capture findings with actionable next fixes. 4. Apply fixes in small batches and rerun the relevant checks or review steps. 5. Update the plan after each iteration. 6. Repeat until outcomes are acceptable or only explicit exceptions remain. 7. If a dependency is missing, bootstrap it or return `status: not_applicable` with explicit reason and fallback path. ### Required Result Format - `status`: `complete` | `clean` | `improved` | `configured` | `not_applicable` | `blocked` - `plan`: concise plan and current iteration step - `actions_taken`: concrete changes made - `validation_skills`: final skills run, or skipped with reasons - `verification`: commands, checks, or review evidence summary - `remaining`: top unresolved items or `none` For setup-only requests with no execution, return `status: configured` and exact next commands. ## Load References - `references/stryker.md` - `references/commands.md` - `references/patterns.md` ## Example Requests - "Add Stryker for this library." - "Use mutation testing on our critical domain layer."
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.