mcpbeat Sign in

Migrate Static To Wrapper Agent Skill

> Mechanically replace static dependency call sites with wrapper or built-in abstraction calls across a bounded scope (file, project, or namespace). Performs codemod-style bulk replacement of DateTime.UtcNow to TimeProvider.GetUtcNow(), File.ReadAllText to IFileSystem, and similar transformations. Adds constructor injection parameters and updates DI registration. TimeProvider, migrate static calls to wrapper, bulk replace File.* with IFileSystem, codemod static to injectable, add constructor injection for time provider, mechanical migration of statics, refactor DateTime to TimeProvider, swap static for injected dependency, convert static calls to use abstraction, replace statics in a class, migrate one file to TimeProvider, scoped migration, update call sites. wrappers (use generate-testability-wrappers), migrating between test frameworks.

2k tokens
context cost
the whole folder, loaded on every use
1
files
instructions only
0
copies elsewhere
how many repositories repackaged it
1034
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/microsoft/testfx --skill migrate-static-to-wrapper

The instruction itself

16 sections, as written by the author

Migrate Static to Wrapper

Perform mechanical, codemod-style replacement of static dependency call sites with calls to injected wrapper interfaces or built-in abstractions. Operates on a bounded scope (single file, project, or namespace) so migrations can be done incrementally.

When to Use

  • After wrappers have been generated (via generate-testability-wrappers) or built-in abstractions identified
  • Migrating DateTime.UtcNowTimeProvider.GetUtcNow() across a project
  • Migrating File.*IFileSystem.File.* across a namespace
  • Adding constructor injection for the new abstraction to affected classes
  • Incremental migration: one project or namespace at a time

When Not to Use

  • No wrapper or abstraction exists yet (use generate-testability-wrappers first)
  • The user wants to detect statics, not migrate them (use detect-static-dependencies)
  • The code does not use dependency injection and the user hasn't chosen ambient context
  • Migrating between test frameworks (use the appropriate migration skill)

Inputs

| Input | Required | Description |

|-------|----------|-------------|

| Static pattern | Yes | What to replace (e.g., DateTime.UtcNow, File.ReadAllText) |

| Replacement abstraction | Yes | What to use instead (e.g., TimeProvider, IFileSystem) |

| Scope | Yes | File path, project (.csproj), namespace, or directory to migrate |

| Injection strategy | No | constructor (default), primary-constructor, or ambient |

Workflow

Step 1: Verify prerequisites

Before modifying any code:

  • Confirm the wrapper/abstraction exists: Check that the interface or built-in abstraction is available in the project. For TimeProvider, verify the target framework is .NET 8+ or Microsoft.Bcl.TimeProvider is referenced. For System.IO.Abstractions, verify the NuGet package is referenced.
  • Confirm DI registration exists: Check Program.cs or Startup.cs for the service registration. If missing, add it before proceeding.
  • Identify all files in scope: List the .cs files that will be modified. Exclude test projects, obj/, bin/, and generated code.

Step 2: Plan the migration for each file

For each file containing the static pattern, determine:

  • Which class(es) contain the call sites — identify the class declarations
  • Whether the class already has the dependency injected — check constructors for existing TimeProvider, IFileSystem, etc. parameters
  • The replacement expression for each call site
Replacement mapping

| Category | Original | DI replacement |

|----------|----------|----------------|

| Time | DateTime.Now | _timeProvider.GetLocalNow().DateTime |

| Time | DateTime.UtcNow | _timeProvider.GetUtcNow().DateTime |

| Time | DateTime.Today | _timeProvider.GetLocalNow().Date |

| Time | DateTimeOffset.UtcNow | _timeProvider.GetUtcNow() |

| File | File.ReadAllText(path) | _fileSystem.File.ReadAllText(path) |

| File | File.WriteAllText(path, text) | _fileSystem.File.WriteAllText(path, text) |

| File | File.Exists(path) | _fileSystem.File.Exists(path) |

| File | Directory.Exists(path) | _fileSystem.Directory.Exists(path) |

| Env | Environment.GetEnvironmentVariable(name) | _env.GetEnvironmentVariable(name) |

| Console | Console.WriteLine(msg) | _console.WriteLine(msg) |

| Process | Process.Start(info) | _processRunner.Start(info) |

Apply the same pattern for other members in each category.

Step 3: Add constructor injection

