Verify is a snapshot testing tool that simplifies the assertion of complex data models and documents.
3,465
stars
6,847
commits
C#
primary language
Sep 11, 2026
updated
Verify is a snapshot tool that simplifies the assertion of complex data models and documents.
Verify is called on the test result during the assertion phase. It serializes that result and stores it in a file that matches the test name. On the next test execution, the result is again serialized and compared to the existing file. The test will fail if the two snapshots do not match: either the change is unexpected, or the reference snapshot needs to be updated to the new result.
[!IMPORTANT] Upcoming: Open Source Maintenance Fee. From August 2026, commercial organizations and government agencies using Verify's official binary releases will be asked to pay a small subscription fee (from $10/month). The source code remains open and free, and individuals, non-revenue organizations, CI, forks, and local development are unaffected. See the proposal and discussion for details and to provide feedback.
See Milestones for release notes.
Entity Framework Extensions is a major sponsor and is proud to contribute to the development this project.
Authentication and authorization via
Browser testing via
Get customized instructions for the specific combination of Operating System, IDE, Test Framework, and Build Server.
Accepting or declining a snapshot file is part of the core workflow of Verify. There are several ways to do this and the approach(s) selected is a personal preference.
.received. file to .verified.. This can be automated via scripts to bulk accept all .received. files by matching a pattern.All examples use Implicit Usings. Ensure <ImplicitUsings> is set to enable to ensure examples compile correctly.
<ImplicitUsings>enable</ImplicitUsings>
If ImplicitUsings are not enabled, substitute usages of Verify() with Verifier.Verify().
Given a class to be tested:
public static class ClassBeingTested
{
public static Person FindPerson() =>
new()
{
Id = new("ebced679-45d3-4653-8791-3d969c4a986c"),
Title = Title.Mr,
GivenNames = "John",
FamilyName = "Smith",
Spouse = "Jill",
Children =
[
"Sam",
"Mary"
],
Address = new()
{
Street = "4 Puddle Lane",
Country = "USA"
}
};
}
Support for NUnit
[TestFixture]
public class Sample
{
[Test]
public Task Test()
{
var person = ClassBeingTested.FindPerson();
return Verify(person);
}
}
Support for xUnitV3
public class Sample
{
[Fact]
public Task Test()
{
var person = ClassBeingTested.FindPerson();
return Verify(person);
}
}
Support for Fixie
public class Sample
{
public Task Test()
{
var person = ClassBeingTested.FindPerson();
return Verify(person);
}
}
Fixie is less opinionated than other test frameworks. As such it leaves up to the consumer how to configure test execution.
To enable Verify the ITestProject and IExecution interfaces need to be used.
Requirements:
ITestProject.Configure using VerifierSettings.AssignTargetAssemblyIExecution.Run using ExecutionState.SetAn example implementation of the above:
public class TestProject :
ITestProject,
IExecution
{
public void Configure(TestConfiguration configuration, TestEnvironment environment)
{
VerifierSettings.AssignTargetAssembly(environment.Assembly);
configuration.Conventions.Add<DefaultDiscovery, TestProject>();
}
public async Task Run(TestSuite testSuite)
{
foreach (var testClass in testSuite.TestClasses)
{
foreach (var test in testClass.Tests)
{
if (test.HasParameters)
{
foreach (var parameters in test
.GetAll<TestCase>()
.Select(_ => _.Parameters))
{
using (ExecutionState.Set(testClass, test, parameters))
{
await test.Run(parameters);
}
}
}
else
{
using (ExecutionState.Set(testClass, test, null))
{
await test.Run();
}
}
}
}
}
}
Support for Expecto
open Expecto
open VerifyTests
open VerifyExpecto
[<Tests>]
let tests =
testTask "findPerson" {
let person = ClassBeingTested.FindPerson()
do! Verifier.Verify("findPerson", person).ToTask()
}
Due to the nature of the Expecto implementation, the following APIs in Verify are not supported.
settings.UseParameters()settings.UseTextForParameters()Support for TUnit
public class Sample
{
[Test]
public Task Test()
{
var person = ClassBeingTested.FindPerson();
return Verify(person);
}
}
Support for MSTest
[TestClass]
public partial class Sample
{
[TestMethod]
public Task Test()
{
var person = ClassBeingTested.FindPerson();
return Verify(person);
}
}
The MSTest implementation leverages a Source Generator and requires test classes to opt in to being processed by the Source Generator.
Add the UsesVerifyAttribute.
For all test classes in an assembly:
[assembly: UsesVerify]
For a specific a test class:
[UsesVerify]
[TestClass]
public class TheTest...
Or inherit from VerifyBase:
[TestClass]
public class VerifyBaseUsage :
VerifyBase
{
[TestMethod]
public Task Simple() =>
Verify("The content");
}
No existing .verified. file.
graph TD
run(Run test and<br/>create Received file)
failTest(Fail Test<br/>and show Diff)
closeDiff(Close Diff)
run-->failTest
shouldAccept{Accept ?}
failTest-->shouldAccept
accept(Move Received<br/>to Verified)
shouldAccept-- Yes -->accept
discard(Discard<br/>Received)
shouldAccept-- No -->discard
accept-->closeDiff
discard-->closeDiff
When the test is initially run it will fail. If a Diff Tool is detected it will be used to display the diff.

