This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Verify is a snapshot testing framework for .NET that simplifies assertion of complex data models and documents. It serializes test results to .verified.* files and compares them against actual results on subsequent runs.
Solution file: src\Verify.slnx (uses modern .slnx format)
Always pass src/Verify.slnx explicitly to dotnet build and dotnet test. There are multiple .slnx files in src/ and omitting the solution file causes ambiguity errors.
# Build
dotnet build src/Verify.slnx
# Test
dotnet test src/Verify.slnx
# Single test
dotnet test src/Verify.slnx --filter "FullyQualifiedName~YourTestName"
# Run tests that require direct execution (TUnit)
dotnet run --project src/Verify.TUnit.Tests/Verify.TUnit.Tests.csproj --configuration ReleaseVerify.Tests- Core verification engine testsVerify.Xunit.Tests/Verify.XunitV3.Tests- xUnit adapter testsVerify.NUnit.Tests- NUnit adapter testsVerify.MSTest.Tests- MSTest adapter testsVerify.Fixie.Tests- Fixie adapter testsVerify.Expecto.Tests/Verify.Expecto.FSharpTests- Expecto (F#) adapter testsVerify.TUnit.Tests- TUnit adapter testsDeterministicTests- Deterministic serialization testsStaticSettingsTests- Global configuration testsStrictJsonTests- JSON parsing tests
# Restore dotnet tools (required for Fixie tests)
dotnet tool restore --tool-manifest src/.config/dotnet-tools.json-
Test Framework Adapters (
Verify.NUnit,Verify.Xunit,Verify.MSTest, etc.)- Extract test metadata (type name, method name, parameters) from framework context
- Implement
BuildVerifier()to createInnerVerifierinstances - Each adapter is framework-specific but follows the same pattern
-
Core Verification Engine (
Verifyproject)InnerVerifier- Orchestrates verification workflow (split across 12 partial files by data type)VerifyEngine- Comparison logic, diff tool launching, callback executionSettingsTask- Fluent builder API for configuration
-
Serialization & Comparison
VerifyJsonWriter- Custom JSON writer extending Argon librarySerializationSettings- Registry of converters and scrubbersComparer/FileComparer/StreamComparer- Different comparison strategies
Adapter Pattern: Each test framework has a minimal adapter that extracts framework metadata differently:
- Xunit: Uses
UseVerifyAttribute(aBeforeAfterTestAttribute) injected via MSBuild - NUnit: Direct access to
TestContext.CurrentContext.Test - MSTest: Requires
[UsesVerify]attribute with source generator - Fixie: Uses
ExecutionState.Current
Partial Classes: InnerVerifier is split across 12 files:
InnerVerifier_Object.cs- Object serializationInnerVerifier_String.cs- Text comparisonInnerVerifier_Stream.cs- Binary filesInnerVerifier_Json.cs- JSON handlingInnerVerifier_Xml.cs- XML serializationInnerVerifier_Archive.cs- ZIP filesInnerVerifier_Directory.cs- Directory treesInnerVerifier_File.cs- Individual filesInnerVerifier_Task.cs- Async unwrappingInnerVerifier_Throws.cs- Exception capture- And others...
Builder Pattern: SettingsTask provides fluent API with ~50 configuration methods that are lazily evaluated at verification time.
Counter Pattern: Deduplicates repeated values in filenames:
- First occurrence:
Date, second:Date_1, third:Date_2, etc. - Separate counters for DateTime, DateTimeOffset, Guid, etc.
Format: {TypeName}.{MethodName}_{Parameters}_{UniqueFor}.{Status}.{Extension}
Example: MyTests.MyTest_param1_param2.verified.txt
Key components:
Namer.cs- Central naming logic with "unique for" variants (runtime, framework, etc.)FileNameBuilder.cs- Builds filename segments from test metadataParameterToName- Converts parameters to filename-safe stringsFileNameCleaner.cs- Removes invalid characters (: * ? / < > |)
- Verification flow:
src/Verify/Verifier/VerifyEngine.cs(main orchestrator) - Serialization:
src/Verify/Serialization/VerifyJsonWriter.csandSerializationSettings.cs - Comparison logic:
src/Verify/Compare/Comparer.cs - File naming:
src/Verify/Naming/FileNameBuilder.cs - Test adapter examples:
src/Verify.Xunit/Verifier.cs,src/Verify.NUnit/Verifier.cs
- Exclude from source control: All
*.received.*files (mismatches during test runs) - Include in source control: All
*.verified.*files (approved snapshots) - File characteristics: UTF-8 with BOM, LF line endings, no trailing newline
*.received.*
*.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
Verify files should use:
charset = utf-8-bomend_of_line = lfinsert_final_newline = false
src/
├── Verify/ # Core library
│ ├── Verifier/ # Verification engine
│ ├── Naming/ # File naming logic
│ ├── Serialization/ # JSON serialization & converters
│ ├── Compare/ # Comparison strategies
│ ├── Recording/ # Data recording during tests
│ ├── Combinations/ # Cartesian product testing
│ ├── DerivePaths/ # Build metadata integration
│ └── buildTransitive/ # MSBuild props/targets
├── Verify.NUnit/ # NUnit adapter
├── Verify.XunitV3/ # xUnit v3 adapter
├── Verify.MSTest/ # MSTest adapter
├── Verify.MSTest.SourceGenerator/ # Code generation for MSTest
├── Verify.Fixie/ # Fixie adapter
├── Verify.Expecto/ # Expecto (F#) adapter
├── Verify.TUnit/ # TUnit adapter
├── [Various test projects]
└── .config/dotnet-tools.json # Local tool manifest
- Create new project (e.g.,
Verify.NewFramework) - Implement
BuildVerifier()to extract test context from framework - Create partial
Verifierclasses for each verification method (Object, String, Stream, etc.) - Add MSBuild props file to inject any required attributes/configuration
- Optionally add module initializer to register test attachment callbacks
Reference existing adapters like Verify.Xunit/Verifier.cs or Verify.NUnit/Verifier.cs.
- Create converter class implementing appropriate interface in
src/Verify/Serialization/Converters/ - Register via
VerifierSettings.AddSerializer<T>(converter)in module initializer - Converters can access
SerializationSettingsfor configuration
- Primary logic in
src/Verify/Naming/FileNameBuilder.cs - Parameter conversion in
src/Verify/Naming/ParameterToName.cs - Sanitization in
src/Verify/FileNameCleaner.cs
When tests fail, .received.* files are created showing actual output. To accept a new snapshot, copy the .received.* file to the corresponding .verified.* filename.
Multi-target naming: When a test project targets multiple frameworks, .received. files include a runtime suffix (e.g., .DotNet11_0.received.txt) but .verified. files do not (e.g., .verified.txt). When accepting snapshots, strip the runtime suffix from the filename.
On CI (AppVeyor), failed test artifacts are uploaded for inspection.
The solution supports:
- .NET Framework: net462, net472, net48 (Windows only)
- .NET: net6.0, net7.0, net8.0, net9.0, net10.0, net11.0
SDK version: 11.0 preview (see src/global.json)
Platform-specific code uses conditional compilation:
#if NET6_0_OR_GREATER
// Modern .NET code
#endif
#if NET8_0_OR_GREATER
// .NET 8+ optimizations (e.g., SearchValues<T>)
#endif-
Module Initializers: Global configuration via
VerifierSettingsmust be done in a module initializer ([ModuleInitializer]) before any tests run. -
MSTest Requires Opt-in: MSTest tests need
[UsesVerify]attribute on class/assembly, or inherit fromVerifyBase. -
Fixie Requires Custom Convention: Fixie needs
ITestProjectandIExecutionimplementations that callVerifierSettings.AssignTargetAssembly()andExecutionState.Set(). -
Snapshot File Nesting: Verify includes MSBuild props that nest snapshot files under test files in IDE. Disable with
<DisableVerifyFileNesting>true</DisableVerifyFileNesting>. -
TUnit Tests: Use
dotnet runinstead ofdotnet testfor TUnit projects. -
Tool Restoration: Run
dotnet tool restorebefore running Fixie tests (requires fixie.console tool).
The MSTest adapter includes a source generator at src/Verify.MSTest.SourceGenerator/ that generates code for tests marked with [UsesVerify]. This handles test context plumbing automatically.
README and docs are generated from source files using MarkdownSnippets:
- Source:
readme.source.md - Generated:
readme.md(DO NOT EDIT) - Doc sources:
docs/mdsource/*.source.md→docs/*.md(generated) - Includes:
docs/mdsource/*.include.md(reusable fragments) - Run
mdsnippetsto regenerate (globally installed dotnet tool)
- Code snippets use
#region SnippetName/#endregionmarkers in source files - Referenced in docs as
snippet: SnippetName - Verified files can be included directly:
snippet: TestClass.Method.verified.txt src/ModuleInitDocs/contains purpose-built snippet classes for documentation (each file wraps a single#region)src/Verify.ExceptionParsing.Tests/ExceptionMessageFormatSamples.cscontains tests whose sole purpose is producing verified snapshots for the exception format docs
src/mdsnippets.json has ValidateContent: true. This forbids certain words (e.g., "you", "your") in .source.md files outside of fenced code blocks. Use third-person phrasing instead.
When a Verify test fails, VerifyExceptionMessageBuilder (src/Verify/Verifier/VerifyExceptionMessageBuilder.cs) produces a structured, machine-parsable exception message with sections: Directory:, New:, NotEqual:, Delete:, Equal:, and FileContent:. See docs/exception-message-format.md for the full format.
Verify.ExceptionParsing (src/Verify.ExceptionParsing/) is a separate library (published as a NuGet package) that parses these exception messages back into structured data.