Snapshot Testing in C#

William Rees
3 min readFeb 12, 2024

--

Snapshot testing is a technique that involves capturing and comparing the output of a piece of code to a previously captured output.

In this post I’ll show how snapshot testing can be used to write a test which asserts that JSON is correctly desterilized to a class. The classes I’ll be working with are:

public class WeatherForecasts : List<WeatherForecast>
{
public static List<WeatherForecast> FromJson(string json)
{
var weatherForecast = JsonSerializer.Deserialize<List<WeatherForecast>>
(json, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
});

if (weatherForecast is null)
{
// TODO:: Throw exception or handle negative case however you want. I'll throw for demo purpose
throw new Exception($"Cannot deserialize input json to {nameof(WeatherForecast)} record.");
}

return weatherForecast;
}
}

public record WeatherForecast(long Date, int TemperatureC, string? Summary)
{
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}

Consider how you would write a test for the method FromJson in the WeatherForecasts class. A typical approahc would be to

  1. Setup the test data/json.
  2. Invoke the FromJson method.
  3. Asset that all the properties in the instance match the expected values.

This would be an example using the XUnit framework.

public class WeatherForecastsTests
{
[Fact]
public void Given_Valid_Weather_Json_When_Converting_To_A_Instance_Of_WeatherForecasts_Then_Deserialization_Should_Succeed_And_All_Properties_Should_Be_Set1()
{
// arrange
var json = @"[
{
""date"": 1707368400,
""temperatureC"": 32,
""summary"": ""Scorching""
}
]";

// act
var forecasts = WeatherForecasts.FromJson(json);

// assert
Assert.NotNull(forecasts);
Assert.Single(forecasts);
Assert.Equal(1707368400, forecasts.First().Date);
Assert.Equal(32, forecasts.First().TemperatureC);
Assert.Equal("Scorching", forecasts.First().Summary);
Assert.Equal(89, forecasts.First().TemperatureF);
}
}

While this test certainly works it does have some drawbacks:

  1. For complex objects the test can take a considerable amount of time to write.
  2. New properties can be added to the class without causing the test to fail. Ideally any change to the class which can impact deserialization should result in a failed test.

Thankfully the Verify.Xunit nuget package can help us address the these issues while also simplifying the test.

Using the verify nuget the test can be rewritten as:

[Fact]
public Task Given_Valid_Weather_Json_When_Converting_To_A_Instance_Of_WeatherForecasts_Then_Deserialization_Should_Succeed_And_All_Properties_Should_Be_Set()
{
// arrange
var json = @"[
{
""date"": 1707368400,
""temperatureC"": 32,
""summary"": ""Scorching""
}
]";

// act
var forecasts = WeatherForecasts.FromJson(json);

// assert
return Verify(forecasts);
}

The only change is that the method now returns Task instead of void and the asserts section is replaced with return Verify(forecasts);

When the test is executed for the first time it will fail, two text files will be created and your IDEs compare window will open which compares the two files

The text files created will follow the naming convention CLASS_NAME.METHOD_NAME.received.txt and CLASS_NAME.METHOD_NAME.verified.txt *.received.txt contains the output of the last test run and *.verified.txt contains the expected snapshot.

In order for the test to pass the content of both received and verified must match so after confirming that received has the correct input you can copy the content to verified.txt and rerun the test

Once the test passes the file *.received.txt should have automatically deleted leaving only *.verified.txt

As a best practice files that end with *.received.txt should not be committed to source control and *.verified.txt must be committed otherwise the test will fail for other developers or when executed during a build pipeline.

Conclusion

Snapshot testing in a great tool which helps you focus on output structure and reduces the complexity of assertions, snapshot testing enhances the overall testing strategy, making it more efficient, readable, and accurate.

Consider incorporating snapshot testing into your testing arsenal to experience the benefits it brings to your development workflow.

Sources

--

--

William Rees

Software engineer with 10+ years of experience. I primarily work on the Microsoft and .NET ecosystem and have extensive experience with Microsoft Azure