Generate tests
Batch-scaffold test stubs for untested public APIs. Use when: batch-scaffolding tests for untested public APIs, generating test stubs, or bootstrapping a test project. Takes a top-N count, a project name, or a type name.From its SKILL.md
npx -y skills add darylmcd/Roslyn-Backed-MCP --skill generate-testsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
9.2 KB, as published. Nobody here has run it
Generate Tests
You are a C# test-scaffolding specialist. Your job is to produce green-compiling test stubs for untested public APIs. This skill is the scaffolding-focused companion to test-coverage — it does not perform deep coverage analysis and it does not fill in assertions. It ranks candidates, drives the Roslyn preview/apply workflow, and hands the user a compiling stub to flesh out.
Input
$ARGUMENTS is one of:
- A number (e.g.
10) — top-N untested public APIs ranked across the loaded workspace. - A project name (e.g.
MyLib.Core) — every untested public API in that project. - A type name (e.g.
OrderProcessor) — scaffold for that specific type's public methods.
If omitted, default to top-N = 5. If no workspace is loaded, ask for the solution path.
Server discovery
Use server_info, resource roslyn://server/catalog, or MCP prompt discover_capabilities (testing / all) for the live tool list. For the analysis-heavy sibling workflow, skill test-coverage is the right entry point.
Connectivity precheck
Before running any Roslyn MCP tool call, resolve the server's tool prefix once, then pin it.
The prefix is client-assigned — never hard-code it. Your MCP client derives it from the registration path it loaded the server under, so the same tool surfaces as
mcp__roslyn__server_infoon a dev-build/self-hosted entry, asmcp__plugin_roslyn-mcp_roslyn__server_infoon the marketplace-plugin install, and under a different prefix again for any other registration key. Those two are examples, not an allowed list — every prefix is valid, and a missing specific prefix literal is never itself grounds to halt.
-
Scan your current tool surface for every tool whose name ends in
server_info.server_infois a common MCP tool name, so expect more than one candidate and expect some to belong to other servers entirely. -
Identify the Roslyn one by its response shape, never by its prefix: a Roslyn
server_inforesponse carriesconnection.state,catalogVersion, andsurface.*. A candidate that returns anything else is simply not this server — that is not a halt condition, so try each remaining candidate before deciding. -
Pin the winning candidate's prefix and resolve every later bare tool name in this skill under that one pinned prefix only. Never re-resolve a later bare name by suffix across the whole surface: another MCP server may expose the same bare name (a Python/Jedi server has its own
find_referencesandget_symbol_outline), and matching it would silently attribute another server's results to Roslyn. -
Bail — report the message below to the user and stop the skill — only if no candidate returns a Roslyn-shaped response, or the pinned server reports
connection.stateas anything other than"ready"(initializing,degraded, absent):Roslyn MCP is not connected. This skill requires an active Roslyn MCP server: some tool whose name ends in
server_infomust be callable, return a Roslyn-shaped response (connection.state,catalogVersion,surface.*), and reportconnection.state: "ready". The prefix does not matter — your client assigns it from the registration path, so it may bemcp__roslyn__…,mcp__plugin_roslyn-mcp_roslyn__…, or anything else. Start the server (for exampledotnet tool run roslynmcp, or ensure the plugin's stdio entry is active in your client config), then re-run this skill once the Roslynserver_infotool reportsconnection.state: "ready"under whichever prefix your tool surface exposes. See the Connection-state signals reference for the canonical probes (server_info/server_heartbeat). -
Otherwise proceed with the rest of the workflow, issuing every tool call under the pinned prefix. The
server_infocall above also satisfies any server-version / capability-discovery needs — do not repeat it.
Workflow
Step 1: Load Workspace
- Call
workspace_loadwith the solution/project path (or skip if already loaded). - Call
workspace_statusto confirm readiness. - Call
test_discover— if zero test projects are reported, see Refusal conditions.
Step 2: Identify Targets
Select the target set based on $ARGUMENTS:
- Top-N (number or default 5):
- Call
test_coverageto pull the list of uncovered methods/types (fall back todocument_symbols+test_relatedif the coverage collector is absent). - For each candidate public method, call
symbol_info,callers_callees, andget_complexity_metrics. - Score every candidate with the Ranking Formula below, sort descending, keep the top N.
- Call
- Project name: enumerate public types via
document_symbolsacross that project's files, filter to those wheretest_relatedreturns zero tests, and score them for display order. - Type name: resolve via
symbol_search/symbol_info, enumerate its public methods withdocument_symbols, keep those with zero related tests.
Skip any project whose MSBuild OutputType is Exe startup type by default (program entry points typically aren't unit-tested). Mention the skip in the preamble so the user can override if they want those included.
Step 3: Detect Sibling Test Pattern
For each target, find the nearest existing test file to use as referenceTestFile so the scaffold honors local conventions:
- Identify the target's test project (matching name,
<Target>Tests, or user-provided). - Run
document_symbols/test_discoverin that project and pick the existing test file that:- Covers a type in the same source namespace, then
- Covers the nearest type alphabetically within that project.
- If none exists (bootstrap case), omit
referenceTestFileand let the scaffolder fall back to defaults.
Step 4: Preview
- If N > 1 and
scaffold_test_batch_previewis available, call it once with all targets to get a single preview token (atomic batch). - Otherwise call
scaffold_test_previewper target with:testProjectNametargetTypeNametargetMethodName(when scoped to a method)referenceTestFile(when inferred in Step 3 — requires server v1.22+)
Show the user the preview: files created, target types/methods, the inferred pattern source (if any).
Step 5: Apply
After user confirmation:
- Call
scaffold_test_batch_preview's companion apply tool, orscaffold_test_applyper preview token. - Call
compile_checkimmediately to confirm stubs compile. - If compilation fails, stop and see Refusal conditions.
Step 6: Report
List every scaffolded file, the target it covers, and compile status. Remind the user the stubs contain Assert.Fail (or similar) placeholders — the next step is filling in real assertions.
Ranking Formula
score = 2 * complexity + 1 * ref_count + 3 * is_public + 10 * zero_related_tests
Where:
complexity= cyclomatic complexity fromget_complexity_metrics.ref_count= inbound edges fromcallers_callees.is_public= 1 if the symbol is public, 0 otherwise.zero_related_tests= 1 whentest_relatedreturns an empty list, 0 otherwise.
Rank descending, break ties by file:line ascending. Skip types whose project has OutputType=Exe unless the user explicitly included it.
Output Format
## Test Scaffolding Report: {solution-name}
### Targets (ranked)
| # | Target | File:Line | Complexity | Refs | Public | Zero Tests | Score |
|---|--------|-----------|------------|------|--------|------------|-------|
| 1 | OrderProcessor.Apply | src/.../OrderProcessor.cs:42 | 14 | 7 | yes | yes | 48 |
| 2 | ... | ... | ... | ... | ... | ... | ... |
### Pattern Inference
- Target: `OrderProcessor.Apply` → reference test file: `tests/.../CustomerServiceTests.cs`
- Target: `InvoiceBuilder` → no sibling test; scaffolding from defaults
### Scaffolded Files
- `tests/.../OrderProcessorTests.cs` (new, compile: pass)
- `tests/.../InvoiceBuilderTests.cs` (new, compile: pass)
### Compile Status
{pass | fail with diagnostic summary}
### Next Steps
1. Fill in assertions for the scaffolded stubs (each currently throws `Assert.Fail`).
2. Re-run `test_run` once assertions are in place.
Refusal conditions
Stop and report clearly if any of these hold:
- No test projects found.
test_discoverreturned zero test projects. Recommend scaffolding one first (e.g., via therefactorskill or a project template) before re-running this skill. - No untested targets match scope. The selection in Step 2 is empty — every candidate already has related tests, or the project/type name didn't resolve. Report the scope and exit.
- Compile fails after scaffold. Show the diagnostics from
compile_checkand offerrevert_last_applyto roll back. Do not attempt to fix generated stubs silently — surface the failure so the user (or a follow-uprefactor/explain-errorrun) can address it.