Meziantou.Framework.SnapshotTesting
3.1.7
Prefix Reserved
See the version list below for details.
dotnet add package Meziantou.Framework.SnapshotTesting --version 3.1.7
NuGet\Install-Package Meziantou.Framework.SnapshotTesting -Version 3.1.7
<PackageReference Include="Meziantou.Framework.SnapshotTesting" Version="3.1.7" />
<PackageVersion Include="Meziantou.Framework.SnapshotTesting" Version="3.1.7" />
<PackageReference Include="Meziantou.Framework.SnapshotTesting" />
paket add Meziantou.Framework.SnapshotTesting --version 3.1.7
#r "nuget: Meziantou.Framework.SnapshotTesting, 3.1.7"
#:package Meziantou.Framework.SnapshotTesting@3.1.7
#addin nuget:?package=Meziantou.Framework.SnapshotTesting&version=3.1.7
#tool nuget:?package=Meziantou.Framework.SnapshotTesting&version=3.1.7
Meziantou.Framework.SnapshotTesting
Meziantou.Framework.SnapshotTesting validates serialized values against snapshot files stored on disk.
Basic usage
public sealed class SampleTests
{
[Fact]
public void ValidateUser()
{
var value = new { Name = "John", Age = 42 };
Snapshot.Validate(value);
}
}
For typed snapshots:
Snapshot.Validate(imageBytes, SnapshotType.Png);
Snapshot.Validate(svgText, SnapshotType.Svg);
For GIF/ICO frame snapshots (opt-in, emitted as PNG snapshots):
var settings = SnapshotSettings.Default with { };
settings.Serializers.AddGifSerializer();
settings.Serializers.AddIcoSerializer();
Snapshot.Validate(gifBytes, SnapshotType.Gif, settings);
Snapshot.Validate(icoBytes, SnapshotType.Ico, settings);
File naming convention
Snapshots are stored in a __snapshots__ directory next to the test source file:
- expected snapshots:
*.verified.<extension> - mismatch output:
*.actual.<extension>
Example:
__snapshots__/SampleTests_ValidateUser.verified.txt__snapshots__/SampleTests_ValidateUser.actual.txt
Notes:
- By default, snapshot names include class name and test name to avoid collisions across test classes.
.actualfiles are always written when a snapshot does not match.- If a single assertion serializes multiple files, an index suffix (
_0,_1, ...) is appended. - If names are too long, already end with
.verified/.actual, or contain characters that are not valid in a file name, a stable hash is added. Removing those characters would let two test names -Case_a/bandCase_a?b, say - claim the same snapshot file, and the hash keeps them apart. The hash does not depend on where the repository is checked out.
Storing snapshots in git
Snapshots are often binary: PNG frames from the GIF/ICO serializers, whatever the ImageSharp and
SkiaSharp backends emit, and .bin for any value whose extension is unknown. Add an entry to your
.gitattributes so git never applies line-ending conversion to them:
**/__snapshots__/** -text
Without it, a repository using the default core.autocrlf=true on Windows rewrites the line endings
of every binary snapshot on checkout. The symptom is snapshots that pass for whoever approved them
and fail for everyone else. PNG files fail to decode outright rather than mis-comparing, because the
PNG signature contains a CR LF pair specifically to catch this, but the reported error
("Unsupported image format") does not point at the cause.
Snapshot naming
You can choose how snapshot names are generated using SnapshotSettings.SnapshotNamingStrategy:
SnapshotNamingStrategies.TestNameSnapshotNamingStrategies.ClassName_TestName(default)SnapshotNamingStrategies.FullName
Calling Snapshot.Validate from a helper method
Wrapping Snapshot.Validate in a helper method is supported. The test method is resolved by walking the
stack until a method carrying a test attribute ([Fact], [Theory], [Test], [TestMethod]) is found, so
the helper frames are skipped and the snapshot is still named after the test, not after the helper.
The snapshot directory, however, comes from [CallerFilePath], which points at the file declaring the
helper. Forward the caller information so the snapshots are created next to the test file:
public static class ApiSnapshot
{
public static void ValidateOpenApiSpec(
string spec,
[CallerFilePath] string? filePath = null,
[CallerLineNumber] int lineNumber = -1)
{
var settings = SnapshotSettings.Default with { /* shared configuration */ };
Snapshot.Validate(spec, "yaml", settings, filePath, lineNumber);
}
}
public sealed class OpenApiTests
{
[Fact]
public void ValidateSpec()
{
ApiSnapshot.ValidateOpenApiSpec(GetSpec());
// => __snapshots__/OpenApiTests_ValidateSpec.verified.yaml
}
}
No custom SnapshotNamingStrategy or SnapshotPathStrategy is needed for this scenario.
This also works when the helper is async and awaits before asserting. The test method is then no longer on
the call stack, so the test name and class name are read from the test framework context instead (Xunit v3,
TUnit, and NUnit). Under a test framework that exposes no context (Xunit v2, MSTest), await inside the helper
after the call to Snapshot.Validate rather than before it, so the test method is still on the stack.
If the same test calls the helper several times, set Snapshot.TestContext to give each call a distinct name
(see Test context).
Snapshots stored as source files
Some snapshots are source files (for example the output of a source generator, see Meziantou.Framework.SnapshotTesting.Roslyn).
The package ships MSBuild targets that remove **/__snapshots__/**/*.cs and **/__snapshots__/**/*.vb from the Compile items and add them as None items, so they still show up in the IDE but are not compiled with the test project.
Set SnapshotTestingExcludeSnapshotFilesFromCompilation to false to opt out:
<PropertyGroup>
<SnapshotTestingExcludeSnapshotFilesFromCompilation>false</SnapshotTestingExcludeSnapshotFilesFromCompilation>
</PropertyGroup>
Approving snapshots
To approve generated *.actual.* files, you can use the dedicated tool package:
dotnet tool install --global Meziantou.Framework.SnapshotTesting.Tool
Meziantou.Framework.SnapshotTesting.Tool approve
Use --interactive to approve or reject snapshots one by one.
Snapshot types
SnapshotType controls extension and optional metadata (MimeType, DisplayName). This can also affect the serializer.
Test context
Snapshot naming uses test context when available:
Snapshot.TestContext(AsyncLocal<SnapshotTestContext?>) can be set explicitly.- Xunit v3, TUnit, and NUnit display names are auto-detected to improve generated file names.
- The test class and method names are auto-detected from the same frameworks. They are used when the call stack does not contain the test method, which happens when the assertion runs in a helper method that awaited before asserting.
Customization
Use SnapshotSettings to customize behavior:
Serializers(SnapshotSerializerCollection)Comparers(SnapshotComparerCollection)SnapshotUpdateStrategy(Disallow,Overwrite,OverwriteWithoutFailure,MergeTool,MergeToolSync)SnapshotPathStrategyfor full path generation
A custom SnapshotNamingStrategy or SnapshotPathStrategy receives a SnapshotPathContext. Its ClassName
and MethodName are read from the call stack, which is the most expensive part of an assertion, so they are
only resolved when a strategy reads them: a strategy that uses neither never pays for that walk. Use
MemberName when the name of the method that called the assertion - captured by the compiler, always
available - is enough.
You can also set the default strategy using the SNAPSHOTTESTING_STRATEGY environment variable.
The value is case-insensitive and must match one of the SnapshotUpdateStrategy static property names (for example: DISALLOW, MergeTool, overwritewithoutfailure).
var settings = SnapshotSettings.Default with
{
SnapshotUpdateStrategy = SnapshotUpdateStrategy.Disallow,
};
Snapshot.Validate(value, SnapshotType.Default, settings);
The default serializers handle human-readable objects, byte[], and Stream.
GIF frame extraction is opt-in via Serializers.AddGifSerializer(): when enabled and SnapshotType.Gif is used with a valid GIF byte[], each frame is serialized as a separate .png snapshot.
ICO image extraction is opt-in via Serializers.AddIcoSerializer(): when enabled and SnapshotType.Ico is used with a valid ICO byte[], each icon image is serialized as a separate .png snapshot.
BMP/PNG/JPEG/TIFF image comparison is opt-in via Comparers.AddImageComparer(). When enabled, SnapshotType.Bmp, SnapshotType.Png, SnapshotType.Jpeg (including .jpg aliases), and SnapshotType.Tiff (including .tif aliases) snapshots are compared by decoded pixel content (ARGB), so format metadata differences do not trigger snapshot mismatches.
To allow small visual differences, configure the image comparer with an SSIM threshold or a maximum 64-bit dHash/pHash Hamming distance. When multiple thresholds are configured, all comparisons must pass. dHash and pHash comparisons allow images with different dimensions, while exact and SSIM comparisons require identical dimensions.
var settings = SnapshotSettings.Default with { };
settings.Comparers.AddImageComparer(new ImageComparisonSettings
{
SimilarityThreshold = 0.95f,
DHashThreshold = 5,
PHashThreshold = 5,
});
Scrubbing
Scrubbing helps make snapshots deterministic by removing unstable values or lines.
var settings = SnapshotSettings.Default with { };
settings.ConfigureHumanReadableSerializer(options => options.ScrubGuid());
settings.ScrubLinesContaining("GeneratedAt:");
Snapshot.Validate(value, SnapshotType.Default, settings);
You can also scrub relative temporal values:
var now = DateTime.UtcNow;
var settings = SnapshotSettings.Default with { };
settings.ConfigureHumanReadableSerializer(options => options.UseRelativeDateTime(now));
| 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. net11.0 is compatible. |
-
net10.0
- Meziantou.Framework.DiffEngine (>= 2.0.7)
- Meziantou.Framework.FullPath (>= 3.0.7)
- Meziantou.Framework.HumanReadableSerializer (>= 4.0.4)
- Meziantou.Framework.LLMContext (>= 2.0.1)
- System.IO.Hashing (>= 10.0.12)
-
net11.0
- Meziantou.Framework.DiffEngine (>= 2.0.7)
- Meziantou.Framework.FullPath (>= 3.0.7)
- Meziantou.Framework.HumanReadableSerializer (>= 4.0.4)
- Meziantou.Framework.LLMContext (>= 2.0.1)
- System.IO.Hashing (>= 10.0.12)
NuGet packages (3)
Showing the top 3 NuGet packages that depend on Meziantou.Framework.SnapshotTesting:
| Package | Downloads |
|---|---|
|
Meziantou.Framework.SnapshotTesting.ImageSharp
Enables verification of SixLabors.ImageSharp images using file-based snapshots |
|
|
Meziantou.Framework.SnapshotTesting.SkiaSharp
Enables verification of SkiaSharp images using file-based snapshots |
|
|
Meziantou.Framework.SnapshotTesting.Roslyn
Enables verification of Roslyn objects (source generator results, syntax trees, and diagnostics) using file-based snapshots |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 3.1.11 | 0 | 9/15/2026 |
| 3.1.10 | 33 | 9/15/2026 |
| 3.1.9 | 40 | 9/15/2026 |
| 3.1.8 | 109 | 9/13/2026 |
| 3.1.7 | 95 | 9/11/2026 |
| 3.1.6 | 125 | 9/9/2026 |
| 3.1.5 | 132 | 9/6/2026 |
| 3.1.4 | 122 | 9/3/2026 |
| 3.1.3 | 123 | 9/3/2026 |
| 3.1.2 | 244 | 8/30/2026 |
| 3.1.1 | 123 | 8/29/2026 |
| 3.1.0 | 139 | 8/24/2026 |
| 3.0.3 | 118 | 8/23/2026 |
| 3.0.2 | 128 | 8/16/2026 |
| 3.0.1 | 275 | 7/8/2026 |
| 3.0.0 | 230 | 7/5/2026 |
| 2.1.12 | 158 | 7/5/2026 |
| 2.1.11 | 129 | 7/3/2026 |
| 2.1.10 | 149 | 7/2/2026 |
| 2.1.9 | 143 | 6/28/2026 |