csharp-scripts
Run file-based C# apps with the .NET CLI when the user explicitly wants C#/.NET code without creating a project. Use for C# language/API experiments, one-file…
MUST USE for C#/.NET deterministic tests that require the smallest production seam for DateTime/Task.Delay/File/Environment/Guid/Random, static API preservation, nested/parallel overrides, or no real I/O. USE ONLY when the target workspace contains C# source plus a .csproj or
$ npx -y skills add dotnet/skills --skill testability-obstacle --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/testability-obstacleContext preview
The summary Claude sees to decide when to auto-load this skill.
MUST USE for C#/.NET deterministic tests that require the smallest production seam for DateTime/Task.Delay/File/Environment/Guid/Random, static API preservation, nested/parallel overrides, or no real I/O. USE ONLY when the target workspace contains C# source plus a .csproj or
name: testability-obstacle description: >- MUST USE for C#/.NET deterministic tests that require the smallest production seam for DateTime/Task.Delay/File/Environment/Guid/Random, static API preservation, nested/parallel overrides, or no real I/O. USE ONLY when the target workspace contains C# source plus a .csproj or .sln. DO NOT USE for audits, bulk migration, code that already has an injectable seam, or an explicit migration to a user-named existing abstraction (migrate-static-to-wrapper). Use instead of general test generation when the requested test is impossible without a production edit and seam selection is still open. license: MIT
Introduce the smallest behavior-preserving seam needed to test a specific C# behavior, then add deterministic tests that prove both the behavior and the seam. The production edit is a means to the requested test, not an invitation to redesign adjacent code.
process, or another ambient dependency.
a fake through the existing seam using `code-testing-agent`.
`detect-static-dependencies`.
`generate-testability-wrappers`.
`migrate-static-to-wrapper`, then generate tests separately.
`IFileSystem` and asks to migrate call sites to it. Use `migrate-static-to-wrapper`, which also updates affected tests.
| Input | Required | Description | |-------|----------|-------------| | Behavior to test | Yes | The method/workflow and expected observable behavior | | Target scope | No | Discover the narrowest relevant file/project when omitted | | Allowed production changes | No | Default to the minimum internal/constructor seam |
Read the target production path and its existing tests. Identify the exact ambient operation preventing a deterministic test and the behavior that must remain unchanged. Do not run a repository-wide static scan for a single-class request.
If an adequate seam already exists, stop refactoring and use it. This skill adds no value when a fake can already be supplied.
Choose by dependency and repository constraints:
| Dependency | Preferred seam | |------------|----------------| | Current time / timers | Inject `TimeProvider`; use `FakeTimeProvider` in tests | | Filesystem | Existing repository abstraction; for one write/read operation use an injected delegate when conventions allow, otherwise a one-member interface or an already accepted `System.IO.Abstractions` | | HTTP | Existing typed `HttpClient`/handler or `IHttpClientFactory` seam | | Randomness | One generated value: injected delegate with `Random.Shared` as the production default; multiple operations/state: inject `Random` or a minimal generator interface | | Environment/console/process | Minimal interface containing only members used by the target |
The scoped `AsyncLocal<T>` rule applies to every static API that must retain its public static shape — clocks, filesystem access, environment lookups, identity generation, and randomness. The scope captures and restores the previous value; never implement `Dispose()` as an unconditional assignment to `null`. Store the provider/value itself in `AsyncLocal<T>`. Do not put a mutable `Stack<T>`, list, or other shared mutable collection in the slot: child execution contexts can inherit the same object and corrupt each other's nesting. When the provider itself is mutable (for example an in-memory store or fake time provider), establish a fresh provider inside each parallel flow rather than mutating one inherited instance from a parent context.
Constructor injection is the default for instance classes. Reuse the repository's DI and naming conventions, but do not add a DI container to a class library just to satisfy this workflow.
Preserve the existing public construction surface unless the user authorizes an API change. Keep a public parameterless constructor as the real-dependency default and place a test-only delegate/provider constructor at the narrowest visibility the test project can reach. Do not turn the seam into a new public optional parameter merely for test convenience.
For a static class or a public API that cannot change, use a scoped ambient seam only when constructor/parameter injection is impossible. The override must:
Use built-in fake-time-aware overloads instead of inventing an `IDelay` wrapper:
| Ambient operation | Replacement | |-------------------|-------------| | `Task.Delay(delay, token)` | `Task.Delay(delay, timeProvider, token)` | | `new CancellationTokenSource(delay)` | `new CancellationTokenSource(delay, timeProvider)` | | `PeriodicTimer(period)` | `new PeriodicTimer(period, timeProvider)` when the target framework provides it |
Test delayed behavior by starting the operation, proving it is incomplete, advancing `FakeTimeProvider`, then awaiting it. For a deadline or boundary, advance to immediately before the deadline and assert the task is still incomplete before advancing across it; an immediate pos
This repository contains the .NET team's curated set of core skills and custom agents for coding agents. For information about the Agent Skills standard, see agentskills.io.
Repo: dotnet/skills
Run file-based C# apps with the .NET CLI when the user explicitly wants C#/.NET code without creating a project. Use for C# language/API experiments, one-file…
Correctly call native (C/C++) libraries from .NET using P/Invoke and LibraryImport. Covers function signatures, string marshalling, memory lifetime,…
Set up NuGet trusted publishing (OIDC) on a GitHub Actions repo — replaces long-lived API keys with short-lived tokens. USE FOR: trusted publishing, NuGet…
Design, implement, optimize, and review SIMD code in .NET. USE FOR: vectorizing scalar loops with TensorPrimitives, Vector64/128/256/512, or platform hardware…
Guides technology selection and implementation of AI and ML features in .NET 8+ applications using ML.NET, Microsoft.Extensions.AI (MEAI), Microsoft Agent…
Configure OpenTelemetry distributed tracing, metrics, and logging in ASP.NET Core using the .NET OpenTelemetry SDK. Use when adding observability, setting up…