Thunder.DocSnippets
0.1.3
dotnet add package Thunder.DocSnippets --version 0.1.3
NuGet\Install-Package Thunder.DocSnippets -Version 0.1.3
<PackageReference Include="Thunder.DocSnippets" Version="0.1.3" />
<PackageVersion Include="Thunder.DocSnippets" Version="0.1.3" />
<PackageReference Include="Thunder.DocSnippets" />
paket add Thunder.DocSnippets --version 0.1.3
#r "nuget: Thunder.DocSnippets, 0.1.3"
#:package Thunder.DocSnippets@0.1.3
#addin nuget:?package=Thunder.DocSnippets&version=0.1.3
#tool nuget:?package=Thunder.DocSnippets&version=0.1.3
DocSnippets
Make your C# XML doc <code> examples runnable as unit tests — the Rust doctest experience for .NET.
DocSnippets is a Roslyn source generator. Add the package, and every <code> block in your XML documentation becomes a compiled, executable NUnit/xUnit/MSTest test method. No extra tooling, no checked-in generated files.
<PackageReference Include="Thunder.DocSnippets" Version="..." />
Quick start
Add DocSnippets to your test project:
<PackageReference Include="Thunder.DocSnippets" Version="..." />Run
dotnet test. Done.
DocSnippets ships an MSBuild .targets file that automatically wires up the adjacent source project's .cs files as AdditionalFiles — no manual <ItemGroup> configuration required.
Writing snippets
Any <code> block in an XML doc comment is picked up automatically:
/// <summary>Adds two integers.</summary>
/// <example>
/// <code>
/// var result = calculator.Add(1, 2); // => 3
/// </code>
/// </example>
public int Add(int a, int b) => a + b;
The assertion comment is transformed into a framework-appropriate equality check at generation time. No assertion library is required in the snippet itself.
Inline assertion patterns
All four comment styles work on both declaration lines and expression lines:
| Pattern | Example | Meaning |
|---|---|---|
// => VALUE |
var x = f(); // => 42 |
Assert x equals 42 |
// result: VALUE |
var x = f(); // result: 42 |
Assert x equals 42 |
// VARNAME: VALUE |
DoSetup(); // myVar: 42 |
Assert myVar equals 42 |
// VALUE (bare literal) |
var x = f(); // 42 |
Assert x equals 42 |
On a declaration line (var x = f(); // => 3), the generator splits the line into the declaration statement and a separate assertion using the declared variable name. On an expression line (f(); // => 3), the entire expression becomes the assertion subject.
Bare literal comments (// 42, // true, // "hello") are only treated as assertions when the comment contains an unambiguous C# literal. Non-literal comments (// sum of values, // see above) are left unchanged.
Excluding a snippet
Add // doctest-ignore on the first line of any <code> block to skip it:
/// <code>
/// // doctest-ignore
/// // This example is illustrative — not executable.
/// var x = SomeExternalCall();
/// </code>
Compile-only snippets
Some examples are valid documentation but not self-contained — they reference live objects (GraphicsDevice, SpriteBatch, etc.) that can't be instantiated in a test without boilerplate that would pollute the rendered docs. Mark these with // doctest-compile-only:
/// <code>
/// // doctest-compile-only
/// spriteBatch.Begin();
/// spriteBatch.Draw(texture, position, Color.White);
/// spriteBatch.End();
/// </code>
The generated test is compiled (so rename refactors and API breakages are caught) but skipped at runtime. DocSnippets automatically stubs any undeclared identifiers (spriteBatch, texture, position) by looking them up in the project's symbol table — no manual stub declarations needed. The skip attribute varies by framework:
| Framework | Attribute |
|---|---|
| NUnit | [Test, Ignore("compile-only")] |
| xUnit | [Fact(Skip = "compile-only")] |
| MSTest | [TestMethod, Ignore] |
Assertion comments (// => VALUE) are not transformed in compile-only snippets — they are emitted verbatim as comments.
Configuration (docsnippets.json)
Add a docsnippets.json file alongside the source files (it is picked up automatically as an AdditionalFile by the shipped MSBuild targets) to configure the generator:
{
"snippetMode": "opt-out",
"assertionStyle": "NUnit",
"implicitUsings": ["MyLib", "MyLib.Models"]
}
| Key | Values | Default | Description |
|---|---|---|---|
snippetMode |
"opt-out", "opt-in" |
"opt-out" |
opt-out: all <code> blocks run. opt-in: only blocks containing // doctest run. |
assertionStyle |
"NUnit", "XUnit", "MSTest" |
(auto-detect) | Override the auto-detected test framework. |
implicitUsings |
Array of namespace strings | [] |
Namespaces added as using to every generated test class. |
Opt-in mode
Mark individual snippets with // doctest to include them when snippetMode is "opt-in":
/// <code>
/// // doctest
/// var x = Multiply(3, 4); // => 12
/// </code>
InternalsVisibleTo
If your snippets reference internal types, add this to your source project:
[assembly: InternalsVisibleTo("YourTestProject")]
Without it, snippets referencing internal members produce CS0122 errors that can be hard to diagnose.
Known limitations
- Tuple deconstruction —
var (a, b) = f(); // => ...is not supported. Use a separate assertion line. - Async snippets — snippets containing
awaitare not supported. The emitted test method is synchronous;awaitwill produce a compile error. - Single-assembly scanning — only direct
ProjectReferencesource projects are scanned. Transitive references are not.
What's new in v0.1.2
// doctest-compile-only— compile-checked-but-skipped snippets with automatic stub inference for undeclared identifiers
What's new in v0.1.1
- Approximate float assertions —
// => ~3.14(one decimal place tolerance),// => ~3.14 (2dp)for explicit precision - Compile-only snippets — see above
What's in v0.1.0
- Inline assertion patterns — four comment styles on both declaration and expression lines:
// => VALUE,// result: VALUE,// VARNAME: VALUE, bare literal// 42 #linediagnostics — build errors in generated test methods now point to the original source line, not the generated fileassertionStyleconfig override — override auto-detected framework viadocsnippets.json//=>arrow alias —//=>accepted as shorthand for// =>- Assert value in test method name —
Add_ShouldBe_3naming from// =>assertions - Overload disambiguation — param-type suffix on overloaded method test names
- Operator and destructor name sanitization — valid C# identifiers for
operator +,~MyClass, etc. snippetMode: opt-in— only run explicitly marked snippets- MSBuild auto-wiring —
AdditionalFilesglob injected via shipped.targetsfile
Learn more about Target Frameworks and .NET Standard.
-
.NETStandard 2.0
- No dependencies.
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 |
|---|---|---|
| 0.1.3 | 99 | 4/30/2026 |
| 0.1.2 | 87 | 4/30/2026 |
| 0.1.1 | 104 | 4/28/2026 |
| 0.1.1-preview9 | 109 | 4/27/2026 |
| 0.1.1-preview8 | 97 | 4/27/2026 |
| 0.1.0 | 99 | 4/26/2026 |
| 0.1.0-preview7.1 | 57 | 4/26/2026 |
| 0.1.0-preview7 | 94 | 4/26/2026 |
| 0.1.0-preview6 | 92 | 4/25/2026 |