testability-obstacle

Introduce minimal production seams to enable deterministic C# tests for ambient dependencies.

5.3k|403|Updated Feb 3, 2026
One-click install
npx skills add https://github.com/dotnet/skills --skill testability-obstacle
Or copy as Structured Prompt for Agent
Please help me install this Agent Skill.
Skill: testability-obstacle
Source: https://github.com/dotnet/skills/tree/main/plugins/dotnet-test/skills/testability-obstacle
Command: npx skills add https://github.com/dotnet/skills --skill testability-obstacle

SYSTEM DOCUMENTATION & REQUIREMENTS

What problem does it solve?

Testing C# code that depends on ambient resources like DateTime, Task.Delay, the filesystem, environment variables, or randomness is impossible without modifying production code. This Skill introduces the smallest behavior-preserving seam (constructor injection, TimeProvider, or scoped AsyncLocal overrides) so deterministic tests can be written without redesigning adjacent code.

Core Features & Use Cases

  • Seam Selection Guidance: Chooses the narrowest safe seam per dependency type, such as TimeProvider for time, injected delegates for single file operations, or minimal interfaces for environment and process access.
  • Static API Preservation: Provides a scoped AsyncLocal<T> override pattern for public static APIs that must retain their shape, with nested restoration and async-flow isolation guarantees.
  • Deterministic Test Authoring: Writes tests using FakeTimeProvider, in-memory fakes, and controlled dependencies with no real I/O, wall-clock waits, or environment mutation.
  • Use Case: A method calls DateTime.UtcNow and File.WriteAllText, making it untestable. The Skill injects TimeProvider and a file-write delegate with production defaults, then adds tests that advance fake time and assert against an in-memory fake.

Quick Start

Ask the agent to make a specific C# method testable by introducing the smallest production seam and writing deterministic tests for it.

Frequently Asked Questions about testability-obstacle

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I test C# code that uses DateTime.Now or DateTime.UtcNow?

Inject TimeProvider into the class and replace DateTime.UtcNow with timeProvider.GetUtcNow().UtcDateTime, preserving DateTime.Kind. In tests, use FakeTimeProvider to advance time deterministically instead of waiting on the wall clock.

How to unit test a static C# method without changing its public API?

Use a scoped AsyncLocal<T> override that returns IDisposable and restores the previous value on dispose, supporting nested scopes. The override flows across await calls and defaults to the real production dependency, keeping tests parallel-safe.

What is the best way to replace Task.Delay in unit tests?

Use the built-in overload Task.Delay(delay, timeProvider, token) with an injected TimeProvider rather than creating an IDelay wrapper. Tests start the operation, assert it is incomplete, advance FakeTimeProvider, then await completion.

When should I not add a testability seam to production code?

Skip the seam when the dependency is already injected or passed as an argument, since a fake can be supplied directly. Also avoid it for repository-wide audits or bulk migrations, which belong to dedicated detection or migration workflows.

Can I use temp files to test filesystem-dependent C# code?

No, tests should use an in-memory fake or an injected delegate such as Action<string, string> with a real default. Real filesystem access makes tests non-deterministic and violates the no-real-I/O requirement.