ANcpLua.Roslyn.Utilities.Testing
1.53.0
dotnet add package ANcpLua.Roslyn.Utilities.Testing --version 1.53.0
NuGet\Install-Package ANcpLua.Roslyn.Utilities.Testing -Version 1.53.0
<PackageReference Include="ANcpLua.Roslyn.Utilities.Testing" Version="1.53.0" />
<PackageVersion Include="ANcpLua.Roslyn.Utilities.Testing" Version="1.53.0" />
<PackageReference Include="ANcpLua.Roslyn.Utilities.Testing" />
paket add ANcpLua.Roslyn.Utilities.Testing --version 1.53.0
#r "nuget: ANcpLua.Roslyn.Utilities.Testing, 1.53.0"
#:package ANcpLua.Roslyn.Utilities.Testing@1.53.0
#addin nuget:?package=ANcpLua.Roslyn.Utilities.Testing&version=1.53.0
#tool nuget:?package=ANcpLua.Roslyn.Utilities.Testing&version=1.53.0
ANcpLua.Roslyn.Utilities
A curated .NET framework utility library. Best-in-slot primitives harvested and refined from three ecosystems:
- Roslyn source generators & analyzers — the incremental generator shape that actually caches, the matching DSL that replaces stringly-typed symbol comparisons, code emission that isn't raw
StringBuilder. - Microsoft Agent Framework (MAF) — test doubles for
AIAgent/IChatClient, a provider-agnostic conformance suite, referenceIChatClientAgentFixtureimplementations for six LLM providers, workflow fixture with fluent assertions. - ModelContextProtocol — OTel semantic conventions (GenAI semconv 1.40), SSE client with reconnect, agent test infrastructure that plays with MCP's transport.
The library is the author's own. Use it, improve it (the upstream is this repo), or propose switching directions — don't reinvent locally.
Packages
| Package | Target | What it's for |
|---|---|---|
ANcpLua.Roslyn.Utilities |
netstandard2.0 | Runtime + Roslyn utilities as a normal NuGet reference (BCL + optional Roslyn layer) |
ANcpLua.Roslyn.Utilities.Sources |
source-only | Embeds the utilities as internal source into source generators (generators can't load NuGet DLLs at runtime) |
ANcpLua.Roslyn.Utilities.Polyfills |
source-only | init, required, Index/Range, nullable & trim attributes for netstandard2.0 |
ANcpLua.Roslyn.Utilities.Testing |
net10.0 | Generator/analyzer/codefix test infrastructure, MSBuild integration tests, cross-framework web testing (xUnit/NUnit/TUnit/Bunit), OTel instrumentation helpers |
ANcpLua.Roslyn.Utilities.Testing.AgentTesting |
net10.0 | MAF agent test doubles, scripted chat clients, MAF conformance suite, provider fixtures for OpenAI/Azure OpenAI/Anthropic/Ollama/Gemini/OpenRouter, AG-UI test server, BitNet integration |
ANcpLua.Roslyn.Utilities.Testing.Workflows |
net10.0 | Microsoft.Agents.AI.Workflows test infrastructure: WorkflowFixture<TInput> with fluent assertions, stateful agent test doubles, execution-environment parametric axis |
Quickstart
Writing a source generator
dotnet add package ANcpLua.Roslyn.Utilities.Sources
A canonical incremental generator is 25 lines when the utilities do their job — see src/ANcpLua.AotReflection/AotReflectionGenerator.cs in this repo for the reference shape:
[Generator]
public sealed class MyGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var flows = context.SyntaxProvider.ForAttributeWithMetadataName(
"MyNamespace.TracedAttribute",
static (node, _) => node is ClassDeclarationSyntax,
static (ctx, ct) => TypeExtractor.Extract(ctx, ct));
var types = flows.ReportAndStop(context);
var files = types
.Select(static (m, _) => OutputGenerator.Generate(m))
.CollectAsEquatableArray();
files.AddSources(context);
}
}
What the library provides at each step:
ForAttributeWithMetadataName— filter syntax before expensive semantic workDiagnosticFlow<T>— railway-oriented pipeline carrying value + accumulated diagnostics, value-equatable for incremental cachingReportAndStop— drain the flow intoReportDiagnosticand yield valuesCollectAsEquatableArray— value equality so the cache actually hitsAddSources— emitFileWithNamerecords without boilerplateMatch.Type()/Match.Method()— fluent symbol matching, no string comparisonsIndentedStringBuilder—BeginBlock()/EndBlock()scopes, no hardcoded indentation stringsGeneratedCodeHelpers—<auto-generated/>headers,#nullable enable, pragma helpers
Testing an agent
dotnet add package ANcpLua.Roslyn.Utilities.Testing.AgentTesting
// Scripted IChatClient double
var client = new FakeChatClient()
.WithText("Hello!")
.WithFunctionCall("get_weather", new { city = "Vienna" });
// Multi-turn agent double with session state
var agent = FakeReplayAgent.FromStrings(
TimeProvider.System, "First response", "Second response");
// Capture and assert OTel activities
using var collector = new ActivityCollector("my-source");
await agent.RunAsync(new ChatMessage(ChatRole.User, "hi"));
collector.FindSingle("my-agent.run")
.AssertStatus(ActivityStatusCode.Ok)
.AssertTag("gen_ai.request.model", "gpt-5.4-mini");
Running the provider-agnostic MAF conformance suite
One fixture implementation unlocks ~30 conformance tests against any
IChatClient-backed agent. Six reference implementations ship in the package:
// OpenAI
public sealed class MyOpenAITests()
: RunTests<OpenAIChatCompletionFixture>(() => new());
// Azure OpenAI
public sealed class MyAzureTests()
: RunTests<AzureOpenAIChatCompletionFixture>(() => new());
// Anthropic (Claude)
public sealed class MyAnthropicTests()
: RunTests<AnthropicChatCompletionFixture>(() => new());
// Ollama (local, free, no API key)
public sealed class MyOllamaTests()
: RunStreamingTests<OllamaChatCompletionFixture>(() => new());
// Google Gemini
public sealed class MyGeminiTests()
: ChatClientAgentRunTests<GoogleGeminiChatCompletionFixture>(() => new());
// OpenRouter (meta-provider, 100+ backing models)
public sealed class MyRouterTests()
: StructuredOutputRunTests<OpenRouterChatCompletionFixture>(() => new());
Wire credentials via testsettings.development.json, environment variables, or user secrets — see TestSettings for the key catalog.
Testing a MAF workflow
dotnet add package ANcpLua.Roslyn.Utilities.Testing.Workflows
public sealed class MyWorkflowTests(ITestOutputHelper output)
: WorkflowFixture<string>(output)
{
protected override Workflow BuildWorkflow() => SimpleSequentialSample.Build();
[Theory]
[InlineData(ExecutionEnvironment.InProcess_Lockstep)]
[InlineData(ExecutionEnvironment.InProcess_OffThread)]
public async Task UppercaseReverse_YieldsReversedShouted(ExecutionEnvironment env)
{
var run = await this.RunAsync("Hello, World!", env);
run.Should()
.YieldOutput<string>(s => s.Should().Be("!DLROW ,OLLEH"))
.And.HaveNoErrors()
.And.CompletedExecutors("UppercaseExecutor", "ReverseTextExecutor");
}
}
What's in the box
Layer 1 — Runtime utilities
Zero-allocation, BCL-only primitives. Consumable from any .NET project.
- Performance:
SpanTokenizer,AsciiHelpers,AsciiSet,IntegerParser,ValueStringBuilder,BitHelpers,MemoryHelpers - Data structures:
EquatableArray<T>,CircularBuffer<T>,Deduplicator<T>,ExpiringCache<TKey,TValue>,Result<T> - Async & streaming:
SseClient<T>(with reconnect),ParallelAsyncExtensions(channel-based),AsyncBatchingWorkQueue<T>,AsyncSequenceExtensions,CancellationSeries - Telemetry support:
TimeConversions(OTLP nanos),AssemblyVersionExtensions - Domain:
ErrorCategorizer(13 categories),ErrorFingerprinter(stable SHA256),StatisticalMath(entropy, KL divergence, RRF),DistributionComparer,SqlOperationParser(OTel db semconv),CursorCodec(opaque pagination),PagedResult<T>,DataReaderExtensions
Layer 2 — Roslyn utilities
Require Microsoft.CodeAnalysis. Used by generators and analyzers.
- Incremental pipeline:
DiagnosticFlow<T>,IncrementalValuesProviderExtensions,SyntaxValueProviderExtensions - Symbol matching:
SymbolMatch/InvocationMatchfluent DSL,SymbolExtensions,TypeSymbolExtensions,AttributeExtensions,OverloadFinder,SemanticGuard - Cached type contexts:
OTelContext,AspNetContext,AwaitableContext,DisposableContext,CollectionContext - Deprecated OTel detection:
DeprecatedOtelAttributes— 50+ attribute mappings synced to GenAI semconv 1.40 - Code emission:
IndentedStringBuilder,GeneratedCodeHelpers,FileWithName,ValueStringBuilder - Flow analysis:
DataFlowAnalyzer<T>— abstract forward dataflow overControlFlowGraphwith worklist + lattice operations - Misc:
MappingRegistry,CodeStylePreferences,DiagnosticAnalyzerBase,TypeCache<TEnum>,HashCombiner,Boxes
Layer 3 — Testing
Generator, analyzer, codefix, refactoring, MSBuild integration, and cross-framework web testing.
- Generator tests:
GeneratorTestEngine(fluent builder),GeneratorCachingReport(compares two runs, detects cache hits),GeneratorStepAnalyzer,ForbiddenTypeAnalyzer - Analyzer / CodeFix / Refactoring tests:
AnalyzerTest,CodeFixTest<TAnalyzer,TCodeFix>,CodeFixTestWithEditorConfig,RefactoringTest,SolutionRefactoringTest,LogAssert - MSBuild integration tests:
ProjectBuilder(fluent isolated temp project),PackageProjectBuilder(Default/ProjectElement/SdkElement import styles),NuGetPackageFixture(package pre-warming),BuildResult+ fluent assertions,DotNetSdkHelpers - Web testing (cross-framework — xUnit root +
NUnit/+TUnit/+Bunit/subfolders):IntegrationTestBase(fast in-memoryTestServer),KestrelTestBase(real Kestrel for HTTP/2 / WebSockets / SSE / Playwright),FakeLoggerExtensions,BunitTestBase - OTel instrumentation:
ActivityInstrumentation(semconv versions,ScopedActivity, GenAI helpers),MetricsInstrumentation,LoggingConventions(EventId ranges, 100+ LogTags),LogEnricherInfrastructure,DataClassificationHelpers(PII/Secret redaction) - Generator helpers:
GeneratorTestHelper<TGenerator>— assertion-oriented one-liners complementing the fluentGeneratorTestEngine
Layer 4 — Agent testing
MAF test infrastructure. Sibling of Workflows, focused on agents.
- Agents/ —
FakeAgentBase,FakeEchoAgent,FakeTextStreamingAgent,FakeMultiMessageAgent,FakeReplayAgent,FakeRoleCheckAgent,FakeDelegatingAgent - ChatClients/ —
FakeChatClient(fluent builder with call recording, scripted sequences, streaming, exception injection),ChatClientAgentTestHelper(multi-turn agent orchestration with history verification),MockChatClients(6 single-purpose variants),ChatMessageExtensions+AsyncEnumerableExtensions - Conformance/ — provider-agnostic MAF conformance suite
IAgentFixture/IChatClientAgentFixturecontracts,AgentTestBase<TFixture>RunTests,RunStreamingTests,ChatClientAgentRunTests,ChatClientAgentRunStreamingTests,StructuredOutputRunTestsMenuPlugin,CityInfo— function-calling and structured-output test payloads- Examples/ — six reference
IChatClientAgentFixtureimplementations:OpenAIChatCompletionFixture,AzureOpenAIChatCompletionFixture,AnthropicChatCompletionFixture,OllamaChatCompletionFixture,GoogleGeminiChatCompletionFixture,OpenRouterChatCompletionFixture, plusTestSettingsconfig key catalog
- Hosting/ —
AGUITestServer(in-memory AG-UI endpoint test server) - Http/ —
FakeHttpMessageHandler(URL pattern matching, SSE streams),SseResponseParser,RecordedRequest - Diagnostics/ —
ActivityCollector(FindSingle,AssertTag,AssertStatus,AssertHasEvent,AssertKind,AssertDuration) - Logging/ —
TestOutputAdapter(xUnit ↔ILoggerbridge with structured log capture),LogRecord - BitNet/ —
BitNetFixture,BitNetAttribute,BitNetTestGroup— integration tests against a real small model via llama.cpp
Layer 5 — Workflow testing
Microsoft.Agents.AI.Workflows test infrastructure. Harvested from microsoft/agent-framework.
- Fixtures/ —
WorkflowFixture<TInput>: derive, overrideBuildWorkflow(), assert via.Should().YieldOutput<T>().And.HaveNoErrors(). Handles execution-environment selection, in-memory checkpointing, and checkpoint resume out of the box. - Runtime/ —
ExecutionEnvironmentparametric[Theory]axis (InProcess_OffThread/InProcess_Lockstep/InProcess_Concurrent) - Agents/ — stateful workflow-oriented test doubles:
TestEchoAgent(session history + prefix echo),TestReplayAgent(fixed replay with duplicate-id validation),TestRequestAgent,RoleCheckAgent - Framework/ — declarative workflow integration-test harness:
TestcaseJSON schema,WorkflowHarness,WorkflowEvents
Some upstream pieces are parked in-tree but excluded from compile because they depend on types that are internal to Microsoft.Agents.AI.Workflows (only reachable inside the upstream repo via InternalsVisibleTo). They'll be enabled when MAF publishes a public testing-helpers package.
Layer 6 — Polyfills
Language and API backports for netstandard2.0 consumers.
| Polyfill | Enables | Opt-out |
|---|---|---|
Index / Range |
array[^1], array[1..3] |
InjectIndexRangeOnLegacy=false |
IsExternalInit |
record types, init setters |
InjectIsExternalInitOnLegacy=false |
| Nullable attributes | [NotNull], [MaybeNull], [MemberNotNull], [NotNullWhen] |
InjectNullabilityAttributesOnLegacy=false |
| Trim/AOT attributes | [RequiresUnreferencedCode], [DynamicallyAccessedMembers] |
InjectTrimAttributesOnLegacy=false |
TimeProvider |
Testable time abstraction | InjectTimeProviderPolyfill=false |
Lock |
System.Threading.Lock |
InjectLockPolyfill=false |
required, params collections, CallerArgumentExpression, UnreachableException, StackTraceHidden, ExperimentalAttribute |
C# 11–13 language features on ns2.0 | per-feature MSBuild props |
Disable all at once: <InjectAllPolyfillsOnLegacy>false</InjectAllPolyfillsOnLegacy>
Separate: AOT reflection generator
This repo also ships ANcpLua.Analyzers.AotReflection — an incremental source generator that replaces runtime typeof(T).GetProperties() with compile-time metadata, making types NativeAOT- and trim-safe. Mark a type [AotReflection] and a generated FooMetadata class appears with strongly-typed getter/setter/invoker delegates. Pair with ANcpLua.Roslyn.Utilities.Testing.Aot ([AotTest], [AotSafe], [TrimSafe], [TrimTest]) to verify the output actually survives PublishAot=true and PublishTrimmed=true.
Design principles
- Compile-time over runtime reflection.
EquatableArray<T>for generator caching,DiagnosticFlow<T>for pipeline error accumulation,IndentedStringBuilderfor emission — the shape of an incremental generator the compiler cache actually likes. - Span-first, allocation-last.
ValueStringBuilderfor hot-path strings,SpanTokenizerfor allocation-free parsing,Boxesfor cached boxed primitives,AsciiSetfor O(1) membership. - OTel semconv 1.40 native.
OTelContextresolves everyActivity/Meter/Counter/Histogram/TracerProvider/MeterProvidertype once.DeprecatedOtelAttributescatchesgen_ai.systemand 50+ other deprecated attribute names during analysis. - Test discipline.
FakeChatClientoverMoq<IChatClient>.GeneratorCachingReportover hand-rolled cache assertions.ForbiddenTypeAnalyzercatchesISymbol/Compilationsnuck into pipeline models.AgentTestBase<TFixture>plugs anyIChatClient-backed provider into a single conformance suite. - Source-only delivery for generators. The
.Sourcespackage rewrites the utilities tointernalvia a pack-time PowerShell transform (Transform-Sources.ps1), because source generators can't load NuGet DLLs at runtime.
Upstream harvest
The Testing.AgentTesting/ChatClients/{ChatClientAgentTestHelper,MockChatClients}, Testing.AgentTesting/Conformance/Examples/*, and most of Testing.Workflows/* originate from the microsoft/agent-framework test tree under the Microsoft License. They're intentionally kept close to upstream shape to ease re-sync when MAF publishes updates. Each harvest file carries a // Source: microsoft/agent-framework dotnet/tests — <filename> comment in its header.
Documentation
ancplua.mintlify.app/utilities — full API reference with examples.
Related
- ANcpLua.NET.Sdk — opinionated .NET SDK wrapper built on the same conventions
- ANcpLua.Analyzers — the author's analyzer catalogue, built on these utilities
License
MIT © Alexander Nachtmann
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- ANcpLua.Roslyn.Utilities (>= 1.53.0)
- AwesomeAssertions (>= 9.4.0)
- Basic.Reference.Assemblies.Net100 (>= 1.8.5)
- Basic.Reference.Assemblies.NetStandard20 (>= 1.8.5)
- bunit (>= 2.7.2)
- Meziantou.Framework (>= 5.0.15)
- Meziantou.Framework.FullPath (>= 1.1.18)
- Meziantou.Framework.TemporaryDirectory (>= 1.0.37)
- Meziantou.Framework.Threading (>= 2.0.4)
- Microsoft.AspNetCore.Mvc.Testing (>= 10.0.6)
- Microsoft.Bcl.AsyncInterfaces (>= 10.0.6)
- Microsoft.Bcl.HashCode (>= 6.0.0)
- Microsoft.CodeAnalysis.Analyzer.Testing (>= 1.1.3)
- Microsoft.CodeAnalysis.Analyzers (>= 5.3.0)
- Microsoft.CodeAnalysis.CSharp (>= 5.3.0)
- Microsoft.CodeAnalysis.CSharp.Analyzer.Testing (>= 1.1.3)
- Microsoft.CodeAnalysis.CSharp.CodeFix.Testing (>= 1.1.3)
- Microsoft.CodeAnalysis.CSharp.CodeRefactoring.Testing (>= 1.1.3)
- Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing (>= 1.1.3)
- Microsoft.CodeAnalysis.CSharp.Workspaces (>= 5.3.0)
- Microsoft.CodeAnalysis.Workspaces.Common (>= 5.3.0)
- Microsoft.Deployment.DotNet.Releases (>= 1.0.1)
- Microsoft.Extensions.AI.Abstractions (>= 10.5.0)
- Microsoft.Extensions.Diagnostics.Testing (>= 10.5.0)
- Microsoft.Extensions.Telemetry.Abstractions (>= 10.5.0)
- MSBuild.StructuredLogger (>= 2.3.154)
- NUnit (>= 4.5.1)
- OpenAI (>= 2.10.0)
- TUnit.Core (>= 1.34.5)
- xunit.v3.assert (>= 3.2.2)
- xunit.v3.extensibility.core (>= 3.2.2)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.53.0 | 0 | 4/18/2026 |
| 1.52.1 | 0 | 4/18/2026 |
| 1.52.0 | 132 | 4/15/2026 |
| 1.51.1 | 130 | 4/12/2026 |
| 1.51.0 | 251 | 4/3/2026 |
| 1.50.0 | 98 | 4/3/2026 |
| 1.49.0 | 98 | 4/2/2026 |
| 1.48.0 | 209 | 3/20/2026 |
| 1.47.0 | 205 | 3/12/2026 |
| 1.45.0 | 378 | 3/10/2026 |
| 1.43.0 | 249 | 2/28/2026 |
| 1.42.0 | 225 | 2/28/2026 |
| 1.41.0 | 105 | 2/28/2026 |
| 1.40.0 | 212 | 2/15/2026 |
| 1.39.0 | 144 | 2/14/2026 |
| 1.38.2 | 193 | 2/14/2026 |
| 1.38.1 | 105 | 2/14/2026 |
| 1.38.0 | 91 | 2/14/2026 |
| 1.37.1 | 92 | 2/14/2026 |
| 1.37.0 | 99 | 2/14/2026 |