In this guide, Januarius Njoku demonstrates how to leverage the Verify library for snapshot testing in C#. The article offers practical steps for setup and execution, providing sample code and clear explanations for developers looking to ensure robust object state validation.

How to Perform Snapshot Testing With Verify in C#

Author: Januarius Njoku
Published: Jan 13, 2025


Snapshot testing offers a robust mechanism for verifying object states during software development. Januarius Njoku’s guide focuses on leveraging the Verify library in C# to automate and simplify this process, covering both the conceptual background and a practical walkthrough for implementation with xUnit.

Introduction

Testing is a vital part of modern software development. Developers usually rely on approaches such as unit testing—to check individual component behavior—and integration testing—to verify the collective operation of multiple components.

However, as the complexity of objects increases, it becomes challenging to ensure that new fields or properties haven’t been overlooked in tests. This is where snapshot testing becomes highly valuable, ensuring object states match expectations with less manual assertion code.

This article discusses:

  • What snapshot testing is
  • How it works
  • How to use the Verify library in .NET (C#)
  • How to integrate snapshot testing with xUnit

What Is Snapshot Testing?

Snapshot testing is a technique for verifying that the state of an object remains as expected over time. On the first test run, the current state of the object is captured and stored as a file or artifact (the “snapshot”). On successive runs, the test compares the current object state to the existing snapshot: if they match, the test passes; if not, it fails.

Snapshot testing is especially useful for scenarios such as:

  • Validating file contents
  • Comparing API responses
  • Ensuring consistent UI component output
  • Checking logs and other outputs

Snapshot Testing in .NET With the Verify Library

The Verify library by Simon Cropp streamlines snapshot testing in .NET. It integrates with popular test frameworks (like xUnit and NUnit), manages snapshot storage, and provides helpful failure messages when discrepancies arise.

  • Supports various object types: JSON, text, images, custom objects
  • Automatic snapshot management: Handles storing and updating expected state files
  • Easy integration: Works with xUnit, NUnit, and more

To learn more about related testing tools, refer to:

The Snapshot Testing Workflow With Verify

  1. First Test Run:
    • The test will fail, as no snapshot is stored yet.
    • Verify generates a snapshot artefact—for example, as a file—and prompts you to accept or reject it.
  2. Accepting the Snapshot:
    • If the captured state is correct, you accept the snapshot (usually by copying from the .received.txt file to a .verified.txt file or using tools/plugins supported by Verify).
  3. Subsequent Test Runs:
    • Provided there are no material changes, tests will pass.
    • Any change in the object state triggers a failed test, signaling that the snapshot should be reviewed and possibly updated.

Practical Walkthrough: Using Verify With xUnit

Let’s step through setting up snapshot testing for a simple object.

1. Define the Object and Factory

Suppose you have an API endpoint returning a Vehicle object:

public class Vehicle
{
    public Guid Id { get; set; }
    public string? Make { get; set; }
    public string? Model { get; set; }
    public int Year { get; set; }
    public string? Color { get; set; }
    public Address? Location { get; set; }
    public List<string>? Features { get; set; }
}

public record Address(string Street, string City, string State, string Country);

Here’s a method to generate a sample Vehicle object:

public static Vehicle GetVehicle() => new()
{
    Id = new("ebced679-45d3-4653-8791-3d969c4a986c"),
    Make = "Toyota",
    Model = "Camry",
    Year = 2022,
    Color = "Blue",
    Location = new Address("123 Main St", "Anytown", "CA", "USA"),
    Features = ["Sunroof", "4 Seats", "Navigation"]
};

2. Set Up the Test Project

Create an xUnit test project:

dotnet new xunit -n Tests

Install the Verify package:

dotnet add package Verify.Xunit

3. Implement the Snapshot Test

Define the test class and method:

public class VerifyVehicleTests
{
    [Fact]
    public Task WhenGetVehicleIsCalled_ThenReturnsTheCorrectObject()
    {
        var vehicle = VehicleFactory.GetVehicle();
        return Verify(vehicle);
    }
}

First Test Execution

  • On the initial test run, the test will fail (since there is no baseline snapshot).
  • Verify creates a .received.txt file (e.g., WhenGetVehicleIsCalled_ThenReturnsTheCorrectObject.received.txt) containing serialized object values, such as:
{
    Id: Guid_1,
    Make: Toyota,
    Model: Camry,
    Year: 2022,
    Color: Blue,
    Location: {
        Street: 123 Main St,
        City: Anytown,
        State: CA,
        Country: USA
    },
    Features: [Sunroof, 4 Seats, Navigation]
}
  • Accept this snapshot by copying it to an accepted file (e.g., .verified.txt). Tools/plugins exist to ease this process.

Test Evolution

  • On subsequent test executions, if the generated object has not changed, the test will pass.
  • Any change to the object will fail the test and prompt a review of the new snapshot.

Best Practices

  • Carefully review snapshots before accepting: Otherwise, breaking or unintended changes could be missed.
  • Automate snapshot acceptance only for explicit approvals: Never auto-approve in CI/CD pipelines.
  • Manage and version control your snapshots: Treat them as part of your test assets.

Conclusion

Snapshot testing, as demonstrated with the Verify library in C#, is a powerful addition to the developer’s toolkit for verifying complex object states with minimal manual test maintenance. It helps catch unintended changes, improves test effectiveness, and increases codebase stability. Coupled with xUnit or similar frameworks, it streamlines quality assurance processes for modern .NET applications.


Useful links:


This post appeared first on “Code Maze Blog”. Read the entire article here