Generate wrapper interfaces and DI registration for hard-to-test static dependencies in C#, when the abstraction does NOT exist yet. Produces IFileSystem, IEnvironmentProvider, IConsole, IProcessRunner wrappers, or guides first-time adoption of TimeProvider and IHttpClientFactory and registering them in DI. USE FOR: generate wrapper for static, create IFileSystem wrapper, wrap DateTime.Now, make static testable, make class testable, create abstraction for File.*, generate DI registration, set up/adopt TimeProvider when it is not registered yet, IHttpClientFactory setup, testability wrapper, create the right abstraction to mock, what abstraction for Environment, how to make statics injectable, adopt System.IO.Abstractions. DO NOT USE FOR: detecting statics (use detect-static-dependencies), migrating call sites or replacing existing DateTime.*/File.* usages once the wrapper is created or already registered in DI (use migrate-static-to-wrapper), general interface design.
Generate wrapper interfaces and DI registration for hard-to-test static dependencies in C#, when the abstraction does NOT exist yet. Produces IFileSystem, IEnvironmentProvider, IConsole, IProcessRunner wrappers, or guides first-time adoption of TimeProvider and IHttpClientFactory and registering them in DI. USE FOR: generate wrapper for static, create IFileSystem wrapper, wrap DateTime.Now, make static testable, make class testable, create abstraction for File.*, generate DI registration, set up/adopt TimeProvider when it is not registered yet, IHttpClientFactory setup, testability wrapper, create the right abstraction to mock, what abstraction for Environment, how to make statics injectable, adopt System.IO.Abstractions. DO NOT USE FOR: detecting statics (use detect-static-dependencies), migrating call sites or replacing existing DateTime.*/File.* usages once the wrapper is created or already registered in DI (use migrate-static-to-wrapper), general interface design.
license
MIT
Generate Testability Wrappers
Generate wrapper interfaces, default implementations, and DI service registration code for untestable static dependencies. For statics that already have .NET built-in abstractions (TimeProvider, IHttpClientFactory), guide adoption of the built-in. For statics without built-in alternatives, generate custom minimal wrappers.
When to Use
After running detect-static-dependencies and identifying which statics to wrap
When the user asks to make a class testable by replacing statics with injected abstractions
When adopting TimeProvider (.NET 8+) or System.IO.Abstractions
When creating a custom wrapper for Environment.*, , or
Console.*
Process.*
When Not to Use
The user wants to find statics first (use detect-static-dependencies)
The user wants to bulk-replace call sites (use migrate-static-to-wrapper)
The static is already behind an interface
The project does not use dependency injection and the user does not want to add it
Inputs
Input
Required
Description
Static category
Yes
Which category: time, filesystem, environment, network, console, process
Target framework
Yes
The TargetFramework from .csproj (affects which built-in abstractions exist)
DI container
No
Which DI framework: microsoft (default), autofac, none (ambient context)
// Requires Microsoft.Extensions.TimeProvider.Testing NuGetvar fakeTime = new FakeTimeProvider(new DateTimeOffset(2026, 1, 15, 0, 0, 0, TimeSpan.Zero));
var processor = new OrderProcessor(fakeTime);
fakeTime.Advance(TimeSpan.FromDays(1));
Assert.True(processor.IsExpired(order));
TimeProvider (pre-.NET 8)
Guide: install Microsoft.Bcl.TimeProvider NuGet. Same API as above.
IHttpClientFactory
No wrapper code needed — register typed clients via builder.Services.AddHttpClient<MyService>() and inject HttpClient directly into the class constructor.
var mockFs = new MockFileSystem(new Dictionary<string, MockFileData>
{
{ "/config.json", new MockFileData("{\"key\": \"value\"}") }
});
var loader = new ConfigLoader(mockFs);
Assert.Equal("{\"key\": \"value\"}", loader.LoadConfig("/config.json"));
Step 5: Generate ambient context alternative (when DI is not available)
If the codebase does not use DI (e.g., old console app, library code), offer the ambient context pattern:
Key trade-offs: AsyncLocal<T> ensures parallel tests don't interfere; production cost is one null check per call; the static readonly field is essentially free.
Step 6: Place generated files
Generate files following the project's existing conventions:
If there is an Abstractions/ or Interfaces/ folder, place the interface there
If there is an Infrastructure/ or Services/ folder, place the implementation there
Otherwise, create files next to the code that uses the static
Always generate:
The interface file (or adoption instructions for built-in abstractions)
The default implementation file
The DI registration snippet (as a code comment at the bottom of the implementation, or as separate instructions)
Validation
Generated interface only wraps statics that were actually detected (not speculative)
Default implementation delegates to the real static with no behavior changes
DI registration uses AddSingleton for stateless wrappers, AddTransient for stateful ones
NuGet packages are recommended where established libraries exist (System.IO.Abstractions, etc.)
For .NET 8+, TimeProvider is recommended over custom ISystemClock
Ambient context pattern includes AsyncLocal<T>, scoped disposal, and trade-off explanation