Snapshooterは、 .NETコアと.NETフレームワークのスナップショットテストツールです
Snapshooterは、.NETのユニットテストの結果検証を簡素化するための柔軟なスナップショットテストツールです。 Jest Snapshotテストのアイデアに基づいています。
Snapshooterの詳細情報を入手するには、Snapshooterドキュメントにアクセスしてください
開始するには、Snapshooter XunitまたはNunit Nugetパッケージをインストールします。
dotnet add package Snapshooter.Xunitdotnet add package Snapshooter.NUnitdotnet add package Snapshooter.MSTest始めましょう
ユニットテストでスナップショットでテスト結果を主張するには、次の手順に従ってください。
Snapshot Assert Statement Snapshot.Match(yourResultObject);ユニットテストに。
例:
/// <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 ) ;
} Snapshot.Match(person)ステートメントは、結果オブジェクトの新しいスナップショットを作成し、 __snapshots__フォルダーに保存します。 __snapshots__フォルダーは、常に実行されたユニットテストファイルの隣にあります。
スナップショット名: <UnitTestClassName>.<TestMethodName>.snap
新しいスナップショットファイルを確認__snapshots__/<UnitTestClassName>.<TestMethodName>.snap 。
Snapshot.Match(person)ステートメントは、テスト結果のスナップショットを再度作成し、 __snapshots__フォルダーのレビューされたスナップショットと比較します。 __snapshots__フォルダーは、常に実行されたユニットテストファイルの隣にあります。
結果オブジェクトが変更され、既存のスナップショットが一致しなくなった場合、単体テストは失敗します。ユニットテストエラーメッセージは、スナップショット内の正確な不一致の位置を指します。
さらに、スナップショットフォルダー__snapshots__では、 __mismatch__という名前のサブフォルダーが作成されます。このフォルダーでは、 __snapshots__フォルダーの既存のスナップショットで不一致である実際のスナップショットを見つけることができます。したがって、2つのスナップショットをテキスト比較ツールと比較することができます。
不一致フォルダーのスナップショット__mismatch__が正しい場合は、親__snapshots__フォルダーに移動するだけです(既存のものをオーバーライドしてください)。
続きを読む
スナップショットのデフォルトマッチ構文は次のとおりです。
Snapshot . Match ( person ) ;ただし、Fluent Syntaxを使用することもできます。
person . MatchSnapshot ( ) ;または、fluentAssertionのshould()構文を使用することもできます。
person . Should ( ) . MatchSnapshot ( ) ;ヌニットについては、ASSERT.TAT SYNTAX(近日公開)をサポートします。
Assert . That ( person , Match . Snapshot ( ) ) ; スナップショットの一部のフィールドがスナップショットアサーション中に無視される場合、次の無視オプションを使用できます。
[ 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" ) ) ;
}無視するフィールドはJSonPathを介して配置されるため、非常に柔軟で、子オブジェクトや配列のフィールドを無視することもできます。
例を無視する:
// 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" ) ) ; 特定の名前ですべてのフィールドを無視したい場合は、2つのオプションがあります。
オプション1:Ingrore Match Option 'Ingoreallfields()'を使用して、名前を追加します。
// Ignores all fields with name 'Id'
Snapshot . Match < Person > ( person , matchOptions => matchOptions . IgnoreAllFields ( "Id" ) ) ;オプション2:次のJSonPath Syntax **を使用して、デフォルトの無視マッチオプション「IngroreFields(**。)」を使用します。
// Ignores all fields with name 'Id'
Snapshot . Match < Person > ( person , matchOptions => matchOptions . IgnoreFields ( "**.Id" ) ) ;スナップショットの一部のフィールドが大きすぎる場合、たとえば多くのデータがあるバイナリフィールドがある場合は、Hashfieldオプションを使用できます。 Hashfieldオプションは、フィールド値のハッシュを作成するため、ハッシュのみが比較されるたびにします。フィールド値に変更がある場合、スナップショットマッチは失敗します。
[ Fact ]
public void ImageSnapshot_HashImageBinary ( )
{
// arrange
var serviceClient = new ServiceClient ( ) ;
// act
TestImage image = serviceClient . CreateMonaLisaImage ( ) ;
// assert
Snapshot . Match ( image , matchOptions => matchOptions . HashField ( "Data" ) ) ;
}ハッシュを使用したスナップショットの例
{
"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= "
}フィールドからハッシュへのフィールドは、JSonPathまたはフィールド名を介して配置できます。
ハッシュフィールドの例:
// 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" ) ) ;スナップショットにフィールドがある場合があります。これは、別の値に対して個別に主張したい場合があります。
たとえば、「人」のIDフィールドは常にサービスで新しく生成されます。したがって、テストでは常に新しいID(GUID)を持つ人を受け取ります。これで、IDが空のガイドではないことを確認する場合、 Assertオプションを使用できます。
/// <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" ) ) ) ) ;
}アサートするフィールドはJsonPathを介して配置されるため、非常に柔軟で、子オブジェクトや配列のフィールドを無視することもできます。
アサート例:
// 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[*]" ) ) ) ) ;Snapshooterのアサート機能は、XunitまたはNunit Assertsに限定されず、流fluentアサーションまたは別のアサートツールを使用することもできます。
すべての無視、ISTYPE、またはアサートフィールドチェックを連結することができます。
[ 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" ) ) ) ) ;
} CIビルドでスナップシューターテストを実行するときは、スナップショットのないテストが最初のスナップショットを作成してグリーンになるため、スナップショットが正しくチェックインされるようにすることができます。
ci-buildにスナップショットがないテストに失敗するために、環境変数SNAPSHOOTER_STRICT_MODE onまたはtrueに設定することにより、Snapshooterの動作を厳密なモードに設定できます。
このプロジェクトは、私たちのコミュニティで予想される行動を明確にするために、貢献者契約によって定義された行動規範を採用しています。詳細については、スイスライフOSS行動規範を参照してください。