To verify the result:
This will result in the Sample.Test.verified.txt being created:
{
GivenNames: John,
FamilyName: Smith,
Spouse: Jill,
Address: {
Street: 4 Puddle Lane,
Country: USA
},
Children: [
Sam,
Mary
],
Id: Guid_1
}
Existing .verified. file.
graph TD
run(Run test and<br/>create Received file)
closeDiff(Close Diff)
failTest(Fail Test<br/>and show Diff)
run-->isSame
shouldAccept{Accept ?}
failTest-->shouldAccept
accept(Move Received<br/>to Verified)
shouldAccept-- Yes -->accept
discard(Discard<br/>Received)
shouldAccept-- No -->discard
isSame{Compare<br/>Verified +<br/>Received}
passTest(Pass Test and<br/>discard Received)
isSame-- Same --> passTest
isSame-- Different --> failTest
accept-->closeDiff
discard-->closeDiff
If the implementation of ClassBeingTested changes:
public static class ClassBeingTested
{
public static Person FindPerson() =>
new()
{
Id = new("ebced679-45d3-4653-8791-3d969c4a986c"),
Title = Title.Mr,
// Middle name added
GivenNames = "John James",
FamilyName = "Smith",
Spouse = "Jill",
Children =
[
"Sam",
"Mary"
],
Address = new()
{
// Address changed
Street = "64 Barnett Street",
Country = "USA"
}
};
}
And the test is re-run it will fail.

