快照器是.NET Core和.NET Framework的快照測試工具
快照器是一種靈活的快照測試工具,可簡化.NET中的單元測試中的結果驗證。它基於開玩笑的快照測試的想法。
要獲取有關快照者的更多詳細信息,請訪問SnapShooter Docs
要開始,請安裝SnapShooter Xunit或Nunit Nuget軟件包:
dotnet add package Snapshooter.Xunitdotnet add package Snapshooter.NUnitdotnet add package Snapshooter.MSTest開始
要通過單元測試中的快照來確定您的測試結果,請按照以下步驟:
插入快照聲明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__文件夾始終在您執行的單元測試文件旁邊。
如果您的結果對像已更改並且現有快照不再匹配,則單位測試將失敗。單位測試錯誤消息將指向快照中確切的不匹配位置。
此外,將創建帶有名稱__mismatch__子文件夾的__snapshots__文件夾中。在此文件夾中,您可以找到與__snapshots__文件夾中現有快照不匹配的實際快照。因此,可以將兩個快照與文本比較工具進行比較。
如果不匹配文件夾中的快照__mismatch__正確,只需將其移至parent __snapshots__文件夾(覆蓋現有的一個)即可。
閱讀更多
快照的默認匹配語法是:
Snapshot . Match ( person ) ;但是,我們也可以使用流利的語法:
person . MatchSnapshot ( ) ;或者我們可以使用FluentAssertion的sys()語法:
person . Should ( ) . MatchSnapshot ( ) ;對於Nunit,我們將支持聲音(即將推出):
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" ) ) ; 如果我們想以特定名稱忽略所有字段,那麼我們有兩個選項:
選項1:使用忽略匹配選項“ ignoreallfields()”並添加名稱。
// Ignores all fields with name 'Id'
Snapshot . Match < Person > ( person , matchOptions => matchOptions . IgnoreAllFields ( "Id" ) ) ;選項2:使用以下JSONPATH語法**使用默認的忽略匹配選項“ ignorefields(**。)”。
// Ignores all fields with name 'Id'
Snapshot . Match < Person > ( person , matchOptions => matchOptions . IgnoreFields ( "**.Id" ) ) ;如果我們的快照的某些字段太大,例如一個帶有大量數據的二進製字段,那麼我們可以使用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= "
}hash的字段可以通過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不是空的GUID,則可以使用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[*]" ) ) ) ) ;快照器斷言功能不限於Xunit或Nunit斷言,也可以使用流利的斷言或其他斷言工具。
可以將所有忽略,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構建沒有快照的測試失敗,您可以通過將環境變量SNAPSHOOTER_STRICT_MODE設置為on或true ,將快照器行為設置為嚴格模式。
該項目採用了貢獻者盟約定義的行為準則,以闡明我們社區的預期行為。有關更多信息,請參閱《瑞士生活OSS行為準則》。