Skills detect-static-dependencies
install
source · Clone the upstream repo
git clone https://github.com/dotnet/skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/dotnet/skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/dotnet-test/skills/detect-static-dependencies" ~/.claude/skills/dotnet-skills-detect-static-dependencies && rm -rf "$T"
manifest:
plugins/dotnet-test/skills/detect-static-dependencies/SKILL.mdsource content
Detect Static Dependencies
Scan a C# codebase for calls to hard-to-test static APIs and produce a ranked report showing which statics appear most frequently, which files are most affected, and which abstractions already exist in the .NET ecosystem to replace them.
When to Use
- Auditing a project's testability before adding unit tests
- Understanding the scope of static coupling in a legacy codebase
- Prioritizing which statics to wrap first (highest-frequency wins)
- Creating a migration plan for incremental testability improvements
When Not to Use
- The user wants wrappers generated (hand off to
)generate-testability-wrappers - The user wants mechanical migration done (hand off to
)migrate-static-to-wrapper - The statics are already behind interfaces or
TimeProvider - The code is not C# / .NET
Inputs
| Input | Required | Description |
|---|---|---|
| Target path | Yes | A file, directory, project (.csproj), or solution (.sln) to scan |
| Exclusion patterns | No | Glob patterns to skip (e.g., , ) |
| Category filter | No | Limit to specific categories: , , , , , |
Workflow
Step 1: Determine scan scope
Resolve the target to a set of
.cs files:
- If a
file, scan that single file..cs - If a directory, scan all
files recursively (excluding.cs
,obj/
).bin/ - If a
, find its directory and scan.csproj
files within..cs - If a
, parse it, find all project directories, and scan.sln
files across all projects..cs
Always exclude
obj/, bin/, and any user-specified exclusion patterns.
Step 2: Search for static dependency patterns
Scan each file for calls matching these categories:
| Category | Patterns to search for | Recommended replacement |
|---|---|---|
| Time | , , , , , , | (.NET 8+) |
| File System | , , , , , , , , , , , | (System.IO.Abstractions NuGet) |
| Environment | , , , , , | Custom |
| Network | , , , | (built-in) |
| Console | , , , | wrapper or |
| Process | , , | Custom |
Step 3: Aggregate and rank results
Count each static call pattern across the entire scan scope. Produce a summary with:
- Category summary — total call sites per category (time, filesystem, env, etc.)
- Top patterns — the 10 most frequent individual patterns ranked by count
- Most affected files — files with the highest number of static dependencies
- Existing abstractions available — for each category, note the recommended .NET abstraction:
- Time →
(built-in since .NET 8)TimeProvider - File system →
(NuGet package)System.IO.Abstractions - HTTP →
(built-in)IHttpClientFactory - Environment → custom
IEnvironmentProvider - Console → custom
orIConsoleILogger - Process → custom
IProcessRunner
- Time →
Step 4: Present the report
Format the output as a structured report:
## Static Dependency Report **Scope**: <project/solution name> **Files scanned**: <count> **Total static call sites**: <count> ### Category Summary | Category | Call Sites | Recommended Abstraction | |-------------|-----------|------------------------| | Time | 42 | TimeProvider (.NET 8+) | | File System | 31 | System.IO.Abstractions | | Environment | 12 | IEnvironmentProvider | | ... | ... | ... | ### Top 10 Patterns | # | Pattern | Count | Files | |---|---------------------|-------|-------| | 1 | DateTime.UtcNow | 28 | 14 | | 2 | File.ReadAllText | 18 | 9 | | ... | ### Most Affected Files | File | Static Calls | Categories | |-------------------------------|-------------|---------------------| | Services/OrderProcessor.cs | 12 | Time, FileSystem | | ... | ### Migration Priority 1. **Time** (42 sites) — Use `TimeProvider`, zero NuGet dependencies on .NET 8+ 2. **File System** (31 sites) — Use `System.IO.Abstractions` NuGet package 3. ...
Step 5: Suggest next steps
Based on the report, recommend:
- Which category to tackle first (fewest dependencies, best built-in support)
- Whether to use
for custom wrapper generationgenerate-testability-wrappers - Whether to use
for mechanical bulk migrationmigrate-static-to-wrapper
Validation
- All
files in scope were scanned (check count).cs - Report includes category totals, top patterns, and affected files
- Each detected pattern has a recommended replacement listed
-
andobj/
directories were excludedbin/ - Migration priority is ordered by impact (count × ease of replacement)
Common Pitfalls
| Pitfall | Solution |
|---|---|
Scanning or generated code | Always exclude , , and |
| Counting wrapped calls as statics | Check if the call is behind an interface or injected service before counting |
| Missing statics inside lambdas/LINQ | Search covers all code within files, including lambdas |
Recommending on < .NET 8 | Check in — if < net8.0, recommend or custom |
| Ignoring test projects | Only scan production code — exclude projects from the scan |