snapshooter

2025-12-07 0 674

Snapshooter is a snapshot testing tool for .NET Core and .NET Framework

Snapshooter is a flexible snapshot testing tool to simplify the result validation in your unit tests in .Net. It is based on the idea of Jest Snapshot Testing.

To get more detailed information about Snapshooter, go to the Snapshooter Docs

Getting Started

To get started, install the Snapshooter Xunit or NUnit nuget package:

XUnit

dotnet add package Snapshooter.Xunit

NUnit

dotnet add package Snapshooter.NUnit

MSTest

dotnet add package Snapshooter.MSTest

Get Started

Assert with Snapshots

To assert your test results with snapshots in your unit tests, follow the following steps:

1. Add snapshot assert statement

Insert a snapshot assert statement Snapshot.Match(yourResultObject); into your unit test.

Example:

/// <summary>
/// Tests if the new created person is valid.
/// </summary>
[Fact]
public void CreatePersonSnapshotTest()
{
    // arrange
    var serviceClient = new ServiceClient();

    // act
    TestPerson person = serviceClient.CreatePerson(
        Guid.Parse(\"2292F21C-8501-4771-A070-C79C7C7EF451\"), \"David\", \"Mustermann\");

    // assert
    Snapshot.Match(person);
}

2. Run the unit test to create a new Snapshot

The Snapshot.Match(person) statement creates a new snapshot of your result object and stores it in the
__snapshots__ folder. The __snapshots__ folder is always next to your executed unit test file.

Snapshot name: <UnitTestClassName>.<TestMethodName>.snap

3. Review new snapshot

Review your new snapshot file __snapshots__/<UnitTestClassName>.<TestMethodName>.snap.

4. Run unit test to assert

Now the Snapshot.Match(person) statement will create again a snapshot of your test result and compare it against your reviewed snapshot in the __snapshots__ folder. The __snapshots__ folder is always next to your executed unit test file.

Mismatching Snapshot Handling

If your result object has changed and the existing snapshot is not matching anymore, then the unit test will fail. The unit test error message will point to the exact mismatching position within the snapshot.

In addition, in the snapshot folder __snapshots__ a subfolder with name __mismatch__ will be created. In this folder you can find
the actual snapshot which is mismatching with the existing snapshot in the __snapshots__ folder. Therefore it is possible to compare the two snapshots with a text compare tool.

If the snapshot in the mismatching folder __mismatch__ is correct, just move it to the parent __snapshots__ folder (override the existing one).

Read More

Different Match-Syntax Possibilities

The default match syntax for snapshots is:

    Snapshot.Match(person);

However, we also could use the fluent syntax:

    person.MatchSnapshot();

Or we can use FluentAssertion\’s should() syntax:

    person.Should().MatchSnapshot();

For NUnit we will support the Assert.That syntax (Coming soon):

    Assert.That(person, Match.Snapshot());

Features

Ignore Fields in Snapshots

If some fields in your snapshot shall be ignored during snapshot assertion, then the following ignore options can be used:

[Fact]
public void CreatePersonSnapshot_IgnoreId()
{
    // arrange
    var serviceClient = new ServiceClient();

    // act
    TestPerson person = serviceClient.CreatePerson(\"Hans\", \"Muster\");

    // assert
    Snapshot.Match<Person>(testPerson, matchOptions => matchOptions.IgnoreField(\"Size\"));
}

The fields to ignore will be located via JsonPath, therefore you are very flexible and you can also ignore fields from child objects or arrays.

Ignore Examples:

// Ignores the field \'StreetNumber\' of the child node \'Address\' of the person
Snapshot.Match<Person>(person, matchOptions => matchOptions.IgnoreField(\"Address.StreetNumber\"));

// Ignores the field \'Name\' of the child node \'Country\' of the child node \'Address\' of the person
Snapshot.Match<Person>(person, matchOptions => matchOptions.IgnoreField(\"Address.Country.Name\"));

// Ignores the field \'Id\' of the first person in the \'Relatives\' array of the person
Snapshot.Match<Person>(person, matchOptions => matchOptions.IgnoreField(\"Relatives[0].Id\"));

// Ignores the field \'Name\' of all \'Children\' nodes of the person
Snapshot.Match<Person>(person, matchOptions => matchOptions.IgnoreField(\"Children[*].Name\"));

// Ignores all fields with name \'Id\'
Snapshot.Match<Person>(person, matchOptions => matchOptions.IgnoreField(\"**.Id\"));

Ignore All Fields by name

If we want to ignore all fields by a specific name, then we have two options:

Option 1: Use the ignore match option \’IgnoreAllFields()\’ and add the name.

// Ignores all fields with name \'Id\'
Snapshot.Match<Person>(person, matchOptions => matchOptions.IgnoreAllFields(\"Id\"));

Option 2: Use the default ignore match option \’IgnoreFields(**.)\’ with the following JsonPath syntax **.

// Ignores all fields with name \'Id\'
Snapshot.Match<Person>(person, matchOptions => matchOptions.IgnoreFields(\"**.Id\"));

Hash Fields in Snapshots

If some fields of our snapshot are too big, for example a binary field with a lot of data, then we can use the HashField option.
The HashField option creates a Hash of the field value and therefore each time only the hash is compared.
If there is a change in the field value, then the snapshot match will fail.

[Fact]
public void ImageSnapshot_HashImageBinary()
{
    // arrange
    var serviceClient = new ServiceClient();

    // act
    TestImage image = serviceClient.CreateMonaLisaImage();

    // assert
    Snapshot.Match(image, matchOptions => matchOptions.HashField(\"Data\"));
}

Example Snapshot with Hash

{
  \"Id\": 3450987,
  \"OwnerId\": \"0680faef-6e89-4d52-bad8-291053c66696\",
  \"Name\": \"Mona Lisa\",
  \"CreationDate\": \"2020-11-10T21:23:09.036+01:00\",
  \"Price\": 951868484.345,
  \"Data\": \"m+sQR9KG9WpgYoQiRASPkt9FLJOLsjK86UuiXKVRzas=\"  
}

The field(s) to hash can be located via JsonPath or via field name.

Hash Field Examples:

// Hash the field \'Data\' of the child node \'Thumbnail\' of the person
Snapshot.Match<Person>(person, matchOptions => matchOptions.HashField(\"Thumbnail.Data\"));

// Hash the field \'Data\' of the first thumbnail in the \'Thumbnails\' array of the image
Snapshot.Match<Person>(person, matchOptions => matchOptions.HashField(\"Thumbnails[0].Data\"));

// Ignores the field \'Data\' of all \'Thumbnails\' nodes of the image
Snapshot.Match<Person>(person, matchOptions => matchOptions.HashField(\"Thumbnails[*].Data\"));

// Ignores all fields with name \'Data\'
Snapshot.Match<Person>(person, matchOptions => matchOptions.HashField(\"**.Data\"));

Assert Fields in Snapshots

Sometimes there are fields in a snapshot, which you want to assert separately against another value.

For Example, the Id field of a \’Person\’ is always newly generated in a service,
therefore you receive in the test always a Person with a new id (Guid).
Now if you want to check that the id is not an empty Guid, the Assert option can be used.

/// <summary>
/// Tests if the new created person is valid and the person id is not empty.
/// </summary>
[Fact]
public void CreatePersonSnapshot_AssertId()
{
    // arrange
    var serviceClient = new ServiceClient();

    // act
    TestPerson person = serviceClient.CreatePerson(\"Hans\", \"Muster\"); // --> id is created within the service

    // assert
    Snapshot.Match<Person>(testPerson, matchOption => matchOption.Assert(
                    fieldOption => Assert.NotEqual(Guid.Empty, fieldOption.Field<Guid>(\"Id\"))));
}

The fields to assert will be located via JsonPath, therefore you are very flexible and you can also ignore fields from child objects or arrays.

Assert Examples:

// Assert the field \'Street\' of the \'Address\' of the person
Snapshot.Match<Person>(person, matchOption => matchOption.Assert(
                    fieldOption => Assert.Equal(15, fieldOption.Field<int>(\"Address.StreetNumber\"))));

// Asserts the field \'Code\' of the field \'Country\' of the \'Address\' of the person
Snapshot.Match<Person>(person, matchOption => matchOption.Assert(
                    fieldOption => Assert.Equal(\"De\", fieldOption.Field<CountryCode>(\"Address.Country.Code\"))));

// Asserts the fist \'Id\' field of the \'Relatives\' array of the person
Snapshot.Match<Person>(person, > matchOption.Assert(
                    fieldOption => Assert.NotNull(fieldOption.Field<string>(\"Relatives[0].Id\"))));

// Asserts every \'Id\' field of all the \'Relatives\' of the person
Snapshot.Match<Person>(person, > matchOption.Assert(
                    fieldOption => Assert.NotNull(fieldOption.Fields<string>(\"Relatives[*].Id\"))));
 
// Asserts \'Relatives\' array is not empty
Snapshot.Match<Person>(person, > matchOption.Assert(
                    fieldOption => Assert.NotNull(fieldOption.Fields<TestPerson>(\"Relatives[*]\"))));

The Snapshooter assert functionality is not limited to Xunit or NUnit asserts, it also could be used Fluent Assertions or another assert tool.

Concatenate Ignore & Asserts checks

All the ignore, isType or assert field checks can be concatenated.

[Fact]
public void Match_ConcatenateFieldChecksTest_SuccessfulMatch()
{
    // arrange
    var serviceClient = new ServiceClient();

    // act
    TestPerson person = serviceClient.CreatePerson(\"Hans\", \"Muster\");

    // act & assert
    Snapshot.Match<TestPerson>(testPerson, matchOption => matchOption
            .Assert(option => Assert.NotEqual(Guid.Empty, option.Field<Guid>(\"Id\")))
            .IgnoreField<DateTime>(\"CreationDate\")
            .Assert(option => Assert.Equal(-58, option.Field<int>(\"Address.StreetNumber\")))
            .Assert(option => testChild.Should().BeEquivalentTo(option.Field<TestChild>(\"Children[3]\")))
            .IgnoreField<TestCountry>(\"Address.Country\")
            .Assert(option => Assert.Null(option.Field<TestCountry>(\"Relatives[0].Address.Plz\"))));
}

Using Snapshooter in CI-Builds

When running snapshooter tests in a CI-build you might want to ensure that a snapshots are correctly checked-in since otherwise tests without a snapshot will just create the initial snapshot and become green.

In order to fail tests that are without a snapshot on your CI-build you can set the snapshooter behavior to strict-mode by setting the environment variable SNAPSHOOTER_STRICT_MODE to on or true.

Community

This project has adopted the code of conduct defined by the Contributor Covenant
to clarify expected behavior in our community. For more information, see the Swiss Life OSS Code of Conduct.

下载源码

通过命令行克隆项目:

git clone https://github.com/SwissLife-OSS/snapshooter.git

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

申明:本文由第三方发布,内容仅代表作者观点,与本网站无关。对本文以及其中全部或者部分内容的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。本网发布或转载文章出于传递更多信息之目的,并不意味着赞同其观点或证实其描述,也不代表本网对其真实性负责。

左子网 开发教程 snapshooter https://www.zuozi.net/31454.html

egov smartcity suite
下一篇: egov smartcity suite
常见问题
  • 1、自动:拍下后,点击(下载)链接即可下载;2、手动:拍下后,联系卖家发放即可或者联系官方找开发者发货。
查看详情
  • 1、源码默认交易周期:手动发货商品为1-3天,并且用户付款金额将会进入平台担保直到交易完成或者3-7天即可发放,如遇纠纷无限期延长收款金额直至纠纷解决或者退款!;
查看详情
  • 1、描述:源码描述(含标题)与实际源码不一致的(例:货不对板); 2、演示:有演示站时,与实际源码小于95%一致的(但描述中有”不保证完全一样、有变化的可能性”类似显著声明的除外); 3、发货:不发货可无理由退款; 4、安装:免费提供安装服务的源码但卖家不履行的; 5、收费:价格虚标,额外收取其他费用的(但描述中有显著声明或双方交易前有商定的除外); 6、其他:如质量方面的硬性常规问题BUG等。 注:经核实符合上述任一,均支持退款,但卖家予以积极解决问题则除外。
查看详情
  • 1、左子会对双方交易的过程及交易商品的快照进行永久存档,以确保交易的真实、有效、安全! 2、左子无法对如“永久包更新”、“永久技术支持”等类似交易之后的商家承诺做担保,请买家自行鉴别; 3、在源码同时有网站演示与图片演示,且站演与图演不一致时,默认按图演作为纠纷评判依据(特别声明或有商定除外); 4、在没有”无任何正当退款依据”的前提下,商品写有”一旦售出,概不支持退款”等类似的声明,视为无效声明; 5、在未拍下前,双方在QQ上所商定的交易内容,亦可成为纠纷评判依据(商定与描述冲突时,商定为准); 6、因聊天记录可作为纠纷评判依据,故双方联系时,只与对方在左子上所留的QQ、手机号沟通,以防对方不承认自我承诺。 7、虽然交易产生纠纷的几率很小,但一定要保留如聊天记录、手机短信等这样的重要信息,以防产生纠纷时便于左子介入快速处理。
查看详情

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务