Add the new dependency following the class's existing pattern:

  • Primary constructor (C# 12+): Add parameter to primary constructor: public class OrderProcessor(ILogger<OrderProcessor> logger, TimeProvider timeProvider)
  • Traditional constructor: Add private readonly field + constructor parameter, matching the existing field naming convention (_camelCase or m_camelCase)

Step 4: Replace call sites

Perform each replacement mechanically. For each call site:

  • Replace the static call with the wrapper call
  • Preserve the surrounding code structure (whitespace, comments, chaining)
  • Add required using directives if not already present
Adding using directives

| Abstraction | Using directive |

|------------|-----------------|

| TimeProvider | None (in System namespace) |

| IFileSystem | using System.IO.Abstractions; |

| IHttpClientFactory | using System.Net.Http; (usually already present) |

| Custom wrappers | using <wrapper namespace>; |

Step 5: Update affected test files

If test files exist for the migrated classes:

  • Update constructor calls — add the new parameter to test class instantiation
  • Use test doubles:
  • TimeProvidernew FakeTimeProvider() from Microsoft.Extensions.TimeProvider.Testing
  • IFileSystemnew MockFileSystem() from System.IO.Abstractions.TestingHelpers
  • Custom wrappers → new Mock<IWrapperName>() or hand-rolled fake

Step 6: Build verification

After all changes in the current scope:

dotnet build <project.csproj>

If the build fails:

  • Missing using: Add the required using directive
  • Missing NuGet package: Run dotnet add package <name>
  • Constructor mismatch in tests: Update test instantiation (Step 5)
  • Ambiguous call: Fully qualify the wrapper call

Step 7: Report changes

Summarize what was done:

## Migration Summary

**Pattern**: DateTime.UtcNow → TimeProvider.GetUtcNow()
**Scope**: MyProject/Services/

### Files Modified (production)
| File | Call Sites Replaced | Injection Added |
|------|--------------------:|:----------------|
| OrderProcessor.cs | 3 | Yes (constructor) |
| NotificationService.cs | 1 | Yes (primary ctor) |

### Files Modified (tests)
| File | Change |
|------|--------|
| OrderProcessorTests.cs | Added FakeTimeProvider parameter |

### Remaining (out of scope)
- MyProject/Legacy/ — 8 call sites not migrated (different namespace)

Validation

  • [ ] All call sites in scope were replaced (none missed)
  • [ ] Constructor injection added to all affected classes
  • [ ] Field naming follows existing class conventions
  • [ ] Required using directives added
  • [ ] Required NuGet packages referenced
  • [ ] Build succeeds after migration
  • [ ] Test files updated with appropriate test doubles
  • [ ] No behavioral changes introduced (wrapper delegates directly to the static)

Common Pitfalls

| Pitfall | Solution |

|---------|----------|

| Replacing statics in test code | Only replace in production code; tests should use fakes/mocks |

| Breaking static classes | Static classes can't have constructors — use ambient context for these |

| Missing FakeTimeProvider NuGet | Add Microsoft.Extensions.TimeProvider.Testing to test project |

| Replacing in expression-bodied members without updating return type | DateTimeDateTimeOffset when using TimeProvider.GetUtcNow() — verify type compatibility |

| Migrating too much at once | Stick to the defined scope — one project or namespace per run |

| Forgetting DI registration | Always verify Program.cs/Startup.cs has the registration before replacing call sites |

Other skills for the same job

different authors, same section of the catalogue
MCP Builder
by anthropics
vendor ×13

Guide for creating high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK).

30k tokens scripts
Changelog Generator
by frostant
×9

Automatically creates user-facing changelogs from git commits by analyzing commit history, categorizing changes, and transforming technical commits into clear, customer-friendly release notes. Turns hours of manual changelog writing into minutes of automated generation.

774 tokens
Finishing A Development Branch
by ZhanlinCui
×7

Use when implementation is complete, all tests pass, and you need to decide how to integrate the work - guides completion of development work by presenting structured options for merge, PR, or cleanup

1k tokens
MCP Builder
by JayZeeDesign
×7

Guide for creating high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK).

37k tokens scripts
Vercel React Native Skills
by vercel-labs
vendor ×6

React Native and Expo best practices for building performant mobile apps. Use when building React Native components, optimizing list performance, implementing animations, or working with native modules. Triggers on tasks involving React Native, Expo, mobile performance, or native platform APIs.

39k tokens
Vercel React Best Practices
by ratacat
×5

React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.

34k tokens
Next Best Practices
by vercel-labs
vendor ×4

Next.js best practices - file conventions, RSC boundaries, data patterns, async APIs, metadata, error handling, route handlers, image/font optimization, bundling

20k tokens
Using Git Worktrees
by ZhanlinCui
×4

Use when starting feature work that needs isolation from current workspace or before executing implementation plans - creates isolated git worktrees with smart directory selection and safety verification

1k tokens

How to use it

Copy the folder

Take microsoft/migrate-static-to-wrapper from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.