The same approach can be used to verify the results and the change to Sample.Test.verified.txt is committed to source control along with the change to ClassBeingTested.
Verify() has overloads that accept Task<T>, ValueTask<T>, and IAsyncEnumerable<T>. These are awaited before verification.
There is also an overload that accepts Func<Task<T>>, which works well with async lambda expressions:
await Verify(
async () => new
{
Foo = await repo.GetFoo(id),
Bars = await repo.GetBars(id)
});
VerifyJson performs the following actions
JToken (if necessary).[Fact]
public Task VerifyJsonString()
{
var json = "{'key': {'msg': 'No action taken'}}";
return VerifyJson(json);
}
[Fact]
public Task VerifyJsonStream()
{
var json = "{'key': {'msg': 'No action taken'}}";
var stream = new MemoryStream(Encoding.UTF8.GetBytes(json));
return VerifyJson(stream);
}
[Fact]
public Task VerifyJsonJToken()
{
var json = "{'key': {'msg': 'No action taken'}}";
var target = JToken.Parse(json);
return Verify(target);
}
Results in a .txt file:
{
key: {
msg: No action taken
}
}
*.received.* files should be excluded from source control.eg. add the following to .gitignore
*.received.*
If using UseSplitModeForUniqueDirectory also include:
*.received/
All *.verified.* files should be committed to source control.
Text variants of verified and received have the following characteristics:
This manifests in several ways:
All text extensions of *.verified.* should have:
eol set to lfworking-tree-encoding set to UTF-8Note: working-tree-encoding=UTF-8 is correct even though Verify writes files with a BOM. Git does not strip or add the BOM — it passes through transparently. The UTF-8-BOM encoding would explicitly add a BOM on checkout and strip it on commit (so the internal blob differs from the working tree), but that is not the desired behavior since Verify writes the BOM itself and it should be preserved in the blob.
All Binary files should also be marked to avoid merging and line ending issues with binary files.
eg add the following to .gitattributes
*.verified.txt text eol=lf working-tree-encoding=UTF-8
*.verified.xml text eol=lf working-tree-encoding=UTF-8
*.verified.json text eol=lf working-tree-encoding=UTF-8
*.verified.bin binary
On Windows, if core.autocrlf is set to true, files may show as modified with no actual content changes. To fix this:
git config --global core.autocrlf input
core.autocrlf=true normalizes line endings to lf on commit, and converts them back to crlf on checkout. So the blobs stored in git are lf while the files on disk are crlf. Verify rejects a verified file containing a carriage return, so tests fail even though the committed content is correct.
Adding the .gitattributes entries above overrides core.autocrlf for those paths, but it does not update files that are already checked out. Git re-applies line ending filters only when a file's blob changes, and since core.autocrlf already normalized those blobs to lf, adding the attributes changes no content. A one-time refresh of the working tree is required after committing .gitattributes:
git rm --cached -r .
git reset --hard
This discards uncommitted changes, so commit or stash first.
Where crlf was committed to the blobs (core.autocrlf unset or false), the content itself needs normalizing instead. In that case git add --renormalize . produces a commit that converts the blobs, and checkout updates each working tree as it is pulled:
git add --renormalize .
git commit -m "Normalize line endings"
Build servers that reuse a cached working directory between runs need the same refresh as a developer machine. A build that clones fresh each run is unaffected.
If modifying text verified/received files in an editor, it is desirable for the editor to respect the above conventions. For EditorConfig enabled the following can be used:
# Verify settings
[*.{received,verified}.{json,txt,xml}]
charset = utf-8-bom
end_of_line = lf
indent_size = unset
indent_style = unset
insert_final_newline = false
tab_width = unset
trim_trailing_whitespace = false
[*.{received,verified}.{json,xml,html,htm,yaml,svg}]
indent_size = 2
indent_style = space
Note that the above are suggested for subset of text extension. Add others as required based on the text file types being verified.
Visual Studio Code does not apply the EditorConfig end_of_line setting natively. Without it, accepting a snapshot by editing in the built-in diff editor (for example reverting a block from received into verified) can save the verified file with crlf on Windows, taken from the default files.eol. Verify then rejects that file for containing a carriage return. Installing the EditorConfig for VS Code extension applies end_of_line = lf on save. Setting "files.eol": "\n" in Visual Studio Code settings has the same effect without the extension.
The settings above are the recommended approach, since they keep the content on disk consistent for everyone working on a repository. Where per developer setup cannot be relied on, Verify can instead be made tolerant of carriage returns and of a trailing newline in verified files. Both are opt in, and both have side effects worth understanding before enabling them. See Newline tolerance.
The above conventions can be checked by calling VerifyChecks.Run() in a test
[TestClass]
public partial class VerifyChecksTests
{
[TestMethod]
public Task Run() =>
VerifyChecks.Run();
}
public class VerifyChecksTests
{
[Tests]
public static Test verifyChecksTest = Runner.TestCase(
nameof(verifyChecksTest),
() => VerifyChecks.Run(typeof(VerifyChecksTests).Assembly));
}
public class VerifyChecksTests
{
public Task Run() =>
VerifyChecks.Run(GetType().Assembly);
}
public class VerifyChecksTests
{
[Fact]
public Task Run() =>
VerifyChecks.Run();
}
public class VerifyChecksTests
{
[Test]
public Task Run() =>
VerifyChecks.Run();
}
Most settings are available at both the global level and at the instance level.
When modifying settings at the global level it should be done using a Module Initializer:
public class StaticSettings
{
[Fact]
public Task Test() =>
Verify("String to verify");
}
public static class StaticSettingsUsage
{
[ModuleInitializer]
public static void Initialize() =>
VerifierSettings.AddScrubber(_ => _.Replace("String to verify", "new value"));
}
In .net framework, where the Module Initializer feature is not enabled by default, either use a Polyfill package (eg https://github.com/SimonCropp/Polyfill) or add the following to the test project:
namespace System.Runtime.CompilerServices;
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public sealed class ModuleInitializerAttribute : Attribute;
Alternatively, place static settings in the "run once before all test" API of the test framework being used.
In some scenarios it can be helpful to get access to the resulting *.verified.* files after a successful run. For example to do an explicit check for contains or not-contains in the resulting text. To allow this all Verify methods return a VerifyResult.
var result = await Verify(
new
{
Property = "Value To Check"
});
Assert.Contains("Value To Check", result.Text);
If using Verifier.Throws, the resulting Exception will also be accessible
var result = await Throws(MethodThatThrows);
Assert.NotNull(result.Exception);
Utility for finding paths based on the current file.
using IOPath = System.IO.Path;
namespace VerifyTests;
public static class CurrentFile
{
public static string Path([CallerFilePath] string file = "") =>
file;
public static string Directory([CallerFilePath] string file = "") =>
IOPath.GetDirectoryName(file)!;
public static string Relative(string relative, [CallerFilePath] string file = "")
{
var directory = IOPath.GetDirectoryName(file)!;
return IOPath.Combine(directory, relative);
}
}
Verify follows Semantic Versioning. The same applies for extensions to Verify. Small changes in the resulting snapshot files may be deployed in a minor version. As such nuget updates to Verify.* should be done as follows:
Verify.*packages in isolationSnapshot changes do not trigger a major version change to avoid causing Diamond dependency issues for downstream extensions.
Unit tests referencing Verify (including unit tests within this repository as well as any other code referencing Verify) can be run and debugged on a local virtualized environment supported by Visual Studio Remote Testing. Initial configurations have been added for WSL and net 7.0 linux docker via testenvironments.json (for third party code, the file needs to be copied or recreated next to the .sln solution file for solution to leverage the functionality).
Upon opening the Tests Explorer the advanced environments are available in the GUI:

This readme will not discuss definitive list of details for proper setup of the environments instead refer the following information sources and warn about particular gotchas:
*.received.* and *.verified.* filesVerify comes with default MSBuild includes for snapshot files (*.received.* and *.verified.*) that nests those files under the test that produced them. C#, VB and F# projects are supported.
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Condition="('$(DisableVerifyFileNesting)' != 'true')">
<None Include="**\*.received.*;**\*.verified.*" Condition="$(Language) == 'C#'">
<ParentFile>$([System.String]::Copy('%(FileName)').Split('.')[0].Split('(')[0])</ParentFile>
<DependentUpon>%(ParentFile).cs</DependentUpon>
</None>
<None Include="**\*.received.*;**\*.verified.*" Condition="$(Language) == 'VB'">
<ParentFile>$([System.String]::Copy('%(FileName)').Split('.')[0].Split('(')[0])</ParentFile>
<DependentUpon>%(ParentFile).vb</DependentUpon>
</None>
</ItemGroup>
</Project>
To opt out of this feature, include the following in the project file:
<PropertyGroup>
<DisableVerifyFileNesting>true</DisableVerifyFileNesting>
</PropertyGroup>
Browser testing via
Helmet designed by Leonidas Ikonomou from The Noun Project.
(top 30 of 82)
5,843 commits
553 commits
182 commits
152 commits
C#
99.9%
Verify is a snapshot testing tool that simplifies the assertion of complex data models and documents.
3,465
stars
6,847
commits
C#
primary language
Sep 11, 2026
updated
Verify is a snapshot tool that simplifies the assertion of complex data models and documents.
Verify is called on the test result during the assertion phase. It serializes that result and stores it in a file that matches the test name. On the next test execution, the result is again serialized and compared to the existing file. The test will fail if the two snapshots do not match: either the change is unexpected, or the reference snapshot needs to be updated to the new result.
[!IMPORTANT] Upcoming: Open Source Maintenance Fee. From August 2026, commercial organizations and government agencies using Verify's official binary releases will be asked to pay a small subscription fee (from $10/month). The source code remains open and free, and individuals, non-revenue organizations, CI, forks, and local development are unaffected. See the proposal and discussion for details and to provide feedback.
See Milestones for release notes.
Entity Framework Extensions is a major sponsor and is proud to contribute to the development this project.
Authentication and authorization via
Browser testing via
Get customized instructions for the specific combination of Operating System, IDE, Test Framework, and Build Server.
Accepting or declining a snapshot file is part of the core workflow of Verify. There are several ways to do this and the approach(s) selected is a personal preference.
.received. file to .verified.. This can be automated via scripts to bulk accept all .received. files by matching a pattern.All examples use Implicit Usings. Ensure <ImplicitUsings> is set to enable to ensure examples compile correctly.
<ImplicitUsings>enable</ImplicitUsings>
If ImplicitUsings are not enabled, substitute usages of Verify() with Verifier.Verify().
Given a class to be tested:
public static class ClassBeingTested
{
public static Person FindPerson() =>
new()
{
Id = new("ebced679-45d3-4653-8791-3d969c4a986c"),
Title = Title.Mr,
GivenNames = "John",
FamilyName = "Smith",
Spouse = "Jill",
Children =
[
"Sam",
"Mary"
],
Address = new()
{
Street = "4 Puddle Lane",
Country = "USA"
}
};
}
Support for NUnit
[TestFixture]
public class Sample
{
[Test]
public Task Test()
{
var person = ClassBeingTested.FindPerson();
return Verify(person);
}
}
Support for xUnitV3
public class Sample
{
[Fact]
public Task Test()
{
var person = ClassBeingTested.FindPerson();
return Verify(person);
}
}
Support for Fixie
public class Sample
{
public Task Test()
{
var person = ClassBeingTested.FindPerson();
return Verify(person);
}
}
Fixie is less opinionated than other test frameworks. As such it leaves up to the consumer how to configure test execution.
To enable Verify the ITestProject and IExecution interfaces need to be used.
Requirements:
ITestProject.Configure using VerifierSettings.AssignTargetAssemblyIExecution.Run using ExecutionState.SetAn example implementation of the above:
public class TestProject :
ITestProject,
IExecution
{
public void Configure(TestConfiguration configuration, TestEnvironment environment)
{
VerifierSettings.AssignTargetAssembly(environment.Assembly);
configuration.Conventions.Add<DefaultDiscovery, TestProject>();
}
public async Task Run(TestSuite testSuite)
{
foreach (var testClass in testSuite.TestClasses)
{
foreach (var test in testClass.Tests)
{
if (test.HasParameters)
{
foreach (var parameters in test
.GetAll<TestCase>()
.Select(_ => _.Parameters))
{
using (ExecutionState.Set(testClass, test, parameters))
{
await test.Run(parameters);
}
}
}
else
{
using (ExecutionState.Set(testClass, test, null))
{
await test.Run();
}
}
}
}
}
}
Support for Expecto
open Expecto
open VerifyTests
open VerifyExpecto
[<Tests>]
let tests =
testTask "findPerson" {
let person = ClassBeingTested.FindPerson()
do! Verifier.Verify("findPerson", person).ToTask()
}
Due to the nature of the Expecto implementation, the following APIs in Verify are not supported.
settings.UseParameters()settings.UseTextForParameters()Support for TUnit
public class Sample
{
[Test]
public Task Test()
{
var person = ClassBeingTested.FindPerson();
return Verify(person);
}
}
Support for MSTest
[TestClass]
public partial class Sample
{
[TestMethod]
public Task Test()
{
var person = ClassBeingTested.FindPerson();
return Verify(person);
}
}
The MSTest implementation leverages a Source Generator and requires test classes to opt in to being processed by the Source Generator.
Add the UsesVerifyAttribute.
For all test classes in an assembly:
[assembly: UsesVerify]
For a specific a test class:
[UsesVerify]
[TestClass]
public class TheTest...
Or inherit from VerifyBase:
[TestClass]
public class VerifyBaseUsage :
VerifyBase
{
[TestMethod]
public Task Simple() =>
Verify("The content");
}
No existing .verified. file.
graph TD
run(Run test and<br/>create Received file)
failTest(Fail Test<br/>and show Diff)
closeDiff(Close Diff)
run-->failTest
shouldAccept{Accept ?}
failTest-->shouldAccept
accept(Move Received<br/>to Verified)
shouldAccept-- Yes -->accept
discard(Discard<br/>Received)
shouldAccept-- No -->discard
accept-->closeDiff
discard-->closeDiff
When the test is initially run it will fail. If a Diff Tool is detected it will be used to display the diff.

To verify the result:
This will result in the Sample.Test.verified.txt being created:
{
GivenNames: John,
FamilyName: Smith,
Spouse: Jill,
Address: {
Street: 4 Puddle Lane,
Country: USA
},
Children: [
Sam,
Mary
],
Id: Guid_1
}
Existing .verified. file.
graph TD
run(Run test and<br/>create Received file)
closeDiff(Close Diff)
failTest(Fail Test<br/>and show Diff)
run-->isSame
shouldAccept{Accept ?}
failTest-->shouldAccept
accept(Move Received<br/>to Verified)
shouldAccept-- Yes -->accept
discard(Discard<br/>Received)
shouldAccept-- No -->discard
isSame{Compare<br/>Verified +<br/>Received}
passTest(Pass Test and<br/>discard Received)
isSame-- Same --> passTest
isSame-- Different --> failTest
accept-->closeDiff
discard-->closeDiff
If the implementation of ClassBeingTested changes:
public static class ClassBeingTested
{
public static Person FindPerson() =>
new()
{
Id = new("ebced679-45d3-4653-8791-3d969c4a986c"),
Title = Title.Mr,
// Middle name added
GivenNames = "John James",
FamilyName = "Smith",
Spouse = "Jill",
Children =
[
"Sam",
"Mary"
],
Address = new()
{
// Address changed
Street = "64 Barnett Street",
Country = "USA"
}
};
}
And the test is re-run it will fail.

The same approach can be used to verify the results and the change to Sample.Test.verified.txt is committed to source control along with the change to ClassBeingTested.
Verify() has overloads that accept Task<T>, ValueTask<T>, and IAsyncEnumerable<T>. These are awaited before verification.
There is also an overload that accepts Func<Task<T>>, which works well with async lambda expressions:
await Verify(
async () => new
{
Foo = await repo.GetFoo(id),
Bars = await repo.GetBars(id)
});
VerifyJson performs the following actions
JToken (if necessary).[Fact]
public Task VerifyJsonString()
{
var json = "{'key': {'msg': 'No action taken'}}";
return VerifyJson(json);
}
[Fact]
public Task VerifyJsonStream()
{
var json = "{'key': {'msg': 'No action taken'}}";
var stream = new MemoryStream(Encoding.UTF8.GetBytes(json));
return VerifyJson(stream);
}
[Fact]
public Task VerifyJsonJToken()
{
var json = "{'key': {'msg': 'No action taken'}}";
var target = JToken.Parse(json);
return Verify(target);
}
Results in a .txt file:
{
key: {
msg: No action taken
}
}
*.received.* files should be excluded from source control.eg. add the following to .gitignore
*.received.*
If using UseSplitModeForUniqueDirectory also include:
*.received/
All *.verified.* files should be committed to source control.
Text variants of verified and received have the following characteristics:
This manifests in several ways:
All text extensions of *.verified.* should have:
eol set to lfworking-tree-encoding set to UTF-8Note: working-tree-encoding=UTF-8 is correct even though Verify writes files with a BOM. Git does not strip or add the BOM — it passes through transparently. The UTF-8-BOM encoding would explicitly add a BOM on checkout and strip it on commit (so the internal blob differs from the working tree), but that is not the desired behavior since Verify writes the BOM itself and it should be preserved in the blob.
All Binary files should also be marked to avoid merging and line ending issues with binary files.
eg add the following to .gitattributes
*.verified.txt text eol=lf working-tree-encoding=UTF-8
*.verified.xml text eol=lf working-tree-encoding=UTF-8
*.verified.json text eol=lf working-tree-encoding=UTF-8
*.verified.bin binary
On Windows, if core.autocrlf is set to true, files may show as modified with no actual content changes. To fix this:
git config --global core.autocrlf input
core.autocrlf=true normalizes line endings to lf on commit, and converts them back to crlf on checkout. So the blobs stored in git are lf while the files on disk are crlf. Verify rejects a verified file containing a carriage return, so tests fail even though the committed content is correct.
Adding the .gitattributes entries above overrides core.autocrlf for those paths, but it does not update files that are already checked out. Git re-applies line ending filters only when a file's blob changes, and since core.autocrlf already normalized those blobs to lf, adding the attributes changes no content. A one-time refresh of the working tree is required after committing .gitattributes:
git rm --cached -r .
git reset --hard
This discards uncommitted changes, so commit or stash first.
Where crlf was committed to the blobs (core.autocrlf unset or false), the content itself needs normalizing instead. In that case git add --renormalize . produces a commit that converts the blobs, and checkout updates each working tree as it is pulled:
git add --renormalize .
git commit -m "Normalize line endings"
Build servers that reuse a cached working directory between runs need the same refresh as a developer machine. A build that clones fresh each run is unaffected.
If modifying text verified/received files in an editor, it is desirable for the editor to respect the above conventions. For EditorConfig enabled the following can be used:
# Verify settings
[*.{received,verified}.{json,txt,xml}]
charset = utf-8-bom
end_of_line = lf
indent_size = unset
indent_style = unset
insert_final_newline = false
tab_width = unset
trim_trailing_whitespace = false
[*.{received,verified}.{json,xml,html,htm,yaml,svg}]
indent_size = 2
indent_style = space
Note that the above are suggested for subset of text extension. Add others as required based on the text file types being verified.
Visual Studio Code does not apply the EditorConfig end_of_line setting natively. Without it, accepting a snapshot by editing in the built-in diff editor (for example reverting a block from received into verified) can save the verified file with crlf on Windows, taken from the default files.eol. Verify then rejects that file for containing a carriage return. Installing the EditorConfig for VS Code extension applies end_of_line = lf on save. Setting "files.eol": "\n" in Visual Studio Code settings has the same effect without the extension.
The settings above are the recommended approach, since they keep the content on disk consistent for everyone working on a repository. Where per developer setup cannot be relied on, Verify can instead be made tolerant of carriage returns and of a trailing newline in verified files. Both are opt in, and both have side effects worth understanding before enabling them. See Newline tolerance.
The above conventions can be checked by calling VerifyChecks.Run() in a test
[TestClass]
public partial class VerifyChecksTests
{
[TestMethod]
public Task Run() =>
VerifyChecks.Run();
}
public class VerifyChecksTests
{
[Tests]
public static Test verifyChecksTest = Runner.TestCase(
nameof(verifyChecksTest),
() => VerifyChecks.Run(typeof(VerifyChecksTests).Assembly));
}
public class VerifyChecksTests
{
public Task Run() =>
VerifyChecks.Run(GetType().Assembly);
}
public class VerifyChecksTests
{
[Fact]
public Task Run() =>
VerifyChecks.Run();
}
public class VerifyChecksTests
{
[Test]
public Task Run() =>
VerifyChecks.Run();
}
Most settings are available at both the global level and at the instance level.
When modifying settings at the global level it should be done using a Module Initializer:
public class StaticSettings
{
[Fact]
public Task Test() =>
Verify("String to verify");
}
public static class StaticSettingsUsage
{
[ModuleInitializer]
public static void Initialize() =>
VerifierSettings.AddScrubber(_ => _.Replace("String to verify", "new value"));
}
In .net framework, where the Module Initializer feature is not enabled by default, either use a Polyfill package (eg https://github.com/SimonCropp/Polyfill) or add the following to the test project:
namespace System.Runtime.CompilerServices;
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public sealed class ModuleInitializerAttribute : Attribute;
Alternatively, place static settings in the "run once before all test" API of the test framework being used.
In some scenarios it can be helpful to get access to the resulting *.verified.* files after a successful run. For example to do an explicit check for contains or not-contains in the resulting text. To allow this all Verify methods return a VerifyResult.
var result = await Verify(
new
{
Property = "Value To Check"
});
Assert.Contains("Value To Check", result.Text);
If using Verifier.Throws, the resulting Exception will also be accessible
var result = await Throws(MethodThatThrows);
Assert.NotNull(result.Exception);
Utility for finding paths based on the current file.
using IOPath = System.IO.Path;
namespace VerifyTests;
public static class CurrentFile
{
public static string Path([CallerFilePath] string file = "") =>
file;
public static string Directory([CallerFilePath] string file = "") =>
IOPath.GetDirectoryName(file)!;
public static string Relative(string relative, [CallerFilePath] string file = "")
{
var directory = IOPath.GetDirectoryName(file)!;
return IOPath.Combine(directory, relative);
}
}
Verify follows Semantic Versioning. The same applies for extensions to Verify. Small changes in the resulting snapshot files may be deployed in a minor version. As such nuget updates to Verify.* should be done as follows:
Verify.*packages in isolationSnapshot changes do not trigger a major version change to avoid causing Diamond dependency issues for downstream extensions.
Unit tests referencing Verify (including unit tests within this repository as well as any other code referencing Verify) can be run and debugged on a local virtualized environment supported by Visual Studio Remote Testing. Initial configurations have been added for WSL and net 7.0 linux docker via testenvironments.json (for third party code, the file needs to be copied or recreated next to the .sln solution file for solution to leverage the functionality).
Upon opening the Tests Explorer the advanced environments are available in the GUI:

This readme will not discuss definitive list of details for proper setup of the environments instead refer the following information sources and warn about particular gotchas:
*.received.* and *.verified.* filesVerify comes with default MSBuild includes for snapshot files (*.received.* and *.verified.*) that nests those files under the test that produced them. C#, VB and F# projects are supported.
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Condition="('$(DisableVerifyFileNesting)' != 'true')">
<None Include="**\*.received.*;**\*.verified.*" Condition="$(Language) == 'C#'">
<ParentFile>$([System.String]::Copy('%(FileName)').Split('.')[0].Split('(')[0])</ParentFile>
<DependentUpon>%(ParentFile).cs</DependentUpon>
</None>
<None Include="**\*.received.*;**\*.verified.*" Condition="$(Language) == 'VB'">
<ParentFile>$([System.String]::Copy('%(FileName)').Split('.')[0].Split('(')[0])</ParentFile>
<DependentUpon>%(ParentFile).vb</DependentUpon>
</None>
</ItemGroup>
</Project>
To opt out of this feature, include the following in the project file:
<PropertyGroup>
<DisableVerifyFileNesting>true</DisableVerifyFileNesting>
</PropertyGroup>
Browser testing via
Helmet designed by Leonidas Ikonomou from The Noun Project.
(top 30 of 82)
5,843 commits
553 commits
182 commits
152 commits
C#
99.9%