ZCrew.Extensions.CodeAnalysis.CSharp.Testing 1.0.0-preview.6

This is a prerelease version of ZCrew.Extensions.CodeAnalysis.CSharp.Testing.
There is a newer prerelease version of this package available.
See the version list below for details.
dotnet add package ZCrew.Extensions.CodeAnalysis.CSharp.Testing --version 1.0.0-preview.6
                    
NuGet\Install-Package ZCrew.Extensions.CodeAnalysis.CSharp.Testing -Version 1.0.0-preview.6
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ZCrew.Extensions.CodeAnalysis.CSharp.Testing" Version="1.0.0-preview.6" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ZCrew.Extensions.CodeAnalysis.CSharp.Testing" Version="1.0.0-preview.6" />
                    
Directory.Packages.props
<PackageReference Include="ZCrew.Extensions.CodeAnalysis.CSharp.Testing" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ZCrew.Extensions.CodeAnalysis.CSharp.Testing --version 1.0.0-preview.6
                    
#r "nuget: ZCrew.Extensions.CodeAnalysis.CSharp.Testing, 1.0.0-preview.6"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ZCrew.Extensions.CodeAnalysis.CSharp.Testing@1.0.0-preview.6
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ZCrew.Extensions.CodeAnalysis.CSharp.Testing&version=1.0.0-preview.6&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=ZCrew.Extensions.CodeAnalysis.CSharp.Testing&version=1.0.0-preview.6&prerelease
                    
Install as a Cake Tool

ZCrew.Extensions.CodeAnalysis.CSharp.Testing

Testing library for verifying Roslyn source generators. It drives a generator through Roslyn's CSharpSourceGeneratorTest harness from a small JSON descriptor, so each test case is just a set of input and expected-output files plus a .json that ties them together.

Installation

Available on NuGet for .NET Standard 2.0:

<PackageReference Include="ZCrew.Extensions.CodeAnalysis.CSharp.Testing" />

Writing a test case

A test case is three kinds of file in a TestCases/ folder next to your test class:

  • Input sources (e.g. MyCase.Attribute.cs) compiled as input to the generator.
  • Expected generated files (e.g. MyCase.SourceText.g.cs) the output to verify against.
  • A JSON descriptor (MyCase.json) maps the inputs, expected outputs, and any expected diagnostics:
{
    "SourceFiles": [
        { "SourceFileName": "MyCase.Attribute.cs" }
    ],
    "GeneratedFiles": [
        {
            "SourceFileName": "MyCase.SourceText.g.cs",
            "GeneratedFileName": "MyNamespace.MyTypeSourceText.g.cs"
        }
    ]
}

SourceFileName is the file on disk; GeneratedFileName is the hint name your generator passes to context.AddSource(hintName, ...).

Expecting diagnostics

Declare expected diagnostics where they occur:

  • On a source file or generated file entry, an ExpectedDiagnostics array asserts diagnostics located in that file. Give each a location by Snippet (the start of its single occurrence in that file) or by an explicit 1-based Line/Column.
  • At the top level, an ExpectedDiagnostics array asserts diagnostics with no location (Location.None) — for example CS5001 or a compilation-level analyzer diagnostic.

Each entry has an Id, an optional Severity (defaults to Error), and an optional Message to match exactly.

{
    "SourceFiles": [
        {
            "SourceFileName": "MyCase.Attribute.cs",
            "ExpectedDiagnostics": [
                { "Id": "CS0246", "Snippet": "CreateService<T>(" },
                { "Id": "CS0246", "Line": 10, "Column": 17 }
            ]
        }
    ],
    "GeneratedFiles": [
        {
            "SourceFileName": "MyCase.SourceText.g.cs",
            "GeneratedFileName": "MyNamespace.MyTypeSourceText.g.cs",
            "ExpectedDiagnostics": [
                { "Id": "CS0219", "Severity": "Warning", "Snippet": "unused" }
            ]
        }
    ],
    "ExpectedDiagnostics": [
        { "Id": "CS5001" }
    ]
}

Only the diagnostic's start is asserted, so the reported span may extend past the located snippet. A snippet that is missing or appears more than once in its file fails the test with a helpful message — use a more specific snippet or an explicit Line/Column.

Wiring the test

Configure a shared baseline once, then load and run each case. Resolve the TestCases folder from the source tree with TestPath.ForCaller() so fixtures are checked into git:

private static readonly SourceGeneratorTestBuilder<MyGenerator, DefaultVerifier> Baseline =
    SourceGeneratorTestBuilder<MyGenerator>
        .CreateDefaultBuilder()
        .WithReferenceAssemblies(ReferenceAssemblies.Net.Net100)
        .WithGeneratorPostInitializationSources();

private static readonly TestPath testCases = TestPath.ForCaller() / "TestCases";

[Theory]
[InlineData("MyCase.json")]
public async Task Generates_expected_sources(string descriptor)
{
    var testCase = await JsonTestCase.FromJsonFileAsync(testCases / descriptor);
    var test = await Baseline.BuildAsync(testCase);
    await test.RunAsync();
}

The builder is immutable (every With* call forks a new builder) so a fully configured baseline can be shared as a fixture and specialized per test without affecting other tests.

Project setup

Keep fixture files out of the compilation and out of the build output. Because the test resolves them from the source tree via TestPath.ForCaller(), they do not need to be copied to bin:

<ItemGroup>
  
  <Compile Remove="**/TestCases/**/*.cs" />
  
  <None Include="**/TestCases/**/*.json" Exclude="bin/**/*.json" />
  <None Include="**/TestCases/**/*.cs" Exclude="bin/**/*.cs" />
</ItemGroup>

Updating expected files in place

Hand-writing and maintaining .g.cs files is tedious and I hate it, you should too. Add WithExpectedSourceUpdates() to the baseline and, whenever the generator's output differs from (or is missing) an expected file, the test overwrites it on disk with the produced output and still fails:

.WithExpectedSourceUpdates(enabled: Environment.GetEnvironmentVariable("CI") is null)

Workflow:

  1. Change your generator, or add a new test case whose .g.cs files do not exist yet.
  2. Run the tests. Mismatched and missing expected files are rewritten in place and the run is red.
  3. Review the changes in source control
  4. Keep them (re-run → green) or revert them.

The tests compare the output to previous file contents, so this won't cause false-positives. This does mean that when you get a failure and you've fixed it: the next test will fail (the previous file contents were broken and the new ones are fixed), and so running the tests again will then pass.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  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. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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.0.0-preview.8 87 8/1/2026
1.0.0-preview.6 75 7/5/2026
1.0.0-preview.5 70 7/5/2026
1.0.0-preview.4 65 6/16/2026
1.0.0-preview.3 64 6/12/2026